diff --git a/src/include.am b/src/include.am index fe97320637..943522b4e8 100644 --- a/src/include.am +++ b/src/include.am @@ -17,10 +17,16 @@ MAINTAINERCLEANFILES+= $(FIPS_FILES) EXTRA_DIST += src/bio.c EXTRA_DIST += src/conf.c EXTRA_DIST += src/pk.c +EXTRA_DIST += src/pk_rsa.c +EXTRA_DIST += src/pk_ec.c +EXTRA_DIST += src/ssl_api_cert.c +EXTRA_DIST += src/ssl_api_crl_ocsp.c +EXTRA_DIST += src/ssl_api_pk.c EXTRA_DIST += src/ssl_asn1.c EXTRA_DIST += src/ssl_bn.c EXTRA_DIST += src/ssl_certman.c EXTRA_DIST += src/ssl_crypto.c +EXTRA_DIST += src/ssl_ech.c EXTRA_DIST += src/ssl_load.c EXTRA_DIST += src/ssl_misc.c EXTRA_DIST += src/ssl_p7p12.c diff --git a/src/pk.c b/src/pk.c index 8f07a679c1..34f26dfcdb 100644 --- a/src/pk.c +++ b/src/pk.c @@ -26,21 +26,6 @@ #include #endif -#ifdef HAVE_ECC - #include - #ifdef HAVE_SELFTEST - /* point compression types. */ - #define ECC_POINT_COMP_EVEN 0x02 - #define ECC_POINT_COMP_ODD 0x03 - #define ECC_POINT_UNCOMP 0x04 - #endif -#endif -#ifndef WOLFSSL_HAVE_ECC_KEY_GET_PRIV - /* FIPS build has replaced ecc.h. */ - #define wc_ecc_key_get_priv(key) (&((key)->k)) - #define WOLFSSL_HAVE_ECC_KEY_GET_PRIV -#endif - #if !defined(WOLFSSL_PK_INCLUDED) #ifndef WOLFSSL_IGNORE_FILE_WARN #warning pk.c does not need to be compiled separately from ssl.c @@ -941,13521 +926,4120 @@ static int wolfssl_der_length(const unsigned char* seq, int len) #endif + +#define WOLFSSL_PK_RSA_INCLUDED +#include "src/pk_rsa.c" + + /******************************************************************************* - * START OF RSA API + * START OF DSA API ******************************************************************************/ -#ifndef NO_RSA - -/* - * RSA METHOD - * Could be used to hold function pointers to implementations of RSA operations. - */ +#ifndef NO_DSA -#if defined(OPENSSL_EXTRA) -/* Return a blank RSA method and set the name and flags. - * - * Only one implementation of RSA operations. - * name is duplicated. - * - * @param [in] name Name to use in method. - * @param [in] flags Flags to set into method. - * @return Newly allocated RSA method on success. - * @return NULL on failure. +#if defined(OPENSSL_EXTRA) && defined(XFPRINTF) && !defined(NO_FILESYSTEM) && \ + !defined(NO_STDIO_FILESYSTEM) +/* return code compliant with OpenSSL : + * 1 if success, 0 if error */ -WOLFSSL_RSA_METHOD *wolfSSL_RSA_meth_new(const char *name, int flags) +int wolfSSL_DSA_print_fp(XFILE fp, WOLFSSL_DSA* dsa, int indent) { - WOLFSSL_RSA_METHOD* meth = NULL; - int name_len = 0; - int err; - - /* Validate name is not NULL. */ - if (name == NULL) - return NULL; - /* Allocate an RSA METHOD to return. */ - meth = (WOLFSSL_RSA_METHOD*)XMALLOC(sizeof(WOLFSSL_RSA_METHOD), NULL, - DYNAMIC_TYPE_OPENSSL); - if (meth == NULL) - return NULL; - - XMEMSET(meth, 0, sizeof(*meth)); - meth->flags = flags; - meth->dynamic = 1; + int ret = 1; - name_len = (int)XSTRLEN(name); - meth->name = (char*)XMALLOC((size_t)(name_len + 1), NULL, - DYNAMIC_TYPE_OPENSSL); - err = (meth->name == NULL); + WOLFSSL_ENTER("wolfSSL_DSA_print_fp"); - if (!err) { - XMEMCPY(meth->name, name, (size_t)(name_len + 1)); + if (fp == XBADFILE || dsa == NULL) { + ret = 0; } - if (err) { - /* meth->name won't be allocated on error. */ - XFREE(meth, NULL, DYNAMIC_TYPE_OPENSSL); - meth = NULL; + if (ret == 1 && dsa->p != NULL) { + int pBits = wolfSSL_BN_num_bits(dsa->p); + if (pBits == 0) { + ret = 0; + } + else { + if (XFPRINTF(fp, "%*s", indent, "") < 0) + ret = 0; + else if (XFPRINTF(fp, "Private-Key: (%d bit)\n", pBits) < 0) + ret = 0; + } + } + if (ret == 1 && dsa->priv_key != NULL) { + ret = pk_bn_field_print_fp(fp, indent, "priv", dsa->priv_key); + } + if (ret == 1 && dsa->pub_key != NULL) { + ret = pk_bn_field_print_fp(fp, indent, "pub", dsa->pub_key); + } + if (ret == 1 && dsa->p != NULL) { + ret = pk_bn_field_print_fp(fp, indent, "P", dsa->p); + } + if (ret == 1 && dsa->q != NULL) { + ret = pk_bn_field_print_fp(fp, indent, "Q", dsa->q); + } + if (ret == 1 && dsa->g != NULL) { + ret = pk_bn_field_print_fp(fp, indent, "G", dsa->g); } - return meth; -} -/* Default RSA method is one with wolfSSL name and no flags. - * - * @return Newly allocated wolfSSL RSA method on success. - * @return NULL on failure. - */ -const WOLFSSL_RSA_METHOD* wolfSSL_RSA_get_default_method(void) -{ - static const WOLFSSL_RSA_METHOD wolfssl_rsa_meth = { - 0, /* No flags. */ - (char*)"wolfSSL RSA", - 0 /* Static definition. */ - }; - return &wolfssl_rsa_meth; -} + WOLFSSL_LEAVE("wolfSSL_DSA_print_fp", ret); -/* Dispose of RSA method and allocated data. - * - * @param [in] meth RSA method to free. - */ -void wolfSSL_RSA_meth_free(WOLFSSL_RSA_METHOD *meth) -{ - /* Free method if available and dynamically allocated. */ - if ((meth != NULL) && meth->dynamic) { - /* Name was duplicated and must be freed. */ - XFREE(meth->name, NULL, DYNAMIC_TYPE_OPENSSL); - /* Dispose of RSA method. */ - XFREE(meth, NULL, DYNAMIC_TYPE_OPENSSL); - } + return ret; } +#endif /* OPENSSL_EXTRA && XSNPRINTF && !NO_FILESYSTEM && NO_STDIO_FILESYSTEM */ -#ifndef NO_WOLFSSL_STUB -/* Stub function for any RSA method setting function. - * - * Nothing is stored - not even flags or name. - * - * @param [in] meth RSA method. - * @param [in] p A pointer. - * @return 1 to indicate success. - */ -int wolfSSL_RSA_meth_set(WOLFSSL_RSA_METHOD *meth, void* p) +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +static void InitwolfSSL_DSA(WOLFSSL_DSA* dsa) { - WOLFSSL_STUB("RSA_METHOD is not implemented."); - - (void)meth; - (void)p; - - return 1; + if (dsa) { + dsa->p = NULL; + dsa->q = NULL; + dsa->g = NULL; + dsa->pub_key = NULL; + dsa->priv_key = NULL; + dsa->internal = NULL; + dsa->inSet = 0; + dsa->exSet = 0; + } } -#endif /* !NO_WOLFSSL_STUB */ -#endif /* OPENSSL_EXTRA */ -/* - * RSA constructor/deconstructor APIs - */ -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -/* Dispose of RSA key and allocated data. - * - * Cannot use rsa after this call. - * - * @param [in] rsa RSA key to free. - */ -void wolfSSL_RSA_free(WOLFSSL_RSA* rsa) +WOLFSSL_DSA* wolfSSL_DSA_new(void) { - int doFree = 1; + WOLFSSL_DSA* external; + DsaKey* key; - WOLFSSL_ENTER("wolfSSL_RSA_free"); + WOLFSSL_MSG("wolfSSL_DSA_new"); - /* Validate parameter. */ - if (rsa == NULL) { - doFree = 0; + key = (DsaKey*) XMALLOC(sizeof(DsaKey), NULL, DYNAMIC_TYPE_DSA); + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_DSA_new malloc DsaKey failure"); + return NULL; } - if (doFree) { - int err; - /* Decrement reference count. */ - wolfSSL_RefDec(&rsa->ref, &doFree, &err); - #ifndef WOLFSSL_REFCNT_ERROR_RETURN - (void)err; - #endif + external = (WOLFSSL_DSA*) XMALLOC(sizeof(WOLFSSL_DSA), NULL, + DYNAMIC_TYPE_DSA); + if (external == NULL) { + WOLFSSL_MSG("wolfSSL_DSA_new malloc WOLFSSL_DSA failure"); + XFREE(key, NULL, DYNAMIC_TYPE_DSA); + return NULL; } - if (doFree) { - void* heap = rsa->heap; - /* Dispose of allocated reference counting data. */ - wolfSSL_RefFree(&rsa->ref); + InitwolfSSL_DSA(external); + if (wc_InitDsaKey(key) != 0) { + WOLFSSL_MSG("wolfSSL_DSA_new InitDsaKey failure"); + XFREE(key, NULL, DYNAMIC_TYPE_DSA); + wolfSSL_DSA_free(external); + return NULL; + } + external->internal = key; - #ifdef HAVE_EX_DATA_CLEANUP_HOOKS - wolfSSL_CRYPTO_cleanup_ex_data(&rsa->ex_data); - #endif + return external; +} - if (rsa->internal != NULL) { - #if !defined(HAVE_FIPS) && defined(WC_RSA_BLINDING) - /* Check if RNG is owned before freeing it. */ - if (rsa->ownRng) { - WC_RNG* rng = ((RsaKey*)(rsa->internal))->rng; - if ((rng != NULL) && (rng != wolfssl_get_global_rng())) { - wc_FreeRng(rng); - XFREE(rng, heap, DYNAMIC_TYPE_RNG); - } - /* RNG isn't freed by wolfCrypt RSA free. */ - } - #endif - /* Dispose of allocated data in wolfCrypt RSA key. */ - wc_FreeRsaKey((RsaKey*)rsa->internal); - /* Dispose of memory for wolfCrypt RSA key. */ - XFREE(rsa->internal, heap, DYNAMIC_TYPE_RSA); - } - /* Dispose of external representation of RSA values. */ - wolfSSL_BN_clear_free(rsa->iqmp); - wolfSSL_BN_clear_free(rsa->dmq1); - wolfSSL_BN_clear_free(rsa->dmp1); - wolfSSL_BN_clear_free(rsa->q); - wolfSSL_BN_clear_free(rsa->p); - wolfSSL_BN_clear_free(rsa->d); - wolfSSL_BN_free(rsa->e); - wolfSSL_BN_free(rsa->n); - - #if defined(OPENSSL_EXTRA) - if (rsa->meth) { - wolfSSL_RSA_meth_free((WOLFSSL_RSA_METHOD*)rsa->meth); +void wolfSSL_DSA_free(WOLFSSL_DSA* dsa) +{ + WOLFSSL_MSG("wolfSSL_DSA_free"); + + if (dsa) { + if (dsa->internal) { + FreeDsaKey((DsaKey*)dsa->internal); + XFREE(dsa->internal, NULL, DYNAMIC_TYPE_DSA); + dsa->internal = NULL; } - #endif + wolfSSL_BN_free(dsa->priv_key); + wolfSSL_BN_free(dsa->pub_key); + wolfSSL_BN_free(dsa->g); + wolfSSL_BN_free(dsa->q); + wolfSSL_BN_free(dsa->p); + InitwolfSSL_DSA(dsa); /* set back to NULLs for safety */ - /* Set back to NULLs for safety. */ - ForceZero(rsa, sizeof(*rsa)); + XFREE(dsa, NULL, DYNAMIC_TYPE_DSA); - XFREE(rsa, heap, DYNAMIC_TYPE_RSA); - (void)heap; + /* dsa = NULL, don't try to access or double free it */ } } -/* Allocate and initialize a new RSA key. - * - * Not OpenSSL API. - * - * @param [in] heap Heap hint for dynamic memory allocation. - * @param [in] devId Device identifier value. - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA* wolfSSL_RSA_new_ex(void* heap, int devId) +/* wolfSSL -> OpenSSL */ +int SetDsaExternal(WOLFSSL_DSA* dsa) { - WOLFSSL_RSA* rsa = NULL; - RsaKey* key = NULL; - int err = 0; - int rsaKeyInited = 0; - - WOLFSSL_ENTER("wolfSSL_RSA_new"); + DsaKey* key; + WOLFSSL_MSG("Entering SetDsaExternal"); - /* Allocate memory for new wolfCrypt RSA key. */ - key = (RsaKey*)XMALLOC(sizeof(RsaKey), heap, DYNAMIC_TYPE_RSA); - if (key == NULL) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_new malloc RsaKey failure"); - err = 1; - } - if (!err) { - /* Allocate memory for new RSA key. */ - rsa = (WOLFSSL_RSA*)XMALLOC(sizeof(WOLFSSL_RSA), heap, - DYNAMIC_TYPE_RSA); - if (rsa == NULL) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_new malloc WOLFSSL_RSA failure"); - err = 1; - } + if (dsa == NULL || dsa->internal == NULL) { + WOLFSSL_MSG("dsa key NULL error"); + return WOLFSSL_FATAL_ERROR; } - if (!err) { - /* Clear all fields of RSA key. */ - XMEMSET(rsa, 0, sizeof(WOLFSSL_RSA)); - /* Cache heap to use for all allocations. */ - rsa->heap = heap; - #ifdef OPENSSL_EXTRA - /* Always have a method set. */ - rsa->meth = wolfSSL_RSA_get_default_method(); - #endif - /* Initialize reference counting. */ - wolfSSL_RefInit(&rsa->ref, &err); -#ifdef WOLFSSL_REFCNT_ERROR_RETURN + key = (DsaKey*)dsa->internal; + + if (wolfssl_bn_set_value(&dsa->p, &key->p) != 1) { + WOLFSSL_MSG("dsa p key error"); + return WOLFSSL_FATAL_ERROR; } - if (!err) { -#endif - /* Initialize wolfCrypt RSA key. */ - if (wc_InitRsaKey_ex(key, heap, devId) != 0) { - WOLFSSL_ERROR_MSG("InitRsaKey WOLFSSL_RSA failure"); - err = 1; - } - else { - rsaKeyInited = 1; - } + + if (wolfssl_bn_set_value(&dsa->q, &key->q) != 1) { + WOLFSSL_MSG("dsa q key error"); + return WOLFSSL_FATAL_ERROR; } - #if !defined(HAVE_FIPS) && defined(WC_RSA_BLINDING) - if (!err) { - WC_RNG* rng; - - /* Create a local RNG. */ - rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), heap, DYNAMIC_TYPE_RNG); - if ((rng != NULL) && (wc_InitRng_ex(rng, heap, devId) != 0)) { - WOLFSSL_MSG("InitRng failure, attempting to use global RNG"); - XFREE(rng, heap, DYNAMIC_TYPE_RNG); - rng = NULL; - } - rsa->ownRng = 1; - if (rng == NULL) { - /* Get the wolfSSL global RNG - not thread safe. */ - rng = wolfssl_get_global_rng(); - rsa->ownRng = 0; - } - if (rng == NULL) { - /* Couldn't create global either. */ - WOLFSSL_ERROR_MSG("wolfSSL_RSA_new no WC_RNG for blinding"); - err = 1; - } - else { - /* Set the local or global RNG into the wolfCrypt RSA key. */ - (void)wc_RsaSetRNG(key, rng); - /* Won't fail as key and rng are not NULL. */ - } + if (wolfssl_bn_set_value(&dsa->g, &key->g) != 1) { + WOLFSSL_MSG("dsa g key error"); + return WOLFSSL_FATAL_ERROR; } - #endif /* !HAVE_FIPS && WC_RSA_BLINDING */ - if (!err) { - /* Set wolfCrypt RSA key into RSA key. */ - rsa->internal = key; - /* Data from external RSA key has not been set into internal one. */ - rsa->inSet = 0; + + if (wolfssl_bn_set_value(&dsa->pub_key, &key->y) != 1) { + WOLFSSL_MSG("dsa y key error"); + return WOLFSSL_FATAL_ERROR; } - if (err) { - /* Dispose of any allocated data on error. */ - /* No failure after RNG allocation - no need to free RNG. */ - if (rsaKeyInited) { - wc_FreeRsaKey(key); - } - XFREE(key, heap, DYNAMIC_TYPE_RSA); - XFREE(rsa, heap, DYNAMIC_TYPE_RSA); - /* Return NULL. */ - rsa = NULL; + if (wolfssl_bn_set_value(&dsa->priv_key, &key->x) != 1) { + WOLFSSL_MSG("dsa x key error"); + return WOLFSSL_FATAL_ERROR; } - return rsa; -} -/* Allocate and initialize a new RSA key. - * - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA* wolfSSL_RSA_new(void) -{ - /* Call wolfSSL API to do work. */ - return wolfSSL_RSA_new_ex(NULL, INVALID_DEVID); -} + dsa->exSet = 1; -/* Increments ref count of RSA key. - * - * @param [in, out] rsa RSA key. - * @return 1 on success - * @return 0 on error - */ -int wolfSSL_RSA_up_ref(WOLFSSL_RSA* rsa) -{ - int err = 0; - if (rsa != NULL) { - wolfSSL_RefInc(&rsa->ref, &err); - } - return !err; + return 1; } - #endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ #ifdef OPENSSL_EXTRA +/* Openssl -> WolfSSL */ +int SetDsaInternal(WOLFSSL_DSA* dsa) +{ + DsaKey* key; + WOLFSSL_MSG("Entering SetDsaInternal"); -#if defined(WOLFSSL_KEY_GEN) + if (dsa == NULL || dsa->internal == NULL) { + WOLFSSL_MSG("dsa key NULL error"); + return WOLFSSL_FATAL_ERROR; + } -/* Allocate a new RSA key and make it a copy. - * - * Encodes to and from DER to copy. - * - * @param [in] rsa RSA key to duplicate. - * @return RSA key on success. - * @return NULL on error. - */ -WOLFSSL_RSA* wolfSSL_RSAPublicKey_dup(WOLFSSL_RSA *rsa) -{ - WOLFSSL_RSA* ret = NULL; - int derSz = 0; - byte* derBuf = NULL; - int err; + key = (DsaKey*)dsa->internal; - WOLFSSL_ENTER("wolfSSL_RSAPublicKey_dup"); + if (dsa->p != NULL && + wolfssl_bn_get_value(dsa->p, &key->p) != 1) { + WOLFSSL_MSG("rsa p key error"); + return WOLFSSL_FATAL_ERROR; + } - err = (rsa == NULL); - if (!err) { - /* Create a new RSA key to return. */ - ret = wolfSSL_RSA_new(); - if (ret == NULL) { - WOLFSSL_ERROR_MSG("Error creating a new WOLFSSL_RSA structure"); - err = 1; - } + if (dsa->q != NULL && + wolfssl_bn_get_value(dsa->q, &key->q) != 1) { + WOLFSSL_MSG("rsa q key error"); + return WOLFSSL_FATAL_ERROR; } - if (!err) { - /* Encode RSA public key to copy to DER - allocates DER buffer. */ - if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1, rsa->heap)) < 0) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); - err = 1; - } + + if (dsa->g != NULL && + wolfssl_bn_get_value(dsa->g, &key->g) != 1) { + WOLFSSL_MSG("rsa g key error"); + return WOLFSSL_FATAL_ERROR; } - if (!err) { - /* Decode DER of the RSA public key into new key. */ - if (wolfSSL_RSA_LoadDer_ex(ret, derBuf, derSz, - WOLFSSL_RSA_LOAD_PUBLIC) != 1) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_LoadDer_ex failed"); - err = 1; + + if (dsa->pub_key != NULL) { + if (wolfssl_bn_get_value(dsa->pub_key, &key->y) != 1) { + WOLFSSL_MSG("rsa pub_key error"); + return WOLFSSL_FATAL_ERROR; } - } - /* Dispose of any allocated DER buffer. */ - XFREE(derBuf, rsa ? rsa->heap : NULL, DYNAMIC_TYPE_ASN1); - if (err) { - /* Disposes of any created RSA key - on error. */ - wolfSSL_RSA_free(ret); - ret = NULL; + /* public key */ + key->type = DSA_PUBLIC; } - return ret; -} -/* wolfSSL_RSAPrivateKey_dup not supported */ + if (dsa->priv_key != NULL) { + if (wolfssl_bn_get_value(dsa->priv_key, &key->x) != 1) { + WOLFSSL_MSG("rsa priv_key error"); + return WOLFSSL_FATAL_ERROR; + } -#endif /* WOLFSSL_KEY_GEN */ + /* private key */ + key->type = DSA_PRIVATE; + } -static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, - void* heap); + dsa->inSet = 1; -/* - * RSA to/from bin APIs - */ + return 1; +} -/* Convert RSA public key data to internal. - * - * Creates new RSA key from the DER encoded RSA public key. - * - * @param [out] out Pointer to RSA key to return through. May be NULL. - * @param [in, out] derBuf Pointer to start of DER encoded data. - * @param [in] derSz Length of the data in the DER buffer. - * @return RSA key on success. - * @return NULL on failure. +/* return code compliant with OpenSSL : + * 1 if success, 0 if error */ -WOLFSSL_RSA *wolfSSL_d2i_RSAPublicKey(WOLFSSL_RSA **out, - const unsigned char **derBuf, long derSz) +int wolfSSL_DSA_generate_key(WOLFSSL_DSA* dsa) { - WOLFSSL_RSA *rsa = NULL; - int err = 0; + int ret = 0; - WOLFSSL_ENTER("wolfSSL_d2i_RSAPublicKey"); + WOLFSSL_ENTER("wolfSSL_DSA_generate_key"); - /* Validate parameters. */ - if (derBuf == NULL) { - WOLFSSL_ERROR_MSG("Bad argument"); - err = 1; - } - /* Create a new RSA key to return. */ - if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) { - WOLFSSL_ERROR_MSG("RSA_new failed"); - err = 1; - } - /* Decode RSA key from DER. */ - if ((!err) && (wolfSSL_RSA_LoadDer_ex(rsa, *derBuf, (int)derSz, - WOLFSSL_RSA_LOAD_PUBLIC) != 1)) { - WOLFSSL_ERROR_MSG("RSA_LoadDer failed"); - err = 1; - } - if ((!err) && (out != NULL)) { - /* Return through parameter too. */ - *out = rsa; - /* Move buffer on by the used amount. */ - *derBuf += wolfssl_der_length(*derBuf, (int)derSz); + if (dsa == NULL || dsa->internal == NULL) { + WOLFSSL_MSG("Bad arguments"); + return 0; } - if (err) { - /* Dispose of any created RSA key. */ - wolfSSL_RSA_free(rsa); - rsa = NULL; - } - return rsa; -} + if (dsa->inSet == 0) { + WOLFSSL_MSG("No DSA internal set, do it"); -/* Convert RSA private key data to internal. - * - * Create a new RSA key from the DER encoded RSA private key. - * - * @param [out] out Pointer to RSA key to return through. May be NULL. - * @param [in, out] derBuf Pointer to start of DER encoded data. - * @param [in] derSz Length of the data in the DER buffer. - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA *wolfSSL_d2i_RSAPrivateKey(WOLFSSL_RSA **out, - const unsigned char **derBuf, long derSz) -{ - WOLFSSL_RSA *rsa = NULL; - int err = 0; + if (SetDsaInternal(dsa) != 1) { + WOLFSSL_MSG("SetDsaInternal failed"); + return ret; + } + } - WOLFSSL_ENTER("wolfSSL_d2i_RSAPublicKey"); +#ifdef WOLFSSL_KEY_GEN + { + int initTmpRng = 0; + WC_RNG *rng = NULL; + WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); - /* Validate parameters. */ - if (derBuf == NULL) { - WOLFSSL_ERROR_MSG("Bad argument"); - err = 1; - } - /* Create a new RSA key to return. */ - if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) { - WOLFSSL_ERROR_MSG("RSA_new failed"); - err = 1; - } - /* Decode RSA key from DER. */ - if ((!err) && (wolfSSL_RSA_LoadDer_ex(rsa, *derBuf, (int)derSz, - WOLFSSL_RSA_LOAD_PRIVATE) != 1)) { - WOLFSSL_ERROR_MSG("RSA_LoadDer failed"); - err = 1; - } - if ((!err) && (out != NULL)) { - /* Return through parameter too. */ - *out = rsa; - /* Move buffer on by the used amount. */ - *derBuf += wolfssl_der_length(*derBuf, (int)derSz); - } + WC_ALLOC_VAR_EX(tmpRng, WC_RNG, 1, NULL, DYNAMIC_TYPE_RNG, + return WOLFSSL_FATAL_ERROR); + if (wc_InitRng(tmpRng) == 0) { + rng = tmpRng; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + rng = wolfssl_get_global_rng(); + } - if (err) { - /* Dispose of any created RSA key. */ - wolfSSL_RSA_free(rsa); - rsa = NULL; - } - return rsa; -} + if (rng) { + /* These were allocated above by SetDsaInternal(). They should + * be cleared before wc_MakeDsaKey() which reinitializes + * x and y. */ + mp_clear(&((DsaKey*)dsa->internal)->x); + mp_clear(&((DsaKey*)dsa->internal)->y); -/* Converts an internal RSA structure to DER format for the private key. - * - * If "pp" is null then buffer size only is returned. - * If "*pp" is null then a created buffer is set in *pp and the caller is - * responsible for free'ing it. - * - * @param [in] rsa RSA key. - * @param [in, out] pp On in, pointer to allocated buffer or NULL. - * May be NULL. - * On out, newly allocated buffer or pointer to byte after - * encoding in passed in buffer. - * - * @return Size of DER encoding on success - * @return BAD_FUNC_ARG when rsa is NULL. - * @return 0 on failure. - */ -int wolfSSL_i2d_RSAPrivateKey(WOLFSSL_RSA *rsa, unsigned char **pp) -{ - int ret; + if (wc_MakeDsaKey(rng, (DsaKey*)dsa->internal) != MP_OKAY) + WOLFSSL_MSG("wc_MakeDsaKey failed"); + else if (SetDsaExternal(dsa) != 1) + WOLFSSL_MSG("SetDsaExternal failed"); + else + ret = 1; + } - WOLFSSL_ENTER("wolfSSL_i2d_RSAPrivateKey"); + if (initTmpRng) + wc_FreeRng(tmpRng); - /* Validate parameters. */ - if (rsa == NULL) { - WOLFSSL_ERROR_MSG("Bad Function Arguments"); - ret = BAD_FUNC_ARG; - } - /* Encode the RSA key as a DER. Call allocates buffer into pp. - * No heap hint as this gets returned to the user */ - else if ((ret = wolfSSL_RSA_To_Der_ex(rsa, pp, 0, NULL)) < 0) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); - ret = 0; + WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); } - - /* Size of DER encoding. */ +#else /* WOLFSSL_KEY_GEN */ + WOLFSSL_MSG("No Key Gen built in"); +#endif return ret; } -/* Converts an internal RSA structure to DER format for the public key. - * - * If "pp" is null then buffer size only is returned. - * If "*pp" is null then a created buffer is set in *pp and the caller is - * responsible for free'ing it. - * - * @param [in] rsa RSA key. - * @param [in, out] pp On in, pointer to allocated buffer or NULL. - * May be NULL. - * On out, newly allocated buffer or pointer to byte after - * encoding in passed in buffer. - * @return Size of DER encoding on success - * @return BAD_FUNC_ARG when rsa is NULL. - * @return 0 on failure. + +/* Returns a pointer to a new WOLFSSL_DSA structure on success and NULL on fail */ -int wolfSSL_i2d_RSAPublicKey(WOLFSSL_RSA *rsa, unsigned char **pp) +WOLFSSL_DSA* wolfSSL_DSA_generate_parameters(int bits, unsigned char* seed, + int seedLen, int* counterRet, unsigned long* hRet, + WOLFSSL_BN_CB cb, void* CBArg) { - int ret; + WOLFSSL_DSA* dsa; - WOLFSSL_ENTER("wolfSSL_i2d_RSAPublicKey"); + WOLFSSL_ENTER("wolfSSL_DSA_generate_parameters"); - /* check for bad functions arguments */ - if (rsa == NULL) { - WOLFSSL_ERROR_MSG("Bad Function Arguments"); - ret = BAD_FUNC_ARG; + (void)cb; + (void)CBArg; + dsa = wolfSSL_DSA_new(); + if (dsa == NULL) { + return NULL; } - /* Encode the RSA key as a DER. Call allocates buffer into pp. - * No heap hint as this gets returned to the user */ - else if ((ret = wolfSSL_RSA_To_Der_ex(rsa, pp, 1, NULL)) < 0) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); - ret = 0; + + if (wolfSSL_DSA_generate_parameters_ex(dsa, bits, seed, seedLen, + counterRet, hRet, NULL) != 1) { + wolfSSL_DSA_free(dsa); + return NULL; } - return ret; + return dsa; } -#endif /* OPENSSL_EXTRA */ -/* - * RSA to/from BIO APIs +/* return code compliant with OpenSSL : + * 1 if success, 0 if error */ +int wolfSSL_DSA_generate_parameters_ex(WOLFSSL_DSA* dsa, int bits, + unsigned char* seed, int seedLen, + int* counterRet, + unsigned long* hRet, void* cb) +{ + int ret = 0; -/* wolfSSL_d2i_RSAPublicKey_bio not supported */ + (void)bits; + (void)seed; + (void)seedLen; + (void)counterRet; + (void)hRet; + (void)cb; -#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY) \ - || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) + WOLFSSL_ENTER("wolfSSL_DSA_generate_parameters_ex"); -#if defined(WOLFSSL_KEY_GEN) && !defined(NO_BIO) + if (dsa == NULL || dsa->internal == NULL) { + WOLFSSL_MSG("Bad arguments"); + return 0; + } -/* Read DER data from a BIO. - * - * DER structures start with a constructed sequence. Use this to calculate the - * total length of the DER data. - * - * @param [in] bio BIO object to read from. - * @param [out] out Buffer holding DER encoding. - * @return Number of bytes to DER encoding on success. - * @return 0 on failure. - */ -static int wolfssl_read_der_bio(WOLFSSL_BIO* bio, unsigned char** out) -{ - int err = 0; - unsigned char seq[MAX_SEQ_SZ]; - unsigned char* der = NULL; - int derLen = 0; +#ifdef WOLFSSL_KEY_GEN + { + int initTmpRng = 0; + WC_RNG *rng = NULL; + WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); - /* Read in a minimal amount to get a SEQUENCE header of any size. */ - if (wolfSSL_BIO_read(bio, seq, sizeof(seq)) != sizeof(seq)) { - WOLFSSL_ERROR_MSG("wolfSSL_BIO_read() of sequence failure"); - err = 1; - } - /* Calculate complete DER encoding length. */ - if ((!err) && ((derLen = wolfssl_der_length(seq, sizeof(seq))) <= 0)) { - WOLFSSL_ERROR_MSG("DER SEQUENCE decode failed"); - err = 1; - } - /* Allocate a buffer to read DER data into. */ - if ((!err) && ((der = (unsigned char*)XMALLOC((size_t)derLen, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER)) == NULL)) { - WOLFSSL_ERROR_MSG("Malloc failure"); - err = 1; - } - if ((!err) && (derLen <= (int)sizeof(seq))) { - /* Copy the previously read data into the buffer. */ - XMEMCPY(der, seq, derLen); - } - else if (!err) { - /* Calculate the unread amount. */ - int len = derLen - (int)sizeof(seq); - /* Copy the previously read data into the buffer. */ - XMEMCPY(der, seq, sizeof(seq)); - /* Read rest of DER data from BIO. */ - if (wolfSSL_BIO_read(bio, der + sizeof(seq), len) != len) { - WOLFSSL_ERROR_MSG("wolfSSL_BIO_read() failure"); - err = 1; + WC_ALLOC_VAR_EX(tmpRng, WC_RNG, 1, NULL, DYNAMIC_TYPE_RNG, + return WOLFSSL_FATAL_ERROR); + if (wc_InitRng(tmpRng) == 0) { + rng = tmpRng; + initTmpRng = 1; + } + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); + rng = wolfssl_get_global_rng(); } - } - if (!err) { - /* Return buffer through parameter. */ - *out = der; - } - - if (err) { - /* Dispose of any allocated buffer on error. */ - XFREE(der, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - derLen = 0; - } - return derLen; -} -/* Reads the RSA private key data from a BIO to the internal form. - * - * Creates new RSA key from the DER encoded RSA private key read from the BIO. - * - * @param [in] bio BIO object to read from. - * @param [out] out Pointer to RSA key to return through. May be NULL. - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA* wolfSSL_d2i_RSAPrivateKey_bio(WOLFSSL_BIO *bio, WOLFSSL_RSA **out) -{ - WOLFSSL_RSA* key = NULL; - unsigned char* der = NULL; - int derLen = 0; - int err; + if (rng) { + if (wc_MakeDsaParameters(rng, bits, + (DsaKey*)dsa->internal) != MP_OKAY) + WOLFSSL_MSG("wc_MakeDsaParameters failed"); + else if (SetDsaExternal(dsa) != 1) + WOLFSSL_MSG("SetDsaExternal failed"); + else + ret = 1; + } - WOLFSSL_ENTER("wolfSSL_d2i_RSAPrivateKey_bio"); + if (initTmpRng) + wc_FreeRng(tmpRng); - /* Validate parameters. */ - err = (bio == NULL); - /* Read just DER encoding from BIO - buffer allocated in call. */ - if ((!err) && ((derLen = wolfssl_read_der_bio(bio, &der)) == 0)) { - err = 1; - } - if (!err) { - /* Keep der for call to deallocate. */ - const unsigned char* cder = der; - /* Create an RSA key from the data from the BIO. */ - key = wolfSSL_d2i_RSAPrivateKey(NULL, &cder, derLen); - err = (key == NULL); - } - if ((!err) && (out != NULL)) { - /* Return the created RSA key through the parameter. */ - *out = key; + WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); } +#else /* WOLFSSL_KEY_GEN */ + WOLFSSL_MSG("No Key Gen built in"); +#endif - if (err) { - /* Dispose of created key on error. */ - wolfSSL_RSA_free(key); - key = NULL; - } - /* Dispose of allocated data. */ - XFREE(der, bio ? bio->heap : NULL, DYNAMIC_TYPE_TMP_BUFFER); - return key; + return ret; } -#endif /* defined(WOLFSSL_KEY_GEN) && !NO_BIO */ - -#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */ -/* - * RSA DER APIs - */ - -#ifdef OPENSSL_EXTRA - -/* Create a DER encoding of key. - * - * Not OpenSSL API. - * - * @param [in] rsa RSA key. - * @param [out] outBuf Allocated buffer containing DER encoding. - * May be NULL. - * @param [in] publicKey Whether to encode as public key. - * @param [in] heap Heap hint. - * @return Encoding size on success. - * @return Negative on failure. - */ -int wolfSSL_RSA_To_Der(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, - void* heap) +void wolfSSL_DSA_get0_pqg(const WOLFSSL_DSA *d, const WOLFSSL_BIGNUM **p, + const WOLFSSL_BIGNUM **q, const WOLFSSL_BIGNUM **g) { - byte* p = NULL; - int ret; - - if (outBuf != NULL) { - p = *outBuf; - } - ret = wolfSSL_RSA_To_Der_ex(rsa, outBuf, publicKey, heap); - if ((ret > 0) && (p != NULL)) { - *outBuf = p; + WOLFSSL_ENTER("wolfSSL_DSA_get0_pqg"); + if (d != NULL) { + if (p != NULL) + *p = d->p; + if (q != NULL) + *q = d->q; + if (g != NULL) + *g = d->g; } - return ret; } -/* Create a DER encoding of key. - * - * Buffer allocated with heap and DYNAMIC_TYPE_TMP_BUFFER. - * - * @param [in] rsa RSA key. - * @param [in, out] outBuf On in, pointer to allocated buffer or NULL. - * May be NULL. - * On out, newly allocated buffer or pointer to byte - * after encoding in passed in buffer. - * @param [in] publicKey Whether to encode as public key. - * @param [in] heap Heap hint. - * @return Encoding size on success. - * @return Negative on failure. - */ -static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, - void* heap) +int wolfSSL_DSA_set0_pqg(WOLFSSL_DSA *d, WOLFSSL_BIGNUM *p, + WOLFSSL_BIGNUM *q, WOLFSSL_BIGNUM *g) { - int ret = 1; - int derSz = 0; - byte* derBuf = NULL; + WOLFSSL_ENTER("wolfSSL_DSA_set0_pqg"); + if (d == NULL || p == NULL || q == NULL || g == NULL) { + WOLFSSL_MSG("Bad parameter"); + return 0; + } + wolfSSL_BN_free(d->p); + wolfSSL_BN_free(d->q); + wolfSSL_BN_free(d->g); + d->p = p; + d->q = q; + d->g = g; + return 1; +} - WOLFSSL_ENTER("wolfSSL_RSA_To_Der"); +void wolfSSL_DSA_get0_key(const WOLFSSL_DSA *d, + const WOLFSSL_BIGNUM **pub_key, const WOLFSSL_BIGNUM **priv_key) +{ + WOLFSSL_ENTER("wolfSSL_DSA_get0_key"); + if (d != NULL) { + if (pub_key != NULL) + *pub_key = d->pub_key; + if (priv_key != NULL) + *priv_key = d->priv_key; + } +} - /* Unused if memory is disabled. */ - (void)heap; +int wolfSSL_DSA_set0_key(WOLFSSL_DSA *d, WOLFSSL_BIGNUM *pub_key, + WOLFSSL_BIGNUM *priv_key) +{ + WOLFSSL_ENTER("wolfSSL_DSA_set0_key"); - /* Validate parameters. */ - if ((rsa == NULL) || ((publicKey != 0) && (publicKey != 1))) { - WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", BAD_FUNC_ARG); - ret = BAD_FUNC_ARG; + /* The private key may be NULL */ + if (d->pub_key == NULL && pub_key == NULL) { + WOLFSSL_MSG("Bad parameter"); + return 0; } - /* Push external RSA data into internal RSA key if not set. */ - if ((ret == 1) && (!rsa->inSet)) { - ret = SetRsaInternal(rsa); + + if (pub_key != NULL) { + wolfSSL_BN_free(d->pub_key); + d->pub_key = pub_key; } - /* wc_RsaKeyToPublicDer encode regardless of values. */ - if ((ret == 1) && publicKey && (mp_iszero(&((RsaKey*)rsa->internal)->n) || - mp_iszero(&((RsaKey*)rsa->internal)->e))) { - ret = BAD_FUNC_ARG; + if (priv_key != NULL) { + wolfSSL_BN_free(d->priv_key); + d->priv_key = priv_key; } - if (ret == 1) { - if (publicKey) { - /* Calculate length of DER encoded RSA public key. */ - derSz = wc_RsaPublicKeyDerSize((RsaKey*)rsa->internal, 1); - if (derSz < 0) { - WOLFSSL_ERROR_MSG("wc_RsaPublicKeyDerSize failed"); - ret = derSz; - } - } - else { - /* Calculate length of DER encoded RSA private key. */ - derSz = wc_RsaKeyToDer((RsaKey*)rsa->internal, NULL, 0); - if (derSz < 0) { - WOLFSSL_ERROR_MSG("wc_RsaKeyToDer failed"); - ret = derSz; - } - } - } + return 1; +} - if ((ret == 1) && (outBuf != NULL)) { - derBuf = *outBuf; - if (derBuf == NULL) { - /* Allocate buffer to hold DER encoded RSA key. */ - derBuf = (byte*)XMALLOC((size_t)derSz, heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (derBuf == NULL) { - WOLFSSL_ERROR_MSG("Memory allocation failed"); - ret = MEMORY_ERROR; - } - } - } - if ((ret == 1) && (outBuf != NULL)) { - if (publicKey > 0) { - /* RSA public key to DER. */ - derSz = wc_RsaKeyToPublicDer((RsaKey*)rsa->internal, derBuf, - (word32)derSz); - } - else { - /* RSA private key to DER. */ - derSz = wc_RsaKeyToDer((RsaKey*)rsa->internal, derBuf, - (word32)derSz); - } - if (derSz < 0) { - WOLFSSL_ERROR_MSG("RSA key encoding failed"); - ret = derSz; - } - else if ((*outBuf) != NULL) { - derBuf = NULL; - *outBuf += derSz; +WOLFSSL_DSA_SIG* wolfSSL_DSA_SIG_new(void) +{ + WOLFSSL_DSA_SIG* sig; + WOLFSSL_ENTER("wolfSSL_DSA_SIG_new"); + sig = (WOLFSSL_DSA_SIG*)XMALLOC(sizeof(WOLFSSL_DSA_SIG), NULL, + DYNAMIC_TYPE_OPENSSL); + if (sig) + XMEMSET(sig, 0, sizeof(WOLFSSL_DSA_SIG)); + return sig; +} + +void wolfSSL_DSA_SIG_free(WOLFSSL_DSA_SIG *sig) +{ + WOLFSSL_ENTER("wolfSSL_DSA_SIG_free"); + if (sig) { + if (sig->r) { + wolfSSL_BN_free(sig->r); } - else { - /* Return allocated buffer. */ - *outBuf = derBuf; + if (sig->s) { + wolfSSL_BN_free(sig->s); } + XFREE(sig, NULL, DYNAMIC_TYPE_OPENSSL); } - if (ret == 1) { - /* Success - return DER encoding size. */ - ret = derSz; - } +} - if ((outBuf != NULL) && (*outBuf != derBuf)) { - /* Not returning buffer, needs to be disposed of. */ - XFREE(derBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); +void wolfSSL_DSA_SIG_get0(const WOLFSSL_DSA_SIG *sig, + const WOLFSSL_BIGNUM **r, const WOLFSSL_BIGNUM **s) +{ + WOLFSSL_ENTER("wolfSSL_DSA_SIG_get0"); + if (sig != NULL) { + *r = sig->r; + *s = sig->s; } - WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", ret); - return ret; } -#endif /* OPENSSL_EXTRA */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -/* Load the DER encoded private RSA key. - * - * Not OpenSSL API. - * - * @param [in] rsa RSA key. - * @param [in] derBuf Buffer holding DER encoding. - * @param [in] derSz Length of DER encoding. - * @return 1 on success. - * @return -1 on failure. - */ -int wolfSSL_RSA_LoadDer(WOLFSSL_RSA* rsa, const unsigned char* derBuf, - int derSz) +int wolfSSL_DSA_SIG_set0(WOLFSSL_DSA_SIG *sig, WOLFSSL_BIGNUM *r, + WOLFSSL_BIGNUM *s) { - /* Call implementation that handles both private and public keys. */ - return wolfSSL_RSA_LoadDer_ex(rsa, derBuf, derSz, WOLFSSL_RSA_LOAD_PRIVATE); + WOLFSSL_ENTER("wolfSSL_DSA_SIG_set0"); + if (r == NULL || s == NULL) { + WOLFSSL_MSG("Bad parameter"); + return 0; + } + + wolfSSL_BN_clear_free(sig->r); + wolfSSL_BN_clear_free(sig->s); + sig->r = r; + sig->s = s; + + return 1; } -/* Load the DER encoded public or private RSA key. - * - * Not OpenSSL API. +#ifndef HAVE_SELFTEST +/** * - * @param [in] rsa RSA key. - * @param [in] derBuf Buffer holding DER encoding. - * @param [in] derSz Length of DER encoding. - * @param [in] opt Indicates public or private key. - * (WOLFSSL_RSA_LOAD_PUBLIC or WOLFSSL_RSA_LOAD_PRIVATE) - * @return 1 on success. - * @return -1 on failure. + * @param sig The input signature to encode + * @param out The output buffer. If *out is NULL then a new buffer is + * allocated. Otherwise the output is written to the buffer. + * @return length on success and -1 on error */ -int wolfSSL_RSA_LoadDer_ex(WOLFSSL_RSA* rsa, const unsigned char* derBuf, - int derSz, int opt) +int wolfSSL_i2d_DSA_SIG(const WOLFSSL_DSA_SIG *sig, byte **out) { - int ret = 1; - int res; - word32 idx = 0; - word32 algId; + /* Space for sequence + two asn ints */ + byte buf[MAX_SEQ_SZ + 2*(ASN_TAG_SZ + MAX_LENGTH_SZ + DSA_MAX_HALF_SIZE)]; + word32 bufLen = sizeof(buf); - WOLFSSL_ENTER("wolfSSL_RSA_LoadDer"); + WOLFSSL_ENTER("wolfSSL_i2d_DSA_SIG"); - /* Validate parameters. */ - if ((rsa == NULL) || (rsa->internal == NULL) || (derBuf == NULL) || - (derSz <= 0)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = WOLFSSL_FATAL_ERROR; + if (sig == NULL || sig->r == NULL || sig->s == NULL || + out == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FATAL_ERROR; } - if (ret == 1) { - rsa->pkcs8HeaderSz = 0; - /* Check if input buffer has PKCS8 header. In the case that it does not - * have a PKCS8 header then do not error out. */ - res = ToTraditionalInline_ex((const byte*)derBuf, &idx, (word32)derSz, - &algId); - if (res > 0) { - /* Store size of PKCS#8 header for encoding. */ - WOLFSSL_MSG("Found PKCS8 header"); - rsa->pkcs8HeaderSz = (word16)idx; - } - /* When decoding and not PKCS#8, return will be ASN_PARSE_E. */ - else if (res != WC_NO_ERR_TRACE(ASN_PARSE_E)) { - /* Something went wrong while decoding. */ - WOLFSSL_ERROR_MSG("Unexpected error with trying to remove PKCS#8 " - "header"); - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 1) { - /* Decode private or public key data. */ - if (opt == WOLFSSL_RSA_LOAD_PRIVATE) { - res = wc_RsaPrivateKeyDecode(derBuf, &idx, (RsaKey*)rsa->internal, - (word32)derSz); - } - else { - res = wc_RsaPublicKeyDecode(derBuf, &idx, (RsaKey*)rsa->internal, - (word32)derSz); - } - /* Check for error. */ - if (res < 0) { - if (opt == WOLFSSL_RSA_LOAD_PRIVATE) { - WOLFSSL_ERROR_MSG("RsaPrivateKeyDecode failed"); - } - else { - WOLFSSL_ERROR_MSG("RsaPublicKeyDecode failed"); - } - WOLFSSL_ERROR_VERBOSE(res); - ret = WOLFSSL_FATAL_ERROR; - } + if (StoreECC_DSA_Sig(buf, &bufLen, + (mp_int*)sig->r->internal, (mp_int*)sig->s->internal) != 0) { + WOLFSSL_MSG("StoreECC_DSA_Sig error"); + return WOLFSSL_FATAL_ERROR; } - if (ret == 1) { - /* Set external RSA key data from wolfCrypt key. */ - if (SetRsaExternal(rsa) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - else { - rsa->inSet = 1; + + if (*out == NULL) { + byte* tmp = (byte*)XMALLOC(bufLen, NULL, DYNAMIC_TYPE_ASN1); + if (tmp == NULL) { + WOLFSSL_MSG("malloc error"); + return WOLFSSL_FATAL_ERROR; } + *out = tmp; } - return ret; -} - -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + XMEMCPY(*out, buf, bufLen); -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) + return (int)bufLen; +} -#if !defined(NO_BIO) || !defined(NO_FILESYSTEM) -/* Load DER encoded data into WOLFSSL_RSA object. - * - * Creates a new WOLFSSL_RSA object if one is not passed in. - * - * @param [in, out] rsa WOLFSSL_RSA object to load into. - * When rsa or *rsa is NULL a new object is created. - * When not NULL and *rsa is NULL then new object - * returned through pointer. - * @param [in] in DER encoded RSA key data. - * @param [in] inSz Size of DER encoded data in bytes. - * @param [in] opt Public or private key encoded in data. Valid values: - * WOLFSSL_RSA_LOAD_PRIVATE, WOLFSSL_RSA_LOAD_PUBLIC. - * @return NULL on failure. - * @return WOLFSSL_RSA object on success. +/** + * Same as wolfSSL_DSA_SIG_new but also initializes the internal bignums. + * @return New WOLFSSL_DSA_SIG with r and s created as well */ -static WOLFSSL_RSA* wolfssl_rsa_d2i(WOLFSSL_RSA** rsa, const unsigned char* in, - long inSz, int opt) +static WOLFSSL_DSA_SIG* wolfSSL_DSA_SIG_new_bn(void) { - WOLFSSL_RSA* ret = NULL; + WOLFSSL_DSA_SIG* ret; - if ((rsa != NULL) && (*rsa != NULL)) { - ret = *rsa; - } - else { - ret = wolfSSL_RSA_new(); + if ((ret = wolfSSL_DSA_SIG_new()) == NULL) { + WOLFSSL_MSG("wolfSSL_DSA_SIG_new error"); + return NULL; } - if ((ret != NULL) && (wolfSSL_RSA_LoadDer_ex(ret, in, (int)inSz, opt) - != 1)) { - if ((rsa == NULL) || (ret != *rsa)) { - wolfSSL_RSA_free(ret); - } - ret = NULL; + + if ((ret->r = wolfSSL_BN_new()) == NULL) { + WOLFSSL_MSG("wolfSSL_BN_new error"); + wolfSSL_DSA_SIG_free(ret); + return NULL; } - if ((rsa != NULL) && (*rsa == NULL)) { - *rsa = ret; + if ((ret->s = wolfSSL_BN_new()) == NULL) { + WOLFSSL_MSG("wolfSSL_BN_new error"); + wolfSSL_DSA_SIG_free(ret); + return NULL; } + return ret; } -#endif -#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ - -/* - * RSA PEM APIs +/** + * This parses a DER encoded ASN.1 structure. The ASN.1 encoding is: + * ASN1_SEQUENCE + * ASN1_INTEGER (DSA r) + * ASN1_INTEGER (DSA s) + * Alternatively, if the input is DSA_160_SIG_SIZE or DSA_256_SIG_SIZE in + * length then this API interprets this as two unsigned binary numbers. + * @param sig If non-null then free'd first and then newly created + * WOLFSSL_DSA_SIG is assigned + * @param pp Input buffer that is moved forward on success + * @param length Length of input buffer + * @return Newly created WOLFSSL_DSA_SIG on success or NULL on failure */ +WOLFSSL_DSA_SIG* wolfSSL_d2i_DSA_SIG(WOLFSSL_DSA_SIG **sig, + const unsigned char **pp, long length) +{ + WOLFSSL_DSA_SIG* ret; + mp_int* r; + mp_int* s; -#ifdef OPENSSL_EXTRA + WOLFSSL_ENTER("wolfSSL_d2i_DSA_SIG"); -#ifndef NO_BIO -#if defined(WOLFSSL_KEY_GEN) -/* Writes PEM encoding of an RSA public key to a BIO. - * - * @param [in] bio BIO object to write to. - * @param [in] rsa RSA key to write. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_PEM_write_bio_RSA_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa) -{ - int ret = 1; - int derSz = 0; - byte* derBuf = NULL; - - WOLFSSL_ENTER("wolfSSL_PEM_write_bio_RSA_PUBKEY"); + if (pp == NULL || *pp == NULL || length < 0) { + WOLFSSL_MSG("Bad function arguments"); + return NULL; + } - /* Validate parameters. */ - if ((bio == NULL) || (rsa == NULL)) { - WOLFSSL_ERROR_MSG("Bad Function Arguments"); - return 0; + if ((ret = wolfSSL_DSA_SIG_new_bn()) == NULL) { + WOLFSSL_MSG("wolfSSL_DSA_SIG_new_bn error"); + return NULL; } - if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1, bio->heap)) < 0) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); - ret = 0; + r = (mp_int*)ret->r->internal; + s = (mp_int*)ret->s->internal; + + if (DecodeECC_DSA_Sig(*pp, (word32)length, r, s) != 0) { + if (length == DSA_160_SIG_SIZE || length == DSA_256_SIG_SIZE) { + /* Two raw numbers of length/2 size each */ + if (mp_read_unsigned_bin(r, *pp, (word32)length/2) != 0) { + WOLFSSL_MSG("r mp_read_unsigned_bin error"); + wolfSSL_DSA_SIG_free(ret); + return NULL; + } + + if (mp_read_unsigned_bin(s, *pp + (length/2), (word32)length/2) != + 0) { + WOLFSSL_MSG("s mp_read_unsigned_bin error"); + wolfSSL_DSA_SIG_free(ret); + return NULL; + } + + *pp += length; + } + else { + WOLFSSL_MSG("DecodeECC_DSA_Sig error"); + wolfSSL_DSA_SIG_free(ret); + return NULL; + } } - if (derBuf == NULL) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed to get buffer"); - ret = 0; + else { + /* DecodeECC_DSA_Sig success move pointer forward */ +#ifndef NO_STRICT_ECDSA_LEN + *pp += length; +#else + { + /* We need to figure out how much to move by ourselves */ + word32 idx = 0; + int len = 0; + if (GetSequence(*pp, &idx, &len, (word32)length) < 0) { + WOLFSSL_MSG("GetSequence error"); + wolfSSL_DSA_SIG_free(ret); + return NULL; + } + *pp += len; + } +#endif } - if ((ret == 1) && (der_write_to_bio_as_pem(derBuf, derSz, bio, - PUBLICKEY_TYPE) != 1)) { - ret = 0; + + if (sig != NULL) { + if (*sig != NULL) + wolfSSL_DSA_SIG_free(*sig); + *sig = ret; } - /* Dispose of DER buffer. */ - XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); return ret; } -#endif /* WOLFSSL_KEY_GEN */ -#endif /* !NO_BIO */ - -#if defined(WOLFSSL_KEY_GEN) -#ifndef NO_FILESYSTEM +#endif /* !HAVE_SELFTEST */ -/* Writes PEM encoding of an RSA public key to a file pointer. - * - * @param [in] fp File pointer to write to. - * @param [in] rsa RSA key to write. - * @param [in] type PEM type to write out. - * @return 1 on success. - * @return 0 on failure. - */ -static int wolfssl_pem_write_rsa_public_key(XFILE fp, WOLFSSL_RSA* rsa, - int type) +static int dsa_do_sign(const unsigned char* d, int dLen, unsigned char* sigRet, + WOLFSSL_DSA* dsa) { - int ret = 1; - int derSz; - byte* derBuf = NULL; + int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); + int initTmpRng = 0; + WC_RNG* rng = NULL; + WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); - /* Validate parameters. */ - if ((fp == XBADFILE) || (rsa == NULL)) { - WOLFSSL_ERROR_MSG("Bad Function Arguments"); - return 0; + if (d == NULL || sigRet == NULL || dsa == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FATAL_ERROR; } - if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1, rsa->heap)) < 0) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); - ret = 0; + if (dsa->inSet == 0) { + WOLFSSL_MSG("No DSA internal set, do it"); + if (SetDsaInternal(dsa) != 1) { + WOLFSSL_MSG("SetDsaInternal failed"); + return WOLFSSL_FATAL_ERROR; + } } - if (derBuf == NULL) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed to get buffer"); - ret = 0; + + WC_ALLOC_VAR_EX(tmpRng, WC_RNG, 1, NULL, DYNAMIC_TYPE_RNG, + return WOLFSSL_FATAL_ERROR); + + if (wc_InitRng(tmpRng) == 0) { + rng = tmpRng; + initTmpRng = 1; } - if ((ret == 1) && (der_write_to_file_as_pem(derBuf, derSz, fp, type, - rsa->heap) != 1)) { - ret = 0; + else { + WOLFSSL_MSG("Bad RNG Init, trying global"); +#ifdef WOLFSSL_SMALL_STACK + XFREE(tmpRng, NULL, DYNAMIC_TYPE_RNG); + tmpRng = NULL; +#endif + rng = wolfssl_get_global_rng(); + if (! rng) + return WOLFSSL_FATAL_ERROR; } - /* Dispose of DER buffer. */ - XFREE(derBuf, rsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (rng) { +#ifdef HAVE_SELFTEST + if (dLen != WC_SHA_DIGEST_SIZE || + wc_DsaSign(d, sigRet, (DsaKey*)dsa->internal, rng) < 0) { + WOLFSSL_MSG("wc_DsaSign failed or dLen wrong length"); + ret = WOLFSSL_FATAL_ERROR; + } +#else + if (wc_DsaSign_ex(d, dLen, sigRet, (DsaKey*)dsa->internal, rng) < 0) { + WOLFSSL_MSG("wc_DsaSign_ex failed"); + ret = WOLFSSL_FATAL_ERROR; + } +#endif + else + ret = WOLFSSL_SUCCESS; + } + + if (initTmpRng) + wc_FreeRng(tmpRng); + WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); return ret; } -/* Writes PEM encoding of an RSA public key to a file pointer. - * - * Header/footer will contain: PUBLIC KEY - * - * @param [in] fp File pointer to write to. - * @param [in] rsa RSA key to write. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_PEM_write_RSA_PUBKEY(XFILE fp, WOLFSSL_RSA* rsa) +/* return 1 on success, < 0 otherwise */ +int wolfSSL_DSA_do_sign(const unsigned char* d, unsigned char* sigRet, + WOLFSSL_DSA* dsa) { - return wolfssl_pem_write_rsa_public_key(fp, rsa, PUBLICKEY_TYPE); -} + WOLFSSL_ENTER("wolfSSL_DSA_do_sign"); -/* Writes PEM encoding of an RSA public key to a file pointer. - * - * Header/footer will contain: RSA PUBLIC KEY - * - * @param [in] fp File pointer to write to. - * @param [in] rsa RSA key to write. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_PEM_write_RSAPublicKey(XFILE fp, WOLFSSL_RSA* rsa) -{ - return wolfssl_pem_write_rsa_public_key(fp, rsa, RSA_PUBLICKEY_TYPE); + return dsa_do_sign(d, WC_SHA_DIGEST_SIZE, sigRet, dsa); } -#endif /* !NO_FILESYSTEM */ -#endif /* WOLFSSL_KEY_GEN */ -#ifndef NO_BIO -/* Create an RSA public key by reading the PEM encoded data from the BIO. - * - * @param [in] bio BIO object to read from. - * @param [out] out RSA key created. - * @param [in] cb Password callback when PEM encrypted. - * @param [in] pass NUL terminated string for passphrase when PEM encrypted. - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA *wolfSSL_PEM_read_bio_RSA_PUBKEY(WOLFSSL_BIO* bio, - WOLFSSL_RSA** out, wc_pem_password_cb* cb, void *pass) +#ifndef HAVE_SELFTEST +WOLFSSL_DSA_SIG* wolfSSL_DSA_do_sign_ex(const unsigned char* digest, + int inLen, WOLFSSL_DSA* dsa) { - WOLFSSL_RSA* rsa = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_RSA_PUBKEY"); - - if ((bio != NULL) && (pem_read_bio_key(bio, cb, pass, PUBLICKEY_TYPE, - &keyFormat, &der) >= 0)) { - rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, - WOLFSSL_RSA_LOAD_PUBLIC); - if (rsa == NULL) { - WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); - } - } - - FreeDer(&der); - if ((out != NULL) && (rsa != NULL)) { - *out = rsa; - } - return rsa; -} + byte sigBin[DSA_MAX_SIG_SIZE]; + const byte *tmp = sigBin; + int sigLen; -WOLFSSL_RSA *wolfSSL_d2i_RSA_PUBKEY_bio(WOLFSSL_BIO *bio, WOLFSSL_RSA **out) -{ - char* data = NULL; - int dataSz = 0; - int memAlloced = 0; - WOLFSSL_RSA* rsa = NULL; + WOLFSSL_ENTER("wolfSSL_DSA_do_sign_ex"); - WOLFSSL_ENTER("wolfSSL_d2i_RSA_PUBKEY_bio"); + if (!digest || !dsa) { + WOLFSSL_MSG("Bad function arguments"); + return NULL; + } - if (bio == NULL) + if (dsa_do_sign(digest, inLen, sigBin, dsa) != 1) { + WOLFSSL_MSG("wolfSSL_DSA_do_sign error"); return NULL; + } - if (wolfssl_read_bio(bio, &data, &dataSz, &memAlloced) != 0) { - if (memAlloced) - XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (dsa->internal == NULL) { + WOLFSSL_MSG("dsa->internal is null"); return NULL; } - rsa = wolfssl_rsa_d2i(out, (const unsigned char*)data, dataSz, - WOLFSSL_RSA_LOAD_PUBLIC); - if (memAlloced) - XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + sigLen = mp_unsigned_bin_size(&((DsaKey*)dsa->internal)->q); + if (sigLen <= 0) { + WOLFSSL_MSG("mp_unsigned_bin_size error"); + return NULL; + } - return rsa; + /* 2 * sigLen for the two points r and s */ + return wolfSSL_d2i_DSA_SIG(NULL, &tmp, 2 * sigLen); } -#endif /* !NO_BIO */ +#endif -#ifndef NO_FILESYSTEM -/* Create an RSA public key by reading the PEM encoded data from the BIO. - * - * Header/footer should contain: PUBLIC KEY - * PEM decoder supports either 'RSA PUBLIC KEY' or 'PUBLIC KEY'. - * - * @param [in] fp File pointer to read from. - * @param [out] out RSA key created. - * @param [in] cb Password callback when PEM encrypted. - * @param [in] pass NUL terminated string for passphrase when PEM encrypted. - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA *wolfSSL_PEM_read_RSA_PUBKEY(XFILE fp, - WOLFSSL_RSA** out, wc_pem_password_cb* cb, void *pass) +static int dsa_do_verify(const unsigned char* d, int dLen, unsigned char* sig, + WOLFSSL_DSA* dsa, int *dsacheck) { - WOLFSSL_RSA* rsa = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_read_RSA_PUBKEY"); - - if ((fp != XBADFILE) && (pem_read_file_key(fp, cb, pass, PUBLICKEY_TYPE, - &keyFormat, &der) >= 0)) { - rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, - WOLFSSL_RSA_LOAD_PUBLIC); - if (rsa == NULL) { - WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); + int ret; + + if (d == NULL || sig == NULL || dsa == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FATAL_ERROR; + } + if (dsa->inSet == 0) + { + WOLFSSL_MSG("No DSA internal set, do it"); + + if (SetDsaInternal(dsa) != 1) { + WOLFSSL_MSG("SetDsaInternal failed"); + return WOLFSSL_FATAL_ERROR; } } - FreeDer(&der); - if ((out != NULL) && (rsa != NULL)) { - *out = rsa; +#ifdef HAVE_SELFTEST + ret = dLen == WC_SHA_DIGEST_SIZE ? + wc_DsaVerify(d, sig, (DsaKey*)dsa->internal, dsacheck) : BAD_FUNC_ARG; +#else + ret = wc_DsaVerify_ex(d, (word32)dLen, sig, (DsaKey*)dsa->internal, + dsacheck); +#endif + if (ret != 0) { + WOLFSSL_MSG("DsaVerify failed"); + return WOLFSSL_FATAL_ERROR; + } + if (*dsacheck != 1) { + WOLFSSL_MSG("DsaVerify sig failed"); + return WOLFSSL_FAILURE; } - return rsa; + + return WOLFSSL_SUCCESS; } -/* Create an RSA public key by reading the PEM encoded data from the BIO. - * - * Header/footer should contain: RSA PUBLIC KEY - * PEM decoder supports either 'RSA PUBLIC KEY' or 'PUBLIC KEY'. - * - * @param [in] fp File pointer to read from. - * @param [out] rsa RSA key created. - * @param [in] cb Password callback when PEM encrypted. May be NULL. - * @param [in] pass NUL terminated string for passphrase when PEM encrypted. - * May be NULL. - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA* wolfSSL_PEM_read_RSAPublicKey(XFILE fp, WOLFSSL_RSA** rsa, - wc_pem_password_cb* cb, void* pass) +int wolfSSL_DSA_do_verify(const unsigned char* d, unsigned char* sig, + WOLFSSL_DSA* dsa, int *dsacheck) { - return wolfSSL_PEM_read_RSA_PUBKEY(fp, rsa, cb, pass); -} + WOLFSSL_ENTER("wolfSSL_DSA_do_verify"); -#endif /* NO_FILESYSTEM */ + return dsa_do_verify(d, WC_SHA_DIGEST_SIZE, sig, dsa, dsacheck); +} -#if defined(WOLFSSL_KEY_GEN) && \ - (defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)) -/* Writes PEM encoding of an RSA private key to newly allocated buffer. - * - * Buffer returned was allocated with: DYNAMIC_TYPE_KEY. - * - * @param [in] rsa RSA key to write. - * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. - * @param [in] passwd Password string when PEM encrypted. May be NULL. - * @param [in] passwdSz Length of password string when PEM encrypted. - * @param [out] pem Allocated buffer with PEM encoding. - * @param [out] pLen Length of PEM encoding. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_PEM_write_mem_RSAPrivateKey(WOLFSSL_RSA* rsa, - const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, - unsigned char **pem, int *pLen) +int wolfSSL_DSA_bits(const WOLFSSL_DSA *d) { - int ret = 1; - byte* derBuf = NULL; - int derSz = 0; + if (!d) + return 0; + if (!d->exSet && SetDsaExternal((WOLFSSL_DSA*)d) != 1) + return 0; + return wolfSSL_BN_num_bits(d->p); +} - WOLFSSL_ENTER("wolfSSL_PEM_write_mem_RSAPrivateKey"); +#ifndef HAVE_SELFTEST +int wolfSSL_DSA_do_verify_ex(const unsigned char* digest, int digest_len, + WOLFSSL_DSA_SIG* sig, WOLFSSL_DSA* dsa) +{ + int dsacheck, sz; + byte sigBin[DSA_MAX_SIG_SIZE]; + byte* sigBinPtr = sigBin; + DsaKey* key; + int qSz; - /* Validate parameters. */ - if ((pem == NULL) || (pLen == NULL) || (rsa == NULL) || - (rsa->internal == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = 0; - } + WOLFSSL_ENTER("wolfSSL_DSA_do_verify_ex"); - /* Set the RSA key data into the wolfCrypt RSA key if not done so. */ - if ((ret == 1) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { - ret = 0; + if (!digest || !sig || !dsa) { + WOLFSSL_MSG("Bad function arguments"); + return 0; } - /* Encode wolfCrypt RSA key to DER - derBuf allocated in call. */ - if ((ret == 1) && ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 0, - rsa->heap)) < 0)) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); - ret = 0; + if (!sig->r || !sig->s) { + WOLFSSL_MSG("No signature found in DSA_SIG"); + return 0; } - if ((ret == 1) && (der_to_enc_pem_alloc(derBuf, derSz, cipher, passwd, - passwdSz, PRIVATEKEY_TYPE, NULL, pem, pLen) != 1)) { - WOLFSSL_ERROR_MSG("der_to_enc_pem_alloc failed"); - ret = 0; + if (dsa->inSet == 0) { + WOLFSSL_MSG("No DSA internal set, do it"); + if (SetDsaInternal(dsa) != 1) { + WOLFSSL_MSG("SetDsaInternal failed"); + return 0; + } } - return ret; -} + key = (DsaKey*)dsa->internal; -#ifndef NO_BIO -/* Writes PEM encoding of an RSA private key to a BIO. - * - * @param [in] bio BIO object to write to. - * @param [in] rsa RSA key to write. - * @param [in] cipher Cipher to use when PEM encrypted. - * @param [in] passwd Password string when PEM encrypted. - * @param [in] len Length of password string when PEM encrypted. - * @param [in] cb Password callback to use when PEM encrypted. - * @param [in] arg NUL terminated string for passphrase when PEM encrypted. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_PEM_write_bio_RSAPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa, - const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int len, - wc_pem_password_cb* cb, void* arg) -{ - int ret = 1; - byte* pem = NULL; - int pLen = 0; + if (key == NULL) { + WOLFSSL_MSG("dsa->internal is null"); + return 0; + } - (void)cb; - (void)arg; + qSz = mp_unsigned_bin_size(&key->q); + if (qSz < 0 || qSz > DSA_MAX_HALF_SIZE) { + WOLFSSL_MSG("mp_unsigned_bin_size error"); + return 0; + } - WOLFSSL_ENTER("wolfSSL_PEM_write_bio_RSAPrivateKey"); + /* read r */ + /* front pad with zeros */ + if ((sz = wolfSSL_BN_num_bytes(sig->r)) < 0 || sz > DSA_MAX_HALF_SIZE) + return 0; + while (sz++ < qSz) + *sigBinPtr++ = 0; + if (wolfSSL_BN_bn2bin(sig->r, sigBinPtr) == -1) + return 0; - /* Validate parameters. */ - if ((bio == NULL) || (rsa == NULL) || (rsa->internal == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = 0; - } + /* Move to s */ + sigBinPtr = sigBin + qSz; - if (ret == 1) { - /* Write PEM to buffer that is allocated in the call. */ - ret = wolfSSL_PEM_write_mem_RSAPrivateKey(rsa, cipher, passwd, len, - &pem, &pLen); - if (ret != 1) { - WOLFSSL_ERROR_MSG("wolfSSL_PEM_write_mem_RSAPrivateKey failed"); - } - } - /* Write PEM to BIO. */ - if ((ret == 1) && (wolfSSL_BIO_write(bio, pem, pLen) <= 0)) { - WOLFSSL_ERROR_MSG("RSA private key BIO write failed"); - ret = 0; + /* read s */ + /* front pad with zeros */ + if ((sz = wolfSSL_BN_num_bytes(sig->s)) < 0 || sz > DSA_MAX_HALF_SIZE) + return 0; + while (sz++ < qSz) + *sigBinPtr++ = 0; + if (wolfSSL_BN_bn2bin(sig->s, sigBinPtr) == -1) + return 0; + + if ((dsa_do_verify(digest, digest_len, sigBin, dsa, &dsacheck) + != 1) || dsacheck != 1) { + return 0; } - /* Dispose of any allocated PEM buffer. */ - XFREE(pem, NULL, DYNAMIC_TYPE_KEY); - return ret; + return 1; } -#endif /* !NO_BIO */ +#endif -#ifndef NO_FILESYSTEM -/* Writes PEM encoding of an RSA private key to a file pointer. - * - * TODO: Support use of the password callback and callback context. - * - * @param [in] fp File pointer to write to. - * @param [in] rsa RSA key to write. - * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. - * @param [in] passwd Password string when PEM encrypted. May be NULL. - * @param [in] passwdSz Length of password string when PEM encrypted. - * @param [in] cb Password callback to use when PEM encrypted. Unused. - * @param [in] arg NUL terminated string for passphrase when PEM - * encrypted. Unused. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_PEM_write_RSAPrivateKey(XFILE fp, WOLFSSL_RSA *rsa, - const WOLFSSL_EVP_CIPHER *cipher, unsigned char *passwd, int passwdSz, - wc_pem_password_cb *cb, void *arg) +int wolfSSL_i2d_DSAparams(const WOLFSSL_DSA* dsa, + unsigned char** out) { - int ret = 1; - byte* pem = NULL; - int pLen = 0; - - (void)cb; - (void)arg; + int ret = 0; + word32 derLen = 0; + int preAllocated = 1; + DsaKey* key = NULL; - WOLFSSL_ENTER("wolfSSL_PEM_write_RSAPrivateKey"); + WOLFSSL_ENTER("wolfSSL_i2d_DSAparams"); - /* Validate parameters. */ - if ((fp == XBADFILE) || (rsa == NULL) || (rsa->internal == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = 0; + if (dsa == NULL || dsa->internal == NULL || out == NULL) { + ret = BAD_FUNC_ARG; } - if (ret == 1) { - /* Write PEM to buffer that is allocated in the call. */ - ret = wolfSSL_PEM_write_mem_RSAPrivateKey(rsa, cipher, passwd, passwdSz, - &pem, &pLen); - if (ret != 1) { - WOLFSSL_ERROR_MSG("wolfSSL_PEM_write_mem_RSAPrivateKey failed"); + if (ret == 0) { + key = (DsaKey*)dsa->internal; + ret = wc_DsaKeyToParamsDer_ex(key, NULL, &derLen); + if (ret == WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { + ret = 0; } } - /* Write PEM to file pointer. */ - if ((ret == 1) && ((int)XFWRITE(pem, 1, (size_t)pLen, fp) != pLen)) { - WOLFSSL_ERROR_MSG("RSA private key file write failed"); - ret = 0; - } - - /* Dispose of any allocated PEM buffer. */ - XFREE(pem, NULL, DYNAMIC_TYPE_KEY); - return ret; -} -#endif /* NO_FILESYSTEM */ -#endif /* WOLFSSL_KEY_GEN && WOLFSSL_PEM_TO_DER */ - -#ifndef NO_BIO -/* Create an RSA private key by reading the PEM encoded data from the BIO. - * - * @param [in] bio BIO object to read from. - * @param [out] out RSA key created. - * @param [in] cb Password callback when PEM encrypted. - * @param [in] pass NUL terminated string for passphrase when PEM encrypted. - * @return RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA* wolfSSL_PEM_read_bio_RSAPrivateKey(WOLFSSL_BIO* bio, - WOLFSSL_RSA** out, wc_pem_password_cb* cb, void* pass) -{ - WOLFSSL_RSA* rsa = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_RSAPrivateKey"); - - if ((bio != NULL) && (pem_read_bio_key(bio, cb, pass, PRIVATEKEY_TYPE, - &keyFormat, &der) >= 0)) { - rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, - WOLFSSL_RSA_LOAD_PRIVATE); - if (rsa == NULL) { - WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); + if (ret == 0 && *out == NULL) { + /* If we're allocating out for the caller, we don't increment out just + past the end of the DER buffer. If out is already allocated, we do. + (OpenSSL convention) */ + preAllocated = 0; + *out = (unsigned char*)XMALLOC(derLen, key->heap, DYNAMIC_TYPE_OPENSSL); + if (*out == NULL) { + ret = MEMORY_E; } } - - FreeDer(&der); - if ((out != NULL) && (rsa != NULL)) { - *out = rsa; + if (ret == 0) { + ret = wc_DsaKeyToParamsDer_ex(key, *out, &derLen); } - return rsa; -} -#endif /* !NO_BIO */ - -/* Create an RSA private key by reading the PEM encoded data from the file - * pointer. - * - * @param [in] fp File pointer to read from. - * @param [out] out RSA key created. - * @param [in] cb Password callback when PEM encrypted. - * @param [in] pass NUL terminated string for passphrase when PEM encrypted. - * @return RSA key on success. - * @return NULL on failure. - */ -#ifndef NO_FILESYSTEM -WOLFSSL_RSA* wolfSSL_PEM_read_RSAPrivateKey(XFILE fp, WOLFSSL_RSA** out, - wc_pem_password_cb* cb, void* pass) -{ - WOLFSSL_RSA* rsa = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_read_RSAPrivateKey"); - - if ((fp != XBADFILE) && (pem_read_file_key(fp, cb, pass, PRIVATEKEY_TYPE, - &keyFormat, &der) >= 0)) { - rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, - WOLFSSL_RSA_LOAD_PRIVATE); - if (rsa == NULL) { - WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); - } + if (ret >= 0 && preAllocated == 1) { + *out += derLen; } - FreeDer(&der); - if ((out != NULL) && (rsa != NULL)) { - *out = rsa; + if (ret < 0 && preAllocated == 0) { + XFREE(*out, key ? key->heap : NULL, DYNAMIC_TYPE_OPENSSL); } - return rsa; -} -#endif /* !NO_FILESYSTEM */ -/* - * RSA print APIs - */ + WOLFSSL_LEAVE("wolfSSL_i2d_DSAparams", ret); -#if defined(XFPRINTF) && !defined(NO_FILESYSTEM) && \ - !defined(NO_STDIO_FILESYSTEM) -/* Print an RSA key to a file pointer. - * - * @param [in] fp File pointer to write to. - * @param [in] rsa RSA key to write. - * @param [in] indent Number of spaces to prepend to each line. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_print_fp(XFILE fp, WOLFSSL_RSA* rsa, int indent) + return ret; +} + +WOLFSSL_DSA* wolfSSL_d2i_DSAparams(WOLFSSL_DSA** dsa, const unsigned char** der, + long derLen) { - int ret = 1; + WOLFSSL_DSA* ret = NULL; + int err = 0; + word32 idx = 0; + int asnLen; + DsaKey* internalKey = NULL; - WOLFSSL_ENTER("wolfSSL_RSA_print_fp"); + WOLFSSL_ENTER("wolfSSL_d2i_DSAparams"); - /* Validate parameters. */ - if ((fp == XBADFILE) || (rsa == NULL)) { - ret = 0; + if (der == NULL || *der == NULL || derLen <= 0) { + err = 1; } - - /* Set the external data from the wolfCrypt RSA key if not done. */ - if ((ret == 1) && (!rsa->exSet)) { - ret = SetRsaExternal(rsa); + if (err == 0) { + ret = wolfSSL_DSA_new(); + err = ret == NULL; } - - /* Get the key size from modulus if available. */ - if ((ret == 1) && (rsa->n != NULL)) { - int keySize = wolfSSL_BN_num_bits(rsa->n); - if (keySize == 0) { - ret = 0; - } - else { - if (XFPRINTF(fp, "%*s", indent, "") < 0) - ret = 0; - else if (XFPRINTF(fp, "RSA Private-Key: (%d bit, 2 primes)\n", - keySize) < 0) - ret = 0; - } + if (err == 0) { + err = GetSequence(*der, &idx, &asnLen, (word32)derLen) <= 0; } - /* Print out any components available. */ - if ((ret == 1) && (rsa->n != NULL)) { - ret = pk_bn_field_print_fp(fp, indent, "modulus", rsa->n); + if (err == 0) { + internalKey = (DsaKey*)ret->internal; + err = GetInt(&internalKey->p, *der, &idx, (word32)derLen) != 0; } - if ((ret == 1) && (rsa->d != NULL)) { - ret = pk_bn_field_print_fp(fp, indent, "privateExponent", rsa->d); + if (err == 0) { + err = GetInt(&internalKey->q, *der, &idx, (word32)derLen) != 0; } - if ((ret == 1) && (rsa->p != NULL)) { - ret = pk_bn_field_print_fp(fp, indent, "prime1", rsa->p); + if (err == 0) { + err = GetInt(&internalKey->g, *der, &idx, (word32)derLen) != 0; } - if ((ret == 1) && (rsa->q != NULL)) { - ret = pk_bn_field_print_fp(fp, indent, "prime2", rsa->q); + if (err == 0) { + err = wolfssl_bn_set_value(&ret->p, &internalKey->p) + != 1; } - if ((ret == 1) && (rsa->dmp1 != NULL)) { - ret = pk_bn_field_print_fp(fp, indent, "exponent1", rsa->dmp1); + if (err == 0) { + err = wolfssl_bn_set_value(&ret->q, &internalKey->q) + != 1; } - if ((ret == 1) && (rsa->dmq1 != NULL)) { - ret = pk_bn_field_print_fp(fp, indent, "exponent2", rsa->dmq1); + if (err == 0) { + err = wolfssl_bn_set_value(&ret->g, &internalKey->g) + != 1; } - if ((ret == 1) && (rsa->iqmp != NULL)) { - ret = pk_bn_field_print_fp(fp, indent, "coefficient", rsa->iqmp); + if (err == 0 && dsa != NULL) { + *dsa = ret; } - WOLFSSL_LEAVE("wolfSSL_RSA_print_fp", ret); + if (err != 0 && ret != NULL) { + wolfSSL_DSA_free(ret); + ret = NULL; + } return ret; } -#endif /* XFPRINTF && !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM */ -#if defined(XSNPRINTF) && !defined(NO_BIO) -/* snprintf() must be available */ - -/* Maximum size of a header line. */ -#define RSA_PRINT_MAX_HEADER_LINE PRINT_NUM_MAX_INDENT +#if defined(WOLFSSL_KEY_GEN) +#ifndef NO_BIO -/* Writes the human readable form of RSA to a BIO. - * - * @param [in] bio BIO object to write to. - * @param [in] rsa RSA key to write. - * @param [in] indent Number of spaces before each line. - * @return 1 on success. - * @return 0 on failure. +/* Takes a DSA Privatekey and writes it out to a WOLFSSL_BIO + * Returns 1 or 0 */ -int wolfSSL_RSA_print(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa, int indent) -{ - int ret = 1; - int sz = 0; - RsaKey* key = NULL; - char line[RSA_PRINT_MAX_HEADER_LINE]; - int i = 0; - mp_int *num = NULL; - /* Header strings. */ - const char *name[] = { - "Modulus:", "Exponent:", "PrivateExponent:", "Prime1:", "Prime2:", - "Exponent1:", "Exponent2:", "Coefficient:" - }; +int wolfSSL_PEM_write_bio_DSAPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_DSA* dsa, + const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, + wc_pem_password_cb* cb, void* arg) +{ + int ret = 1; + byte *pem = NULL; + int pLen = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_DSAPrivateKey"); - WOLFSSL_ENTER("wolfSSL_RSA_print"); + (void)cb; + (void)arg; /* Validate parameters. */ - if ((bio == NULL) || (rsa == NULL) || (indent > PRINT_NUM_MAX_INDENT)) { - ret = WOLFSSL_FATAL_ERROR; + if ((bio == NULL) || (dsa == NULL)) { + WOLFSSL_MSG("Bad Function Arguments"); + ret = 0; } if (ret == 1) { - key = (RsaKey*)rsa->internal; - - /* Get size in bits of key for printing out. */ - sz = wolfSSL_RSA_bits(rsa); - if (sz <= 0) { - WOLFSSL_ERROR_MSG("Error getting RSA key size"); - ret = 0; - } - } - if (ret == 1) { - /* Print any indent spaces. */ - ret = wolfssl_print_indent(bio, line, sizeof(line), indent); - } - if (ret == 1) { - /* Print header line. */ - int len = XSNPRINTF(line, sizeof(line), "\nRSA %s: (%d bit)\n", - (!mp_iszero(&key->d)) ? "Private-Key" : "Public-Key", sz); - if (len >= (int)sizeof(line)) { - WOLFSSL_ERROR_MSG("Buffer overflow while formatting key preamble"); - ret = 0; - } - else { - if (wolfSSL_BIO_write(bio, line, len) <= 0) { - ret = 0; - } - } + ret = wolfSSL_PEM_write_mem_DSAPrivateKey(dsa, cipher, passwd, passwdSz, + &pem, &pLen); } - for (i = 0; (ret == 1) && (i < RSA_INTS); i++) { - /* Get mp_int for index. */ - switch (i) { - case 0: - /* Print out modulus */ - num = &key->n; - break; - case 1: - num = &key->e; - break; - case 2: - num = &key->d; - break; - case 3: - num = &key->p; - break; - case 4: - num = &key->q; - break; - case 5: - num = &key->dP; - break; - case 6: - num = &key->dQ; - break; - case 7: - num = &key->u; - break; - default: - WOLFSSL_ERROR_MSG("Bad index value"); - } - - if (i == 1) { - /* Print exponent as a 32-bit value. */ - ret = wolfssl_print_value(bio, num, name[i], indent); - } - else if (!mp_iszero(num)) { - /* Print name and MP integer. */ - ret = wolfssl_print_number(bio, num, name[i], indent); - } + /* Write PEM to BIO. */ + if ((ret == 1) && (wolfSSL_BIO_write(bio, pem, pLen) != pLen)) { + WOLFSSL_ERROR_MSG("DSA private key BIO write failed"); + ret = 0; } + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); return ret; } -#endif /* XSNPRINTF && !NO_BIO */ -#endif /* OPENSSL_EXTRA */ - -/* - * RSA get/set/test APIs - */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -/* Set RSA key data (external) from wolfCrypt RSA key (internal). +#ifndef HAVE_SELFTEST +/* Encode the DSA public key as DER. * - * @param [in, out] rsa RSA key. - * @return 1 on success. - * @return 0 on failure. + * @param [in] key DSA key to encode. + * @param [out] der Pointer through which buffer is returned. + * @param [in] heap Heap hint. + * @return Size of encoding on success. + * @return 0 on error. */ -int SetRsaExternal(WOLFSSL_RSA* rsa) +static int wolfssl_dsa_key_to_pubkey_der(WOLFSSL_DSA* key, unsigned char** der, + void* heap) { - int ret = 1; - - WOLFSSL_ENTER("SetRsaExternal"); + int sz; + unsigned char* buf = NULL; - /* Validate parameters. */ - if ((rsa == NULL) || (rsa->internal == NULL)) { - WOLFSSL_ERROR_MSG("rsa key NULL error"); - ret = WOLFSSL_FATAL_ERROR; + /* Use maximum encoded size to allocate. */ + sz = MAX_DSA_PUBKEY_SZ; + /* Allocate memory to hold encoding. */ + buf = (byte*)XMALLOC((size_t)sz, heap, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + WOLFSSL_MSG("malloc failed"); + sz = 0; } - - if (ret == 1) { - RsaKey* key = (RsaKey*)rsa->internal; - - /* Copy modulus. */ - ret = wolfssl_bn_set_value(&rsa->n, &key->n); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa n error"); - } - if (ret == 1) { - /* Copy public exponent. */ - ret = wolfssl_bn_set_value(&rsa->e, &key->e); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa e error"); - } - } - - if (key->type == RSA_PRIVATE) { - #ifndef WOLFSSL_RSA_PUBLIC_ONLY - if (ret == 1) { - /* Copy private exponent. */ - ret = wolfssl_bn_set_value(&rsa->d, &key->d); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa d error"); - } - } - if (ret == 1) { - /* Copy first prime. */ - ret = wolfssl_bn_set_value(&rsa->p, &key->p); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa p error"); - } - } - if (ret == 1) { - /* Copy second prime. */ - ret = wolfssl_bn_set_value(&rsa->q, &key->q); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa q error"); - } - } - #if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || \ - !defined(RSA_LOW_MEM) - if (ret == 1) { - /* Copy d mod p-1. */ - ret = wolfssl_bn_set_value(&rsa->dmp1, &key->dP); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa dP error"); - } - } - if (ret == 1) { - /* Copy d mod q-1. */ - ret = wolfssl_bn_set_value(&rsa->dmq1, &key->dQ); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa dq error"); - } - } - if (ret == 1) { - /* Copy 1/q mod p. */ - ret = wolfssl_bn_set_value(&rsa->iqmp, &key->u); - if (ret != 1) { - WOLFSSL_ERROR_MSG("rsa u error"); - } - } - #endif - #else - WOLFSSL_ERROR_MSG("rsa private key not compiled in "); - ret = 0; - #endif /* !WOLFSSL_RSA_PUBLIC_ONLY */ + if (sz > 0) { + /* Encode public key to DER using wolfSSL. */ + sz = wc_DsaKeyToPublicDer((DsaKey*)key->internal, buf, (word32)sz); + if (sz < 0) { + WOLFSSL_MSG("wc_DsaKeyToPublicDer failed"); + sz = 0; } } - if (ret == 1) { - /* External values set. */ - rsa->exSet = 1; + + /* Return buffer on success. */ + if (sz > 0) { + *der = buf; } else { - /* Return 0 on failure. */ - ret = 0; + /* Dispose of any dynamically allocated data not returned. */ + XFREE(buf, heap, DYNAMIC_TYPE_TMP_BUFFER); } - return ret; + return sz; } -#endif /* (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) */ - -#ifdef OPENSSL_EXTRA -/* Set wolfCrypt RSA key data (internal) from RSA key (external). - * - * @param [in, out] rsa RSA key. - * @return 1 on success. - * @return 0 on failure. +/* Takes a DSA public key and writes it out to a WOLFSSL_BIO + * Returns 1 or 0 */ -int SetRsaInternal(WOLFSSL_RSA* rsa) +int wolfSSL_PEM_write_bio_DSA_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_DSA* dsa) { int ret = 1; + unsigned char* derBuf = NULL; + int derSz = 0; - WOLFSSL_ENTER("SetRsaInternal"); + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_DSA_PUBKEY"); /* Validate parameters. */ - if ((rsa == NULL) || (rsa->internal == NULL)) { - WOLFSSL_ERROR_MSG("rsa key NULL error"); - ret = WOLFSSL_FATAL_ERROR; + if ((bio == NULL) || (dsa == NULL)) { + WOLFSSL_MSG("Bad Function Arguments"); + return 0; } - if (ret == 1) { - RsaKey* key = (RsaKey*)rsa->internal; - - /* Copy down modulus if available. */ - if ((rsa->n != NULL) && (wolfssl_bn_get_value(rsa->n, &key->n) != 1)) { - WOLFSSL_ERROR_MSG("rsa n key error"); - ret = WOLFSSL_FATAL_ERROR; - } - - /* Copy down public exponent if available. */ - if ((ret == 1) && (rsa->e != NULL) && - (wolfssl_bn_get_value(rsa->e, &key->e) != 1)) { - WOLFSSL_ERROR_MSG("rsa e key error"); - ret = WOLFSSL_FATAL_ERROR; - } - - /* Enough numbers for public key */ - key->type = RSA_PUBLIC; - -#ifndef WOLFSSL_RSA_PUBLIC_ONLY - /* Copy down private exponent if available. */ - if ((ret == 1) && (rsa->d != NULL)) { - if (wolfssl_bn_get_value(rsa->d, &key->d) != 1) { - WOLFSSL_ERROR_MSG("rsa d key error"); - ret = WOLFSSL_FATAL_ERROR; - } - else { - /* Enough numbers for private key */ - key->type = RSA_PRIVATE; - } - } - - /* Copy down first prime if available. */ - if ((ret == 1) && (rsa->p != NULL) && - (wolfssl_bn_get_value(rsa->p, &key->p) != 1)) { - WOLFSSL_ERROR_MSG("rsa p key error"); - ret = WOLFSSL_FATAL_ERROR; - } - - /* Copy down second prime if available. */ - if ((ret == 1) && (rsa->q != NULL) && - (wolfssl_bn_get_value(rsa->q, &key->q) != 1)) { - WOLFSSL_ERROR_MSG("rsa q key error"); - ret = WOLFSSL_FATAL_ERROR; - } - -#if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || !defined(RSA_LOW_MEM) - /* Copy down d mod p-1 if available. */ - if ((ret == 1) && (rsa->dmp1 != NULL) && - (wolfssl_bn_get_value(rsa->dmp1, &key->dP) != 1)) { - WOLFSSL_ERROR_MSG("rsa dP key error"); - ret = WOLFSSL_FATAL_ERROR; - } - - /* Copy down d mod q-1 if available. */ - if ((ret == 1) && (rsa->dmq1 != NULL) && - (wolfssl_bn_get_value(rsa->dmq1, &key->dQ) != 1)) { - WOLFSSL_ERROR_MSG("rsa dQ key error"); - ret = WOLFSSL_FATAL_ERROR; - } - - /* Copy down 1/q mod p if available. */ - if ((ret == 1) && (rsa->iqmp != NULL) && - (wolfssl_bn_get_value(rsa->iqmp, &key->u) != 1)) { - WOLFSSL_ERROR_MSG("rsa u key error"); - ret = WOLFSSL_FATAL_ERROR; - } -#endif -#endif + /* Encode public key in EC key as DER. */ + derSz = wolfssl_dsa_key_to_pubkey_der(dsa, &derBuf, bio->heap); + if (derSz == 0) { + ret = 0; + } - if (ret == 1) { - /* All available numbers have been set down. */ - rsa->inSet = 1; - } + /* Write out to BIO the PEM encoding of the DSA public key. */ + if ((ret == 1) && (der_write_to_bio_as_pem(derBuf, derSz, bio, + PUBLICKEY_TYPE) != 1)) { + ret = 0; } + /* Dispose of any dynamically allocated data. */ + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; } +#endif /* HAVE_SELFTEST */ +#endif /* !NO_BIO */ -/* Set the RSA method into object. - * - * @param [in, out] rsa RSA key. - * @param [in] meth RSA method. - * @return 1 always. +/* return code compliant with OpenSSL : + * 1 if success, 0 if error */ -int wolfSSL_RSA_set_method(WOLFSSL_RSA *rsa, WOLFSSL_RSA_METHOD *meth) +int wolfSSL_PEM_write_mem_DSAPrivateKey(WOLFSSL_DSA* dsa, + const WOLFSSL_EVP_CIPHER* cipher, + unsigned char* passwd, int passwdSz, + unsigned char **pem, int *pLen) { - if (rsa != NULL) { - /* Store the method into object. */ - rsa->meth = meth; - /* Copy over flags. */ - rsa->flags = meth->flags; - } - /* OpenSSL always assumes it will work. */ - return 1; -} +#if (defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)) && \ + !defined(NO_MD5) + byte *derBuf, *tmp, *cipherInfo = NULL; + int der_max_len = 0, derSz = 0; + const int type = DSA_PRIVATEKEY_TYPE; + const char* header = NULL; + const char* footer = NULL; -/* Get the RSA method from the RSA object. - * - * @param [in] rsa RSA key. - * @return RSA method on success. - * @return NULL when RSA is NULL or no method set. - */ -const WOLFSSL_RSA_METHOD* wolfSSL_RSA_get_method(const WOLFSSL_RSA *rsa) -{ - return (rsa != NULL) ? rsa->meth : NULL; -} + WOLFSSL_MSG("wolfSSL_PEM_write_mem_DSAPrivateKey"); -/* Get the size in bytes of the RSA key. - * - * Return compliant with OpenSSL - * - * @param [in] rsa RSA key. - * @return RSA modulus size in bytes. - * @return 0 on error. - */ -int wolfSSL_RSA_size(const WOLFSSL_RSA* rsa) -{ - int ret = 0; + if (pem == NULL || pLen == NULL || dsa == NULL || dsa->internal == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return 0; + } + + if (wc_PemGetHeaderFooter(type, &header, &footer) != 0) + return 0; - WOLFSSL_ENTER("wolfSSL_RSA_size"); + if (dsa->inSet == 0) { + WOLFSSL_MSG("No DSA internal set, do it"); - if (rsa != NULL) { - /* Make sure we have set the RSA values into wolfCrypt RSA key. */ - if (rsa->inSet || (SetRsaInternal((WOLFSSL_RSA*)rsa) == 1)) { - /* Get key size in bytes using wolfCrypt RSA key. */ - ret = wc_RsaEncryptSize((RsaKey*)rsa->internal); + if (SetDsaInternal(dsa) != 1) { + WOLFSSL_MSG("SetDsaInternal failed"); + return 0; } } - return ret; -} - -/* Get the size in bits of the RSA key. - * - * Uses external modulus field. - * - * @param [in] rsa RSA key. - * @return RSA modulus size in bits. - * @return 0 on error. - */ -int wolfSSL_RSA_bits(const WOLFSSL_RSA* rsa) -{ - int ret = 0; + der_max_len = MAX_DSA_PRIVKEY_SZ; - WOLFSSL_ENTER("wolfSSL_RSA_bits"); + derBuf = (byte*)XMALLOC((size_t)der_max_len, NULL, DYNAMIC_TYPE_DER); + if (derBuf == NULL) { + WOLFSSL_MSG("malloc failed"); + return 0; + } - if (rsa != NULL) { - /* Get number of bits in external modulus. */ - ret = wolfSSL_BN_num_bits(rsa->n); + /* Key to DER */ + derSz = wc_DsaKeyToDer((DsaKey*)dsa->internal, derBuf, (word32)der_max_len); + if (derSz < 0) { + WOLFSSL_MSG("wc_DsaKeyToDer failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + return 0; } - return ret; -} - -/* Get the BN objects that are the Chinese-Remainder Theorem (CRT) parameters. - * - * Only for those that are not NULL parameters. - * - * @param [in] rsa RSA key. - * @param [out] dmp1 BN that is d mod (p - 1). May be NULL. - * @param [out] dmq1 BN that is d mod (q - 1). May be NULL. - * @param [out] iqmp BN that is 1/q mod p. May be NULL. - */ -void wolfSSL_RSA_get0_crt_params(const WOLFSSL_RSA *rsa, - const WOLFSSL_BIGNUM **dmp1, const WOLFSSL_BIGNUM **dmq1, - const WOLFSSL_BIGNUM **iqmp) -{ - WOLFSSL_ENTER("wolfSSL_RSA_get0_crt_params"); + /* encrypt DER buffer if required */ + if (passwd != NULL && passwdSz > 0 && cipher != NULL) { + int ret; - /* For any parameters not NULL, return the BN from the key or NULL. */ - if (dmp1 != NULL) { - *dmp1 = (rsa != NULL) ? rsa->dmp1 : NULL; - } - if (dmq1 != NULL) { - *dmq1 = (rsa != NULL) ? rsa->dmq1 : NULL; + ret = EncryptDerKey(derBuf, &derSz, cipher, passwd, passwdSz, + &cipherInfo, der_max_len, WC_MD5); + if (ret != 1) { + WOLFSSL_MSG("EncryptDerKey failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + return ret; + } + /* tmp buffer with a max size */ + *pLen = (derSz * 2) + (int)XSTRLEN(header) + 1 + + (int)XSTRLEN(footer) + 1 + HEADER_ENCRYPTED_KEY_SIZE; } - if (iqmp != NULL) { - *iqmp = (rsa != NULL) ? rsa->iqmp : NULL; + else { /* tmp buffer with a max size */ + *pLen = (derSz * 2) + (int)XSTRLEN(header) + 1 + + (int)XSTRLEN(footer) + 1; } -} -/* Set the BN objects that are the Chinese-Remainder Theorem (CRT) parameters - * into RSA key. - * - * If CRT parameter is NULL then there must be one in the RSA key already. - * - * @param [in, out] rsa RSA key. - * @param [in] dmp1 BN that is d mod (p - 1). May be NULL. - * @param [in] dmq1 BN that is d mod (q - 1). May be NULL. - * @param [in] iqmp BN that is 1/q mod p. May be NULL. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_set0_crt_params(WOLFSSL_RSA *rsa, WOLFSSL_BIGNUM *dmp1, - WOLFSSL_BIGNUM *dmq1, WOLFSSL_BIGNUM *iqmp) -{ - int ret = 1; + tmp = (byte*)XMALLOC((size_t)*pLen, NULL, DYNAMIC_TYPE_PEM); + if (tmp == NULL) { + WOLFSSL_MSG("malloc failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); + return 0; + } - WOLFSSL_ENTER("wolfSSL_RSA_set0_crt_params"); + /* DER to PEM */ + *pLen = wc_DerToPemEx(derBuf, (word32)derSz, tmp, (word32)*pLen, cipherInfo, + type); + if (*pLen <= 0) { + WOLFSSL_MSG("wc_DerToPemEx failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); + XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); + return 0; + } + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); - /* If a param is NULL in rsa then it must be non-NULL in the - * corresponding user input. */ - if ((rsa == NULL) || ((rsa->dmp1 == NULL) && (dmp1 == NULL)) || - ((rsa->dmq1 == NULL) && (dmq1 == NULL)) || - ((rsa->iqmp == NULL) && (iqmp == NULL))) { - WOLFSSL_ERROR_MSG("Bad parameters"); - ret = 0; + *pem = (byte*)XMALLOC((size_t)((*pLen)+1), NULL, DYNAMIC_TYPE_KEY); + if (*pem == NULL) { + WOLFSSL_MSG("malloc failed"); + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); + return 0; } - if (ret == 1) { - /* Replace the BNs. */ - if (dmp1 != NULL) { - wolfSSL_BN_clear_free(rsa->dmp1); - rsa->dmp1 = dmp1; - } - if (dmq1 != NULL) { - wolfSSL_BN_clear_free(rsa->dmq1); - rsa->dmq1 = dmq1; - } - if (iqmp != NULL) { - wolfSSL_BN_clear_free(rsa->iqmp); - rsa->iqmp = iqmp; - } + XMEMSET(*pem, 0, (size_t)((*pLen)+1)); - /* Set the values into the wolfCrypt RSA key. */ - if (SetRsaInternal(rsa) != 1) { - if (dmp1 != NULL) { - rsa->dmp1 = NULL; - } - if (dmq1 != NULL) { - rsa->dmq1 = NULL; - } - if (iqmp != NULL) { - rsa->iqmp = NULL; - } - ret = 0; - } + if (XMEMCPY(*pem, tmp, (size_t)*pLen) == NULL) { + WOLFSSL_MSG("XMEMCPY failed"); + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); + return 0; } + XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); - return ret; + return 1; +#else + (void)dsa; + (void)cipher; + (void)passwd; + (void)passwdSz; + (void)pem; + (void)pLen; + return 0; +#endif /* (WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM) && !NO_MD5 */ } -/* Get the BN objects that are the factors of the RSA key (two primes p and q). - * - * @param [in] rsa RSA key. - * @param [out] p BN that is first prime. May be NULL. - * @param [out] q BN that is second prime. May be NULL. +#ifndef NO_FILESYSTEM +/* return code compliant with OpenSSL : + * 1 if success, 0 if error */ -void wolfSSL_RSA_get0_factors(const WOLFSSL_RSA *rsa, const WOLFSSL_BIGNUM **p, - const WOLFSSL_BIGNUM **q) +int wolfSSL_PEM_write_DSAPrivateKey(XFILE fp, WOLFSSL_DSA *dsa, + const WOLFSSL_EVP_CIPHER *enc, + unsigned char *kstr, int klen, + wc_pem_password_cb *cb, void *u) { - WOLFSSL_ENTER("wolfSSL_RSA_get0_factors"); + byte *pem; + int pLen, ret; - /* For any primes not NULL, return the BN from the key or NULL. */ - if (p != NULL) { - *p = (rsa != NULL) ? rsa->p : NULL; - } - if (q != NULL) { - *q = (rsa != NULL) ? rsa->q : NULL; - } -} + (void)cb; + (void)u; -/* Set the BN objects that are the factors of the RSA key (two primes p and q). - * - * If factor parameter is NULL then there must be one in the RSA key already. - * - * @param [in, out] rsa RSA key. - * @param [in] p BN that is first prime. May be NULL. - * @param [in] q BN that is second prime. May be NULL. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_set0_factors(WOLFSSL_RSA *rsa, WOLFSSL_BIGNUM *p, - WOLFSSL_BIGNUM *q) -{ - int ret = 1; + WOLFSSL_MSG("wolfSSL_PEM_write_DSAPrivateKey"); - WOLFSSL_ENTER("wolfSSL_RSA_set0_factors"); + if (fp == XBADFILE || dsa == NULL || dsa->internal == NULL) { + WOLFSSL_MSG("Bad function arguments"); + return 0; + } - /* If a param is null in r then it must be non-null in the - * corresponding user input. */ - if (rsa == NULL || ((rsa->p == NULL) && (p == NULL)) || - ((rsa->q == NULL) && (q == NULL))) { - WOLFSSL_ERROR_MSG("Bad parameters"); - ret = 0; + ret = wolfSSL_PEM_write_mem_DSAPrivateKey(dsa, enc, kstr, klen, &pem, + &pLen); + if (ret != 1) { + WOLFSSL_MSG("wolfSSL_PEM_write_mem_DSAPrivateKey failed"); + return 0; } - if (ret == 1) { - /* Replace the BNs. */ - if (p != NULL) { - wolfSSL_BN_clear_free(rsa->p); - rsa->p = p; - } - if (q != NULL) { - wolfSSL_BN_clear_free(rsa->q); - rsa->q = q; - } - /* Set the values into the wolfCrypt RSA key. */ - if (SetRsaInternal(rsa) != 1) { - if (p != NULL) { - rsa->p = NULL; - } - if (q != NULL) { - rsa->q = NULL; - } - ret = 0; - } + ret = (int)XFWRITE(pem, (size_t)pLen, 1, fp); + if (ret != 1) { + WOLFSSL_MSG("DSA private key file write failed"); + return 0; } - return ret; + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + return 1; } -/* Get the BN objects for the basic key numbers of the RSA key (modulus, public - * exponent, private exponent). - * - * @param [in] rsa RSA key. - * @param [out] n BN that is the modulus. May be NULL. - * @param [out] e BN that is the public exponent. May be NULL. - * @param [out] d BN that is the private exponent. May be NULL. +#endif /* NO_FILESYSTEM */ +#endif /* defined(WOLFSSL_KEY_GEN) */ + +#ifndef NO_FILESYSTEM +/* return code compliant with OpenSSL : + * 1 if success, 0 if error */ -void wolfSSL_RSA_get0_key(const WOLFSSL_RSA *rsa, const WOLFSSL_BIGNUM **n, - const WOLFSSL_BIGNUM **e, const WOLFSSL_BIGNUM **d) +#ifndef NO_WOLFSSL_STUB +int wolfSSL_PEM_write_DSA_PUBKEY(XFILE fp, WOLFSSL_DSA *x) { - WOLFSSL_ENTER("wolfSSL_RSA_get0_key"); + (void)fp; + (void)x; + WOLFSSL_STUB("PEM_write_DSA_PUBKEY"); + WOLFSSL_MSG("wolfSSL_PEM_write_DSA_PUBKEY not implemented"); - /* For any parameters not NULL, return the BN from the key or NULL. */ - if (n != NULL) { - *n = (rsa != NULL) ? rsa->n : NULL; - } - if (e != NULL) { - *e = (rsa != NULL) ? rsa->e : NULL; - } - if (d != NULL) { - *d = (rsa != NULL) ? rsa->d : NULL; - } + return 0; } +#endif +#endif /* NO_FILESYSTEM */ + +#ifndef NO_BIO -/* Set the BN objects for the basic key numbers into the RSA key (modulus, - * public exponent, private exponent). +#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) && (!defined(NO_CERTS) && \ + !defined(NO_FILESYSTEM) && defined(WOLFSSL_KEY_GEN)) +/* Uses the same format of input as wolfSSL_PEM_read_bio_PrivateKey but expects + * the results to be an DSA key. * - * If BN parameter is NULL then there must be one in the RSA key already. + * bio structure to read DSA private key from + * dsa if not null is then set to the result + * cb password callback for reading PEM + * pass password string * - * @param [in,out] rsa RSA key. - * @param [in] n BN that is the modulus. May be NULL. - * @param [in] e BN that is the public exponent. May be NULL. - * @param [in] d BN that is the private exponent. May be NULL. - * @return 1 on success. - * @return 0 on failure. + * returns a pointer to a new WOLFSSL_DSA structure on success and NULL on fail */ -int wolfSSL_RSA_set0_key(WOLFSSL_RSA *rsa, WOLFSSL_BIGNUM *n, WOLFSSL_BIGNUM *e, - WOLFSSL_BIGNUM *d) +WOLFSSL_DSA* wolfSSL_PEM_read_bio_DSAPrivateKey(WOLFSSL_BIO* bio, + WOLFSSL_DSA** dsa, + wc_pem_password_cb* cb, + void* pass) { - int ret = 1; + WOLFSSL_EVP_PKEY* pkey = NULL; + WOLFSSL_DSA* local; + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_DSAPrivateKey"); - /* If the fields n and e in r are NULL, the corresponding input - * parameters MUST be non-NULL for n and e. d may be - * left NULL (in case only the public key is used). - */ - if ((rsa == NULL) || ((rsa->n == NULL) && (n == NULL)) || - ((rsa->e == NULL) && (e == NULL))) { - ret = 0; - } - if (ret == 1) { - /* Replace the BNs. */ - if (n != NULL) { - wolfSSL_BN_free(rsa->n); - rsa->n = n; - } - if (e != NULL) { - wolfSSL_BN_free(rsa->e); - rsa->e = e; - } - if (d != NULL) { - /* Private key is sensitive data. */ - wolfSSL_BN_clear_free(rsa->d); - rsa->d = d; - } - /* Set the values into the wolfCrypt RSA key. */ - if (SetRsaInternal(rsa) != 1) { - if (n != NULL) { - rsa->n = NULL; - } - if (e != NULL) { - rsa->e = NULL; - } - if (d != NULL) { - rsa->d = NULL; - } - ret = 0; - } + pkey = wolfSSL_PEM_read_bio_PrivateKey(bio, NULL, cb, pass); + if (pkey == NULL) { + WOLFSSL_MSG("Error in PEM_read_bio_PrivateKey"); + return NULL; + } + /* Since the WOLFSSL_DSA structure is being taken from WOLFSSL_EVP_PKEY the + * flag indicating that the WOLFSSL_DSA structure is owned should be FALSE + * to avoid having it free'd */ + pkey->ownDsa = 0; + local = pkey->dsa; + if (dsa != NULL) { + *dsa = local; } - - return ret; + wolfSSL_EVP_PKEY_free(pkey); + return local; } -/* Get the flags of the RSA key. - * - * @param [in] rsa RSA key. - * @return Flags set in RSA key on success. - * @return 0 when RSA key is NULL. +/* Reads an DSA public key from a WOLFSSL_BIO into a WOLFSSL_DSA. + * Returns 1 or 0 */ -int wolfSSL_RSA_flags(const WOLFSSL_RSA *rsa) +WOLFSSL_DSA *wolfSSL_PEM_read_bio_DSA_PUBKEY(WOLFSSL_BIO* bio,WOLFSSL_DSA** dsa, + wc_pem_password_cb* cb, void* pass) { - int ret = 0; + WOLFSSL_EVP_PKEY* pkey; + WOLFSSL_DSA* local; + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_DSA_PUBKEY"); - /* Get flags from the RSA key if available. */ - if (rsa != NULL) { - ret = rsa->flags; + pkey = wolfSSL_PEM_read_bio_PUBKEY(bio, NULL, cb, pass); + if (pkey == NULL) { + WOLFSSL_MSG("wolfSSL_PEM_read_bio_PUBKEY failed"); + return NULL; } - return ret; -} - -/* Set the flags into the RSA key. - * - * @param [in, out] rsa RSA key. - * @param [in] flags Flags to set. - */ -void wolfSSL_RSA_set_flags(WOLFSSL_RSA *rsa, int flags) -{ - /* Add the flags into RSA key if available. */ - if (rsa != NULL) { - rsa->flags |= flags; + /* Since the WOLFSSL_DSA structure is being taken from WOLFSSL_EVP_PKEY the + * flag indicating that the WOLFSSL_DSA structure is owned should be FALSE + * to avoid having it free'd */ + pkey->ownDsa = 0; + local = pkey->dsa; + if (dsa != NULL) { + *dsa = local; } -} -/* Clear the flags in the RSA key. - * - * @param [in, out] rsa RSA key. - * @param [in] flags Flags to clear. - */ -void wolfSSL_RSA_clear_flags(WOLFSSL_RSA *rsa, int flags) -{ - /* Clear the flags passed in that are on the RSA key if available. */ - if (rsa != NULL) { - rsa->flags &= ~flags; - } + wolfSSL_EVP_PKEY_free(pkey); + return local; } +#endif /* (OPENSSL_EXTRA || OPENSSL_ALL) && (!NO_CERTS && + !NO_FILESYSTEM && WOLFSSL_KEY_GEN) */ -/* Test the flags in the RSA key. - * - * @param [in] rsa RSA key. - * @return Matching flags of RSA key on success. - * @return 0 when RSA key is NULL. - */ -int wolfSSL_RSA_test_flags(const WOLFSSL_RSA *rsa, int flags) -{ - /* Return the flags passed in that are set on the RSA key if available. */ - return (rsa != NULL) ? (rsa->flags & flags) : 0; -} +#endif /* NO_BIO */ -/* Get the extra data, by index, associated with the RSA key. - * - * @param [in] rsa RSA key. - * @param [in] idx Index of extra data. - * @return Extra data (anonymous type) on success. - * @return NULL on failure. - */ -void* wolfSSL_RSA_get_ex_data(const WOLFSSL_RSA *rsa, int idx) -{ - WOLFSSL_ENTER("wolfSSL_RSA_get_ex_data"); +#endif /* OPENSSL_EXTRA */ -#ifdef HAVE_EX_DATA - return (rsa == NULL) ? NULL : - wolfSSL_CRYPTO_get_ex_data(&rsa->ex_data, idx); -#else - (void)rsa; - (void)idx; +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* return 1 if success, -1 if error */ +int wolfSSL_DSA_LoadDer(WOLFSSL_DSA* dsa, const unsigned char* derBuf, + int derSz) +{ + word32 idx = 0; + int ret; - return NULL; -#endif -} + WOLFSSL_ENTER("wolfSSL_DSA_LoadDer"); -/* Set extra data against the RSA key at an index. - * - * @param [in, out] rsa RSA key. - * @param [in] idx Index set set extra data at. - * @param [in] data Extra data of anonymous type. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_set_ex_data(WOLFSSL_RSA *rsa, int idx, void *data) -{ - WOLFSSL_ENTER("wolfSSL_RSA_set_ex_data"); + if (dsa == NULL || dsa->internal == NULL || derBuf == NULL || derSz <= 0) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FATAL_ERROR; + } -#ifdef HAVE_EX_DATA - return (rsa == NULL) ? 0 : - wolfSSL_CRYPTO_set_ex_data(&rsa->ex_data, idx, data); -#else - (void)rsa; - (void)idx; - (void)data; + ret = DsaPrivateKeyDecode(derBuf, &idx, (DsaKey*)dsa->internal, + (word32)derSz); + if (ret < 0) { + WOLFSSL_MSG("DsaPrivateKeyDecode failed"); + return WOLFSSL_FATAL_ERROR; + } - return 0; -#endif -} + if (SetDsaExternal(dsa) != 1) { + WOLFSSL_MSG("SetDsaExternal failed"); + return WOLFSSL_FATAL_ERROR; + } -#ifdef HAVE_EX_DATA_CLEANUP_HOOKS -/* Set the extra data and cleanup callback against the RSA key at an index. - * - * Not OpenSSL API. - * - * @param [in, out] rsa RSA key. - * @param [in] idx Index set set extra data at. - * @param [in] data Extra data of anonymous type. - * @param [in] freeCb Callback function to free extra data. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_set_ex_data_with_cleanup(WOLFSSL_RSA *rsa, int idx, void *data, - wolfSSL_ex_data_cleanup_routine_t freeCb) -{ - WOLFSSL_ENTER("wolfSSL_RSA_set_ex_data_with_cleanup"); + dsa->inSet = 1; - return (rsa == NULL) ? 0 : - wolfSSL_CRYPTO_set_ex_data_with_cleanup(&rsa->ex_data, idx, data, - freeCb); + return 1; } -#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ - -/* - * RSA check key APIs - */ -#ifdef WOLFSSL_RSA_KEY_CHECK -/* Check that the RSA key is valid using wolfCrypt. - * - * @param [in] rsa RSA key. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_check_key(const WOLFSSL_RSA* rsa) +/* Loads DSA key from DER buffer. opt = DSA_LOAD_PRIVATE or DSA_LOAD_PUBLIC. + returns 1 on success, or 0 on failure. */ +int wolfSSL_DSA_LoadDer_ex(WOLFSSL_DSA* dsa, const unsigned char* derBuf, + int derSz, int opt) { - int ret = 1; + word32 idx = 0; + int ret; - WOLFSSL_ENTER("wolfSSL_RSA_check_key"); + WOLFSSL_ENTER("wolfSSL_DSA_LoadDer"); - /* Validate parameters. */ - if ((rsa == NULL) || (rsa->internal == NULL)) { - ret = 0; + if (dsa == NULL || dsa->internal == NULL || derBuf == NULL || derSz <= 0) { + WOLFSSL_MSG("Bad function arguments"); + return WOLFSSL_FATAL_ERROR; } - /* Constant RSA - assume internal data has been set. */ + if (opt == WOLFSSL_DSA_LOAD_PRIVATE) { + ret = DsaPrivateKeyDecode(derBuf, &idx, (DsaKey*)dsa->internal, + (word32)derSz); + } + else { + ret = DsaPublicKeyDecode(derBuf, &idx, (DsaKey*)dsa->internal, + (word32)derSz); + } - /* Check wolfCrypt RSA key. */ - if ((ret == 1) && (wc_CheckRsaKey((RsaKey*)rsa->internal) != 0)) { - ret = 0; + if (ret < 0 && opt == WOLFSSL_DSA_LOAD_PRIVATE) { + WOLFSSL_ERROR_VERBOSE(ret); + WOLFSSL_MSG("DsaPrivateKeyDecode failed"); + return WOLFSSL_FATAL_ERROR; + } + else if (ret < 0 && opt == WOLFSSL_DSA_LOAD_PUBLIC) { + WOLFSSL_ERROR_VERBOSE(ret); + WOLFSSL_MSG("DsaPublicKeyDecode failed"); + return WOLFSSL_FATAL_ERROR; } - WOLFSSL_LEAVE("wolfSSL_RSA_check_key", ret); + if (SetDsaExternal(dsa) != 1) { + WOLFSSL_MSG("SetDsaExternal failed"); + return WOLFSSL_FATAL_ERROR; + } - return ret; -} -#endif /* WOLFSSL_RSA_KEY_CHECK */ + dsa->inSet = 1; -/* - * RSA generate APIs - */ + return 1; +} +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ -/* Get a random number generator associated with the RSA key. - * - * If not able, then get the global if possible. - * *tmpRng must not be an initialized RNG. - * *tmpRng is allocated when WOLFSSL_SMALL_STACK is defined and an RNG isn't - * associated with the wolfCrypt RSA key. - * - * @param [in] rsa RSA key. - * @param [out] tmpRng Temporary random number generator. - * @param [out] initTmpRng Temporary random number generator was initialized. - * - * @return A wolfCrypt RNG to use on success. - * @return NULL on error. - */ -WC_RNG* WOLFSSL_RSA_GetRNG(WOLFSSL_RSA* rsa, WC_RNG** tmpRng, int* initTmpRng) +#ifdef OPENSSL_EXTRA +#ifndef NO_BIO +WOLFSSL_DSA *wolfSSL_PEM_read_bio_DSAparams(WOLFSSL_BIO *bp, WOLFSSL_DSA **x, + wc_pem_password_cb *cb, void *u) { - WC_RNG* rng = NULL; - int err = 0; + WOLFSSL_DSA* dsa; + DsaKey* key; + int length; + unsigned char* buf; + word32 bufSz; + int ret; + word32 idx = 0; + DerBuffer* pDer; - /* Check validity of parameters. */ - if ((rsa == NULL) || (initTmpRng == NULL)) { - err = 1; - } - if (!err) { - /* Haven't initialized any RNG passed through tmpRng. */ - *initTmpRng = 0; + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_DSAparams"); - #if !defined(HAVE_FIPS) && defined(WC_RSA_BLINDING) - /* Use wolfCrypt RSA key's RNG if available/set. */ - rng = ((RsaKey*)rsa->internal)->rng; - #endif - } - if ((!err) && (rng == NULL) && (tmpRng != NULL)) { - /* Make an RNG with tmpRng or get global. */ - rng = wolfssl_make_rng(*tmpRng, initTmpRng); - if ((rng != NULL) && *initTmpRng) { - *tmpRng = rng; - } + ret = wolfSSL_BIO_get_mem_data(bp, &buf); + if (ret <= 0) { + WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_DSAparams", ret); + return NULL; } - return rng; -} + bufSz = (word32)ret; -/* Use the wolfCrypt RSA APIs to generate a new RSA key. - * - * @param [in, out] rsa RSA key. - * @param [in] bits Number of bits that the modulus must have. - * @param [in] e A BN object holding the public exponent to use. - * @param [in] cb Status callback. Unused. - * @return 0 on success. - * @return wolfSSL native error code on error. - */ -static int wolfssl_rsa_generate_key_native(WOLFSSL_RSA* rsa, int bits, - WOLFSSL_BIGNUM* e, void* cb) -{ -#ifdef WOLFSSL_KEY_GEN - int ret = 0; -#ifdef WOLFSSL_SMALL_STACK - WC_RNG* tmpRng = NULL; -#else - WC_RNG _tmpRng[1]; - WC_RNG* tmpRng = _tmpRng; -#endif - int initTmpRng = 0; - WC_RNG* rng = NULL; - long en = 0; -#endif + if (cb != NULL || u != NULL) { + /* + * cb is for a call back when encountering encrypted PEM files + * if cb == NULL and u != NULL then u = null terminated password string + */ + WOLFSSL_MSG("Not supporting callback or password for encrypted PEM"); + } - (void)cb; + if (PemToDer(buf, (long)bufSz, DSA_PARAM_TYPE, &pDer, NULL, NULL, + NULL) < 0 ) { + WOLFSSL_MSG("Issue converting from PEM to DER"); + return NULL; + } - WOLFSSL_ENTER("wolfssl_rsa_generate_key_native"); + if (GetSequence(pDer->buffer, &idx, &length, pDer->length) < 0) { + WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_DSAparams", ret); + FreeDer(&pDer); + return NULL; + } -#ifdef WOLFSSL_KEY_GEN - /* Get RNG in wolfCrypt RSA key or initialize a new one (or global). */ - rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); - if (rng == NULL) { - /* Something went wrong so return memory error. */ - ret = MEMORY_E; + dsa = wolfSSL_DSA_new(); + if (dsa == NULL) { + FreeDer(&pDer); + WOLFSSL_MSG("Error creating DSA struct"); + return NULL; } - if ((ret == 0) && ((en = (long)wolfSSL_BN_get_word(e)) <= 0)) { - ret = BAD_FUNC_ARG; + + key = (DsaKey*)dsa->internal; + if (key == NULL) { + FreeDer(&pDer); + wolfSSL_DSA_free(dsa); + WOLFSSL_MSG("Error finding DSA key struct"); + return NULL; } - if (ret == 0) { - /* Generate an RSA key. */ - ret = wc_MakeRsaKey((RsaKey*)rsa->internal, bits, en, rng); - if (ret != MP_OKAY) { - WOLFSSL_ERROR_MSG("wc_MakeRsaKey failed"); - } + + if (GetInt(&key->p, pDer->buffer, &idx, pDer->length) < 0 || + GetInt(&key->q, pDer->buffer, &idx, pDer->length) < 0 || + GetInt(&key->g, pDer->buffer, &idx, pDer->length) < 0 ) { + WOLFSSL_MSG("dsa key error"); + FreeDer(&pDer); + wolfSSL_DSA_free(dsa); + return NULL; } - if (ret == 0) { - /* Get the values from wolfCrypt RSA key into external RSA key. */ - ret = SetRsaExternal(rsa); - if (ret == 1) { - /* Internal matches external. */ - rsa->inSet = 1; - /* Return success. */ - ret = 0; - } - else { - /* Something went wrong so return memory error. */ - ret = MEMORY_E; - } + + if (wolfssl_bn_set_value(&dsa->p, &key->p) != 1) { + WOLFSSL_MSG("dsa p key error"); + FreeDer(&pDer); + wolfSSL_DSA_free(dsa); + return NULL; } - /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ - if (initTmpRng) { - wc_FreeRng(tmpRng); + if (wolfssl_bn_set_value(&dsa->q, &key->q) != 1) { + WOLFSSL_MSG("dsa q key error"); + FreeDer(&pDer); + wolfSSL_DSA_free(dsa); + return NULL; } - WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); - return ret; -#else - WOLFSSL_ERROR_MSG("No Key Gen built in"); + if (wolfssl_bn_set_value(&dsa->g, &key->g) != 1) { + WOLFSSL_MSG("dsa g key error"); + FreeDer(&pDer); + wolfSSL_DSA_free(dsa); + return NULL; + } - (void)rsa; - (void)e; - (void)bits; + if (x != NULL) { + *x = dsa; + } - return NOT_COMPILED_IN; -#endif + FreeDer(&pDer); + return dsa; } +#endif /* !NO_BIO */ -/* Generate an RSA key that has the specified modulus size and public exponent. - * - * Note: Because of wc_MakeRsaKey an RSA key size generated can be rounded - * down to nearest multiple of 8. For example generating a key of size - * 2999 bits will make a key of size 374 bytes instead of 375 bytes. - * - * @param [in] bits Number of bits that the modulus must have i.e. 2048. - * @param [in] e Public exponent to use i.e. 65537. - * @param [in] cb Status callback. Unused. - * @param [in] data Data to pass to status callback. Unused. - * @return A new RSA key on success. - * @return NULL on failure. - */ -WOLFSSL_RSA* wolfSSL_RSA_generate_key(int bits, unsigned long e, - void(*cb)(int, int, void*), void* data) +#if !defined(NO_DH) +WOLFSSL_DH *wolfSSL_DSA_dup_DH(const WOLFSSL_DSA *dsa) { - WOLFSSL_RSA* rsa = NULL; - WOLFSSL_BIGNUM* bn = NULL; - int err = 0; - - WOLFSSL_ENTER("wolfSSL_RSA_generate_key"); + WOLFSSL_DH* dh; + DhKey* key; - (void)cb; - (void)data; + WOLFSSL_ENTER("wolfSSL_DSA_dup_DH"); - /* Validate bits. */ - if (bits < 0) { - WOLFSSL_ERROR_MSG("Bad argument: bits was less than 0"); - err = 1; - } - /* Create a new BN to hold public exponent - for when wolfCrypt supports - * longer values. */ - if ((!err) && ((bn = wolfSSL_BN_new()) == NULL)) { - WOLFSSL_ERROR_MSG("Error creating big number"); - err = 1; + if (dsa == NULL) { + return NULL; } - /* Set public exponent. */ - if ((!err) && (wolfSSL_BN_set_word(bn, e) != 1)) { - WOLFSSL_ERROR_MSG("Error using e value"); - err = 1; + + dh = wolfSSL_DH_new(); + if (dh == NULL) { + return NULL; } + key = (DhKey*)dh->internal; - /* Create an RSA key object to hold generated key. */ - if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) { - WOLFSSL_ERROR_MSG("memory error"); - err = 1; + if (dsa->p != NULL && + wolfssl_bn_get_value(((WOLFSSL_DSA*)dsa)->p, &key->p) + != 1) { + WOLFSSL_MSG("rsa p key error"); + wolfSSL_DH_free(dh); + return NULL; + } + if (dsa->g != NULL && + wolfssl_bn_get_value(((WOLFSSL_DSA*)dsa)->g, &key->g) + != 1) { + WOLFSSL_MSG("rsa g key error"); + wolfSSL_DH_free(dh); + return NULL; } - while (!err) { - int ret; - /* Use wolfCrypt to generate RSA key. */ - ret = wolfssl_rsa_generate_key_native(rsa, bits, bn, NULL); - #ifdef HAVE_FIPS - /* Keep trying if failed to find a prime. */ - if (ret == WC_NO_ERR_TRACE(PRIME_GEN_E)) { - continue; - } - #endif - if (ret != WOLFSSL_ERROR_NONE) { - /* Unrecoverable error in generation. */ - err = 1; - } - /* Done generating - unrecoverable error or success. */ - break; + if (wolfssl_bn_set_value(&dh->p, &key->p) != 1) { + WOLFSSL_MSG("dsa p key error"); + wolfSSL_DH_free(dh); + return NULL; } - if (err) { - /* Dispose of RSA key object if generation didn't work. */ - wolfSSL_RSA_free(rsa); - /* Returning NULL on error. */ - rsa = NULL; + if (wolfssl_bn_set_value(&dh->g, &key->g) != 1) { + WOLFSSL_MSG("dsa g key error"); + wolfSSL_DH_free(dh); + return NULL; } - /* Dispose of the temporary BN used for the public exponent. */ - wolfSSL_BN_free(bn); - return rsa; + return dh; } +#endif /* !NO_DH */ -/* Generate an RSA key that has the specified modulus size and public exponent. - * - * Note: Because of wc_MakeRsaKey an RSA key size generated can be rounded - * down to nearest multiple of 8. For example generating a key of size - * 2999 bits will make a key of size 374 bytes instead of 375 bytes. - * - * @param [in] bits Number of bits that the modulus must have i.e. 2048. - * @param [in] e Public exponent to use, i.e. 65537, as a BN. - * @param [in] cb Status callback. Unused. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_RSA_generate_key_ex(WOLFSSL_RSA* rsa, int bits, WOLFSSL_BIGNUM* e, - void* cb) -{ - int ret = 1; +#endif /* OPENSSL_EXTRA */ - /* Validate parameters. */ - if ((rsa == NULL) || (rsa->internal == NULL)) { - WOLFSSL_ERROR_MSG("bad arguments"); - ret = 0; - } - else { - for (;;) { - /* Use wolfCrypt to generate RSA key. */ - int gen_ret = wolfssl_rsa_generate_key_native(rsa, bits, e, cb); - #ifdef HAVE_FIPS - /* Keep trying again if public key value didn't work. */ - if (gen_ret == WC_NO_ERR_TRACE(PRIME_GEN_E)) { - continue; - } - #endif - if (gen_ret != WOLFSSL_ERROR_NONE) { - /* Unrecoverable error in generation. */ - ret = 0; - } - /* Done generating - unrecoverable error or success. */ - break; - } - } +#endif /* !NO_DSA */ - return ret; -} +/******************************************************************************* + * END OF DSA API + ******************************************************************************/ -#endif /* OPENSSL_EXTRA */ -/* - * RSA padding APIs - */ +/******************************************************************************* + * START OF DH API + ******************************************************************************/ -#ifdef WC_RSA_PSS +#ifndef NO_DH -#if defined(OPENSSL_EXTRA) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) -static int rsa_pss_calc_salt(int saltLen, int hashLen, int emLen) -{ - /* Calculate the salt length to use for special cases. */ - switch (saltLen) { - /* Negative saltLen values are treated differently. */ - case WC_RSA_PSS_SALTLEN_DIGEST: - saltLen = hashLen; - break; - case WC_RSA_PSS_SALTLEN_MAX_SIGN: - case WC_RSA_PSS_SALTLEN_MAX: - #ifdef WOLFSSL_PSS_LONG_SALT - saltLen = emLen - hashLen - 2; - #else - saltLen = hashLen; - (void)emLen; - #endif - break; - default: - break; - } - if (saltLen < 0) { - /* log invalid salt, let wolfCrypt handle error */ - WOLFSSL_ERROR_MSG("invalid saltLen"); - saltLen = -3; /* for wolfCrypt to produce error must be < -2 */ - } - return saltLen; -} -#endif /* OPENSSL_EXTRA && !HAVE_SELFTEST */ +#ifdef OPENSSL_EXTRA -#if (defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \ - defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX)) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) +/* + * DH constructor/deconstructor APIs + */ -/* Add PKCS#1 PSS padding to hash. - * - * - * +-----------+ - * | M | - * +-----------+ - * | - * V - * Hash - * | - * V - * +--------+----------+----------+ - * M' = |Padding1| mHash | salt | - * +--------+----------+----------+ - * | - * +--------+----------+ V - * DB = |Padding2|maskedseed| Hash - * +--------+----------+ | - * | | - * V | +--+ - * xor <--- MGF <---| |bc| - * | | +--+ - * | | | - * V V V - * +-------------------+----------+--+ - * EM = | maskedDB |maskedseed|bc| - * +-------------------+----------+--+ - * Diagram taken from https://tools.ietf.org/html/rfc3447#section-9.1 +/* Allocate and initialize a new DH key. * - * @param [in] rsa RSA key. - * @param [out] em Encoded message. - * @param [in[ mHash Message hash. - * @param [in] hashAlg Hash algorithm. - * @param [in] mgf1Hash MGF algorithm. - * @param [in] saltLen Length of salt to generate. - * @return 1 on success. - * @return 0 on failure. + * @return DH key on success. + * @return NULL on failure. */ - -int wolfSSL_RSA_padding_add_PKCS1_PSS_mgf1(WOLFSSL_RSA *rsa, unsigned char *em, - const unsigned char *mHash, const WOLFSSL_EVP_MD *hashAlg, - const WOLFSSL_EVP_MD *mgf1Hash, int saltLen) +WOLFSSL_DH* wolfSSL_DH_new(void) { - int ret = 1; - enum wc_HashType hashType = WC_HASH_TYPE_NONE; - int hashLen = 0; - int emLen = 0; - int mgf = 0; - int initTmpRng = 0; - WC_RNG *rng = NULL; -#ifdef WOLFSSL_SMALL_STACK - WC_RNG* tmpRng = NULL; -#else - WC_RNG _tmpRng[1]; - WC_RNG* tmpRng = _tmpRng; -#endif - - WOLFSSL_ENTER("wolfSSL_RSA_padding_add_PKCS1_PSS"); - - /* Validate parameters. */ - if ((rsa == NULL) || (em == NULL) || (mHash == NULL) || (hashAlg == NULL)) { - ret = 0; - } - - if (mgf1Hash == NULL) - mgf1Hash = hashAlg; + int err = 0; + WOLFSSL_DH* dh = NULL; + DhKey* key = NULL; - if (ret == 1) { - /* Get/create an RNG. */ - rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); - if (rng == NULL) { - WOLFSSL_ERROR_MSG("WOLFSSL_RSA_GetRNG error"); - ret = 0; - } - } + WOLFSSL_ENTER("wolfSSL_DH_new"); - /* TODO: use wolfCrypt RSA key to get emLen and bits? */ - /* Set the external data from the wolfCrypt RSA key if not done. */ - if ((ret == 1) && (!rsa->exSet)) { - ret = SetRsaExternal(rsa); + /* Allocate OpenSSL DH key. */ + dh = (WOLFSSL_DH*)XMALLOC(sizeof(WOLFSSL_DH), NULL, DYNAMIC_TYPE_DH); + if (dh == NULL) { + WOLFSSL_ERROR_MSG("wolfSSL_DH_new malloc WOLFSSL_DH failure"); + err = 1; } - if (ret == 1) { - /* Get the wolfCrypt hash algorithm type. */ - hashType = EvpMd2MacType(hashAlg); - if (hashType > WC_HASH_TYPE_MAX) { - WOLFSSL_ERROR_MSG("EvpMd2MacType error"); - ret = 0; - } - } - if (ret == 1) { - /* Get the wolfCrypt MGF algorithm from hash algorithm. */ - mgf = wc_hash2mgf(EvpMd2MacType(mgf1Hash)); - if (mgf == WC_MGF1NONE) { - WOLFSSL_ERROR_MSG("wc_hash2mgf error"); - ret = 0; - } - } - if (ret == 1) { - /* Get the length of the hash output. */ - hashLen = wolfSSL_EVP_MD_size(hashAlg); - if (hashLen < 0) { - WOLFSSL_ERROR_MSG("wolfSSL_EVP_MD_size error"); - ret = 0; - } + if (!err) { + /* Clear key data. */ + XMEMSET(dh, 0, sizeof(WOLFSSL_DH)); + /* Initialize reference counting. */ + wolfSSL_RefInit(&dh->ref, &err); +#ifdef WOLFSSL_REFCNT_ERROR_RETURN } - - if (ret == 1) { - /* Get length of RSA key - encrypted message length. */ - emLen = wolfSSL_RSA_size(rsa); - if (emLen <= 0) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_size error"); - ret = 0; + if (!err) { +#endif + /* Allocate wolfSSL DH key. */ + key = (DhKey*)XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH); + if (key == NULL) { + WOLFSSL_ERROR_MSG("wolfSSL_DH_new malloc DhKey failure"); + err = 1; } } - - if (ret == 1) { - saltLen = rsa_pss_calc_salt(saltLen, hashLen, emLen); - } - - if (ret == 1) { - /* Generate RSA PKCS#1 PSS padding for hash using wolfCrypt. */ - if (wc_RsaPad_ex(mHash, (word32)hashLen, em, (word32)emLen, - RSA_BLOCK_TYPE_1, rng, WC_RSA_PSS_PAD, hashType, mgf, NULL, 0, - saltLen, wolfSSL_BN_num_bits(rsa->n), NULL) != MP_OKAY) { - WOLFSSL_ERROR_MSG("wc_RsaPad_ex error"); - ret = 0; + if (!err) { + /* Set and initialize wolfSSL DH key. */ + dh->internal = key; + if (wc_InitDhKey(key) != 0) { + WOLFSSL_ERROR_MSG("wolfSSL_DH_new InitDhKey failure"); + err = 1; } } - /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ - if (initTmpRng) { - wc_FreeRng(tmpRng); + if (err && (dh != NULL)) { + /* Dispose of the allocated memory. */ + XFREE(key, NULL, DYNAMIC_TYPE_DH); + wolfSSL_RefFree(&dh->ref); + XFREE(dh, NULL, DYNAMIC_TYPE_DH); + dh = NULL; } - WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); - - return ret; -} - -int wolfSSL_RSA_padding_add_PKCS1_PSS(WOLFSSL_RSA *rsa, unsigned char *em, - const unsigned char *mHash, const WOLFSSL_EVP_MD *hashAlg, int saltLen) -{ - return wolfSSL_RSA_padding_add_PKCS1_PSS_mgf1(rsa, em, mHash, hashAlg, NULL, - saltLen); + return dh; } -/* Checks that the hash is valid for the RSA PKCS#1 PSS encoded message. - * - * Refer to wolfSSL_RSA_padding_add_PKCS1_PSS for a diagram. +#if defined(HAVE_PUBLIC_FFDHE) || (defined(HAVE_FIPS) && FIPS_VERSION_EQ(2,0)) +/* Set the DH parameters based on the NID. * - * @param [in] rsa RSA key. - * @param [in[ mHash Message hash. - * @param [in] hashAlg Hash algorithm. - * @param [in] mgf1Hash MGF algorithm. - * @param [in] em Encoded message. - * @param [in] saltLen Length of salt to generate. - * @return 1 on success. - * @return 0 on failure. + * @param [in, out] dh DH key to set. + * @param [in] nid Numeric ID of predefined DH parameters. + * @return 0 on success. + * @return 1 on failure. */ -int wolfSSL_RSA_verify_PKCS1_PSS_mgf1(WOLFSSL_RSA *rsa, - const unsigned char *mHash, const WOLFSSL_EVP_MD *hashAlg, - const WOLFSSL_EVP_MD *mgf1Hash, const unsigned char *em, int saltLen) +static int wolfssl_dh_set_nid(WOLFSSL_DH* dh, int nid) { - int ret = 1; - int hashLen = 0; - int mgf = 0; - int emLen = 0; - int mPrimeLen = 0; - enum wc_HashType hashType = WC_HASH_TYPE_NONE; - byte *mPrime = NULL; - byte *buf = NULL; - - WOLFSSL_ENTER("wolfSSL_RSA_verify_PKCS1_PSS"); - - /* Validate parameters. */ - if ((rsa == NULL) || (mHash == NULL) || (hashAlg == NULL) || (em == NULL)) { - ret = 0; - } - - if (mgf1Hash == NULL) - mgf1Hash = hashAlg; + int err = 0; + const DhParams* params = NULL; - /* TODO: use wolfCrypt RSA key to get emLen and bits? */ - /* Set the external data from the wolfCrypt RSA key if not done. */ - if ((ret == 1) && (!rsa->exSet)) { - ret = SetRsaExternal(rsa); + /* HAVE_PUBLIC_FFDHE not required to expose wc_Dh_ffdhe* functions in + * FIPS v2 module */ + switch (nid) { +#ifdef HAVE_FFDHE_2048 + case WC_NID_ffdhe2048: + params = wc_Dh_ffdhe2048_Get(); + break; +#endif /* HAVE_FFDHE_2048 */ +#ifdef HAVE_FFDHE_3072 + case WC_NID_ffdhe3072: + params = wc_Dh_ffdhe3072_Get(); + break; +#endif /* HAVE_FFDHE_3072 */ +#ifdef HAVE_FFDHE_4096 + case WC_NID_ffdhe4096: + params = wc_Dh_ffdhe4096_Get(); + break; +#endif /* HAVE_FFDHE_4096 */ + default: + break; } - - if (ret == 1) { - /* Get hash length for hash algorithm. */ - hashLen = wolfSSL_EVP_MD_size(hashAlg); - if (hashLen < 0) { - ret = 0; - } + if (params == NULL) { + WOLFSSL_ERROR_MSG("Unable to find DH params for nid."); + err = 1; } - if (ret == 1) { - /* Get length of RSA key - encrypted message length. */ - emLen = wolfSSL_RSA_size(rsa); - if (emLen <= 0) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_size error"); - ret = 0; + if (!err) { + /* Set prime from data retrieved. */ + dh->p = wolfSSL_BN_bin2bn(params->p, (int)params->p_len, NULL); + if (dh->p == NULL) { + WOLFSSL_ERROR_MSG("Error converting p hex to WOLFSSL_BIGNUM."); + err = 1; } } - - if (ret == 1) { - saltLen = rsa_pss_calc_salt(saltLen, hashLen, emLen); - } - - if (ret == 1) { - /* Get the wolfCrypt hash algorithm type. */ - hashType = EvpMd2MacType(hashAlg); - if (hashType > WC_HASH_TYPE_MAX) { - WOLFSSL_ERROR_MSG("EvpMd2MacType error"); - ret = 0; + if (!err) { + /* Set generator from data retrieved. */ + dh->g = wolfSSL_BN_bin2bn(params->g, (int)params->g_len, NULL); + if (dh->g == NULL) { + WOLFSSL_ERROR_MSG("Error converting g hex to WOLFSSL_BIGNUM."); + err = 1; } } - - if (ret == 1) { - /* Get the wolfCrypt MGF algorithm from hash algorithm. */ - if ((mgf = wc_hash2mgf(EvpMd2MacType(mgf1Hash))) == WC_MGF1NONE) { - WOLFSSL_ERROR_MSG("wc_hash2mgf error"); - ret = 0; +#ifdef HAVE_FFDHE_Q + if (!err) { + /* Set order from data retrieved. */ + dh->q = wolfSSL_BN_bin2bn(params->q, params->q_len, NULL); + if (dh->q == NULL) { + WOLFSSL_ERROR_MSG("Error converting q hex to WOLFSSL_BIGNUM."); + err = 1; } } +#endif - if (ret == 1) { - /* Allocate buffer to unpad inline with. */ - buf = (byte*)XMALLOC((size_t)emLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (buf == NULL) { - WOLFSSL_ERROR_MSG("malloc error"); - ret = 0; - } + /* Synchronize the external into internal DH key's parameters. */ + if ((!err) && (SetDhInternal(dh) != 1)) { + WOLFSSL_ERROR_MSG("Failed to set internal DH params."); + err = 1; } - - if (ret == 1) { - /* Copy encrypted message to temp for inline unpadding. */ - XMEMCPY(buf, em, (size_t)emLen); - - /* Remove and verify the PSS padding. */ - mPrimeLen = wc_RsaUnPad_ex(buf, (word32)emLen, &mPrime, - RSA_BLOCK_TYPE_1, WC_RSA_PSS_PAD, hashType, mgf, NULL, 0, saltLen, - wolfSSL_BN_num_bits(rsa->n), NULL); - if (mPrimeLen < 0) { - WOLFSSL_ERROR_MSG("wc_RsaPad_ex error"); - ret = 0; - } + if (!err) { + /* External DH key parameters were set. */ + dh->exSet = 1; } - if (ret == 1) { - /* Verify the hash is correct. */ - if (wc_RsaPSS_CheckPadding_ex(mHash, (word32)hashLen, mPrime, - (word32)mPrimeLen, hashType, saltLen, - wolfSSL_BN_num_bits(rsa->n)) != MP_OKAY) { - WOLFSSL_ERROR_MSG("wc_RsaPSS_CheckPadding_ex error"); - ret = 0; - } + if (err == 1) { + /* Dispose of any external parameters. */ + #ifdef HAVE_FFDHE_Q + wolfSSL_BN_free(dh->q); + dh->q = NULL; + #endif + wolfSSL_BN_free(dh->p); + dh->p = NULL; + wolfSSL_BN_free(dh->g); + dh->g = NULL; } - /* Dispose of any allocated buffer. */ - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return ret; -} - -int wolfSSL_RSA_verify_PKCS1_PSS(WOLFSSL_RSA *rsa, const unsigned char *mHash, - const WOLFSSL_EVP_MD *hashAlg, - const unsigned char *em, int saltLen) -{ - return wolfSSL_RSA_verify_PKCS1_PSS_mgf1(rsa, mHash, hashAlg, NULL, em, - saltLen); + return err; } -#endif /* (!HAVE_FIPS || FIPS_VERSION_GT(2,0)) && \ - (OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_NGINX) */ -#endif /* WC_RSA_PSS */ - -/* - * RSA sign/verify APIs - */ - -#if defined(WC_RSA_PSS) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,1)) - #ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER - #define DEF_PSS_SALT_LEN RSA_PSS_SALT_LEN_DEFAULT - #else - #define DEF_PSS_SALT_LEN RSA_PSS_SALT_LEN_DISCOVER - #endif -#else - #define DEF_PSS_SALT_LEN 0 /* not used */ -#endif - -#if defined(OPENSSL_EXTRA) - -/* Encode the message hash. +#elif !defined(HAVE_PUBLIC_FFDHE) && (!defined(HAVE_FIPS) || \ + FIPS_VERSION_GT(2,0)) +/* Set the DH parameters based on the NID. * - * Used by signing and verification. + * FIPS v2 and lower doesn't support wc_DhSetNamedKey. * - * @param [in] hashAlg Hash algorithm OID. - * @param [in] hash Hash of message to encode for signing. - * @param [in] hLen Length of hash of message. - * @param [out] enc Encoded message hash. - * @param [out] encLen Length of encoded message hash. - * @param [in] padding Which padding scheme is being used. - * @return 1 on success. - * @return 0 on failure. - */ -static int wolfssl_rsa_sig_encode(int hashAlg, const unsigned char* hash, - unsigned int hLen, unsigned char* enc, unsigned int* encLen, int padding) + * @param [in, out] dh DH key to set. + * @param [in] nid Numeric ID of predefined DH parameters. + * @return 0 on success. + * @return 1 on failure. + */ +static int wolfssl_dh_set_nid(WOLFSSL_DH* dh, int nid) { - int ret = 1; - int hType = WC_HASH_TYPE_NONE; - - /* Validate parameters. */ - if ((hash == NULL) || (enc == NULL) || (encLen == NULL)) { - ret = 0; - } + int err = 0; + int name = 0; +#ifdef HAVE_FFDHE_Q + int elements = ELEMENT_P | ELEMENT_G | ELEMENT_Q; +#else + int elements = ELEMENT_P | ELEMENT_G; +#endif /* HAVE_FFDHE_Q */ - if ((ret == 1) && (hashAlg != WC_NID_undef) && - (padding == WC_RSA_PKCS1_PADDING)) { - /* Convert hash algorithm to hash type for PKCS#1.5 padding. */ - hType = (int)nid2oid(hashAlg, oidHashType); - if (hType == -1) { - ret = 0; - } + switch (nid) { +#ifdef HAVE_FFDHE_2048 + case WC_NID_ffdhe2048: + name = WC_FFDHE_2048; + break; +#endif /* HAVE_FFDHE_2048 */ +#ifdef HAVE_FFDHE_3072 + case WC_NID_ffdhe3072: + name = WC_FFDHE_3072; + break; +#endif /* HAVE_FFDHE_3072 */ +#ifdef HAVE_FFDHE_4096 + case WC_NID_ffdhe4096: + name = WC_FFDHE_4096; + break; +#endif /* HAVE_FFDHE_4096 */ + default: + err = 1; + WOLFSSL_ERROR_MSG("Unable to find DH params for nid."); + break; } - if ((ret == 1) && (padding == WC_RSA_PKCS1_PADDING)) { - /* PKCS#1.5 encoding. */ - word32 encSz = wc_EncodeSignature(enc, hash, hLen, hType); - if (encSz == 0) { - WOLFSSL_ERROR_MSG("Bad Encode Signature"); - ret = 0; - } - else { - *encLen = (unsigned int)encSz; - } + /* Set the internal DH key's parameters based on name. */ + if ((!err) && (wc_DhSetNamedKey((DhKey*)dh->internal, name) != 0)) { + WOLFSSL_ERROR_MSG("wc_DhSetNamedKey failed."); + err = 1; } - /* Other padding schemes require the hash as is. */ - if ((ret == 1) && (padding != WC_RSA_PKCS1_PADDING)) { - XMEMCPY(enc, hash, hLen); - *encLen = hLen; + /* Synchronize the internal into external DH key's parameters. */ + if (!err && (SetDhExternal_ex(dh, elements) != 1)) { + WOLFSSL_ERROR_MSG("Failed to set external DH params."); + err = 1; } - return ret; + return err; } - -/* Sign the message hash using hash algorithm and RSA key. +#else +/* Set the DH parameters based on the NID. * - * @param [in] hashAlg Hash algorithm OID. - * @param [in] hash Hash of message to encode for signing. - * @param [in] hLen Length of hash of message. - * @param [out] enc Encoded message hash. - * @param [out] encLen Length of encoded message hash. - * @param [in] rsa RSA key. - * @return 1 on success. - * @return 0 on failure. + * Pre-defined DH parameters not available. + * + * @param [in, out] dh DH key to set. + * @param [in] nid Numeric ID of predefined DH parameters. + * @return 1 for failure. */ -int wolfSSL_RSA_sign(int hashAlg, const unsigned char* hash, unsigned int hLen, - unsigned char* sigRet, unsigned int* sigLen, WOLFSSL_RSA* rsa) +static int wolfssl_dh_set_nid(WOLFSSL_DH* dh, int nid) { - if (sigLen != NULL) { - /* No size checking in this API */ - *sigLen = RSA_MAX_SIZE / CHAR_BIT; - } - /* flag is 1: output complete signature. */ - return wolfSSL_RSA_sign_generic_padding(hashAlg, hash, hLen, sigRet, - sigLen, rsa, 1, WC_RSA_PKCS1_PADDING); + return 1; } +#endif -/* Sign the message hash using hash algorithm and RSA key. +/* Allocate and initialize a new DH key with the parameters based on the NID. * - * Not OpenSSL API. + * @param [in] nid Numeric ID of DH parameters. * - * @param [in] hashAlg Hash algorithm NID. - * @param [in] hash Hash of message to encode for signing. - * @param [in] hLen Length of hash of message. - * @param [out] enc Encoded message hash. - * @param [out] encLen Length of encoded message hash. - * @param [in] rsa RSA key. - * @param [in] flag When 1: Output encrypted signature. - * When 0: Output encoded hash. - * @return 1 on success. - * @return 0 on failure. + * @return DH key on success. + * @return NULL on failure. */ -int wolfSSL_RSA_sign_ex(int hashAlg, const unsigned char* hash, - unsigned int hLen, unsigned char* sigRet, unsigned int* sigLen, - WOLFSSL_RSA* rsa, int flag) +WOLFSSL_DH* wolfSSL_DH_new_by_nid(int nid) { - int ret = 0; + WOLFSSL_DH* dh = NULL; + int err = 0; - if ((flag == 0) || (flag == 1)) { - if (sigLen != NULL) { - /* No size checking in this API */ - *sigLen = RSA_MAX_SIZE / CHAR_BIT; - } - ret = wolfSSL_RSA_sign_generic_padding(hashAlg, hash, hLen, sigRet, - sigLen, rsa, flag, WC_RSA_PKCS1_PADDING); + WOLFSSL_ENTER("wolfSSL_DH_new_by_nid"); + + /* Allocate a new DH key. */ + dh = wolfSSL_DH_new(); + if (dh == NULL) { + WOLFSSL_ERROR_MSG("Failed to create WOLFSSL_DH."); + err = 1; + } + if (!err) { + /* Set the parameters based on NID. */ + err = wolfssl_dh_set_nid(dh, nid); } - return ret; -} + if (err && (dh != NULL)) { + /* Dispose of the key on failure to set. */ + wolfSSL_DH_free(dh); + dh = NULL; + } -int wolfSSL_RSA_sign_generic_padding(int hashAlg, const unsigned char* hash, - unsigned int hLen, unsigned char* sigRet, unsigned int* sigLen, - WOLFSSL_RSA* rsa, int flag, int padding) -{ - return wolfSSL_RSA_sign_mgf(hashAlg, hash, hLen, sigRet, sigLen, rsa, flag, - padding, hashAlg, DEF_PSS_SALT_LEN); + WOLFSSL_LEAVE("wolfSSL_DH_new_by_nid", err); + + return dh; } -/** - * Sign a message hash with the chosen message digest, padding, and RSA key. +/* Dispose of DH key and allocated data. * - * Not OpenSSL API. + * Cannot use dh after this call. * - * @param [in] hashAlg Hash NID - * @param [in] hash Message hash to sign. - * @param [in] mLen Length of message hash to sign. - * @param [out] sigRet Output buffer. - * @param [in, out] sigLen On Input: length of sigRet buffer. - * On Output: length of data written to sigRet. - * @param [in] rsa RSA key used to sign the input. - * @param [in] flag 1: Output the signature. - * 0: Output the value that the unpadded signature - * should be compared to. - * @param [in] padding Padding to use. Only RSA_PKCS1_PSS_PADDING and - * WC_RSA_PKCS1_PADDING are currently supported for - * signing. - * @param [in] mgf1Hash MGF1 Hash NID - * @param [in] saltLen Length of RSA PSS salt - * @return 1 on success. - * @return 0 on failure. + * @param [in] dh DH key to free. */ -int wolfSSL_RSA_sign_mgf(int hashAlg, const unsigned char* hash, - unsigned int hLen, unsigned char* sigRet, unsigned int* sigLen, - WOLFSSL_RSA* rsa, int flag, int padding, int mgf1Hash, int saltLen) +void wolfSSL_DH_free(WOLFSSL_DH* dh) { - int ret = 1; - word32 outLen = 0; - int signSz = 0; - WC_RNG* rng = NULL; - int initTmpRng = 0; -#ifdef WOLFSSL_SMALL_STACK - WC_RNG* tmpRng = NULL; - byte* encodedSig = NULL; -#else - WC_RNG _tmpRng[1]; - WC_RNG* tmpRng = _tmpRng; - byte encodedSig[MAX_ENCODED_SIG_SZ]; -#endif - unsigned int encSz = 0; - - WOLFSSL_ENTER("wolfSSL_RSA_sign_mgf"); - - if (flag == 0) { - /* Only encode message. */ - return wolfssl_rsa_sig_encode(hashAlg, hash, hLen, sigRet, sigLen, - padding); - } - - /* Validate parameters. */ - if ((hash == NULL) || (sigRet == NULL) || sigLen == NULL || rsa == NULL) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = 0; - } - - /* Set wolfCrypt RSA key data from external if not already done. */ - if ((ret == 1) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { - ret = 0; - } - - if (ret == 1) { - /* Get the maximum signature length. */ - outLen = (word32)wolfSSL_BN_num_bytes(rsa->n); - /* Check not an error return. */ - if (outLen == 0) { - WOLFSSL_ERROR_MSG("Bad RSA size"); - ret = 0; - } - /* Check signature buffer is big enough. */ - else if (outLen > *sigLen) { - WOLFSSL_ERROR_MSG("Output buffer too small"); - ret = 0; - } - } + int doFree = 0; -#ifdef WOLFSSL_SMALL_STACK - if (ret == 1) { - /* Allocate encoded signature buffer if doing PKCS#1 padding. */ - encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, - DYNAMIC_TYPE_SIGNATURE); - if (encodedSig == NULL) { - ret = 0; - } - } -#endif + WOLFSSL_ENTER("wolfSSL_DH_free"); - if (ret == 1) { - /* Get/create an RNG. */ - rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); - if (rng == NULL) { - WOLFSSL_ERROR_MSG("WOLFSSL_RSA_GetRNG error"); - ret = 0; - } - } + if (dh != NULL) { + int err; - /* Either encodes with PKCS#1.5 or copies hash into encodedSig. */ - if ((ret == 1) && (wolfssl_rsa_sig_encode(hashAlg, hash, hLen, encodedSig, - &encSz, padding) == 0)) { - WOLFSSL_ERROR_MSG("Bad Encode Signature"); - ret = 0; + /* Only free if all references to it are done */ + wolfSSL_RefDec(&dh->ref, &doFree, &err); + /* Ignore errors - doFree will be 0 on error. */ + (void)err; } + if (doFree) { + /* Dispose of allocated reference counting data. */ + wolfSSL_RefFree(&dh->ref); - if (ret == 1) { - switch (padding) { - #if defined(WC_RSA_NO_PADDING) || defined(WC_RSA_DIRECT) - case WC_RSA_NO_PAD: - if ((signSz = wc_RsaDirect(encodedSig, encSz, sigRet, &outLen, - (RsaKey*)rsa->internal, RSA_PRIVATE_ENCRYPT, rng)) <= 0) { - WOLFSSL_ERROR_MSG("Bad RSA Sign no pad"); - ret = 0; - } - break; - #endif - #if defined(WC_RSA_PSS) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,1)) - case WC_RSA_PKCS1_PSS_PADDING: - { - RsaKey* key = (RsaKey*)rsa->internal; - enum wc_HashType mgf1, hType; - hType = wc_OidGetHash((int)nid2oid(hashAlg, oidHashType)); - if (mgf1Hash == WC_NID_undef) - mgf1Hash = hashAlg; - mgf1 = wc_OidGetHash((int)nid2oid(mgf1Hash, oidHashType)); - /* handle compat layer salt special cases */ - saltLen = rsa_pss_calc_salt(saltLen, wc_HashGetDigestSize(hType), - wolfSSL_RSA_size(rsa)); - - /* Create RSA PSS signature. */ - if ((signSz = wc_RsaPSS_Sign_ex(encodedSig, encSz, sigRet, outLen, - hType, wc_hash2mgf(mgf1), saltLen, key, rng)) <= 0) { - WOLFSSL_ERROR_MSG("Bad RSA PSS Sign"); - ret = 0; - } - break; - } - #endif - #ifndef WC_NO_RSA_OAEP - case WC_RSA_PKCS1_OAEP_PADDING: - /* Not a signature padding scheme. */ - WOLFSSL_ERROR_MSG("RSA_PKCS1_OAEP_PADDING not supported for " - "signing"); - ret = 0; - break; - #endif - case WC_RSA_PKCS1_PADDING: - { - /* Sign (private encrypt) PKCS#1 encoded signature. */ - if ((signSz = wc_RsaSSL_Sign(encodedSig, encSz, sigRet, outLen, - (RsaKey*)rsa->internal, rng)) <= 0) { - WOLFSSL_ERROR_MSG("Bad PKCS1 RSA Sign"); - ret = 0; - } - break; - } - default: - WOLFSSL_ERROR_MSG("Unsupported padding"); - (void)mgf1Hash; - (void)saltLen; - ret = 0; - break; + /* Dispose of wolfSSL DH key. */ + if (dh->internal) { + wc_FreeDhKey((DhKey*)dh->internal); + XFREE(dh->internal, NULL, DYNAMIC_TYPE_DH); + dh->internal = NULL; } - } - if (ret == 1) { - /* Return the size of signature generated. */ - *sigLen = (unsigned int)signSz; - } + /* Dispose of any allocated BNs. */ + wolfSSL_BN_free(dh->priv_key); + wolfSSL_BN_free(dh->pub_key); + wolfSSL_BN_free(dh->g); + wolfSSL_BN_free(dh->p); + wolfSSL_BN_free(dh->q); + /* Set back to NULLs for safety. */ + XMEMSET(dh, 0, sizeof(WOLFSSL_DH)); - /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ - if (initTmpRng) { - wc_FreeRng(tmpRng); + XFREE(dh, NULL, DYNAMIC_TYPE_DH); } - WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); - WC_FREE_VAR_EX(encodedSig, NULL, DYNAMIC_TYPE_SIGNATURE); - - WOLFSSL_LEAVE("wolfSSL_RSA_sign_mgf", ret); - return ret; } -/** - * Verify a message hash with the chosen message digest, padding, and RSA key. +/* Increments ref count of DH key. * - * @param [in] hashAlg Hash NID - * @param [in] hash Message hash. - * @param [in] mLen Length of message hash. - * @param [in] sigRet Signature data. - * @param [in] sigLen Length of signature data. - * @param [in] rsa RSA key used to sign the input - * @return 1 on success. - * @return 0 on failure. + * @param [in, out] dh DH key. + * @return 1 on success + * @return 0 on error */ -int wolfSSL_RSA_verify(int hashAlg, const unsigned char* hash, - unsigned int hLen, const unsigned char* sig, unsigned int sigLen, - WOLFSSL_RSA* rsa) +int wolfSSL_DH_up_ref(WOLFSSL_DH* dh) { - return wolfSSL_RSA_verify_ex(hashAlg, hash, hLen, sig, sigLen, rsa, - WC_RSA_PKCS1_PADDING); -} + int err = 1; -int wolfSSL_RSA_verify_ex(int hashAlg, const unsigned char* hash, - unsigned int hLen, const unsigned char* sig, unsigned int sigLen, - WOLFSSL_RSA* rsa, int padding) -{ - return wolfSSL_RSA_verify_mgf(hashAlg, hash, hLen, sig, sigLen, rsa, - padding, hashAlg, DEF_PSS_SALT_LEN); + WOLFSSL_ENTER("wolfSSL_DH_up_ref"); + + if (dh != NULL) { + wolfSSL_RefInc(&dh->ref, &err); + } + + return !err; } -/** - * Verify a message hash with the chosen message digest, padding, and RSA key. +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH) || \ + defined(OPENSSL_EXTRA) + +#ifdef WOLFSSL_DH_EXTRA +/* Duplicate the DH key. * - * Not OpenSSL API. + * Internal DH key in 'dh' is updated if necessary. * - * @param [in] hashAlg Hash NID - * @param [in] hash Message hash. - * @param [in] mLen Length of message hash. - * @param [in] sigRet Signature data. - * @param [in] sigLen Length of signature data. - * @param [in] rsa RSA key used to sign the input - * @param [in] padding Padding to use. Only RSA_PKCS1_PSS_PADDING and - * WC_RSA_PKCS1_PADDING are currently supported for - * signing. - * @param [in] mgf1Hash MGF1 Hash NID - * @param [in] saltLen Length of RSA PSS salt - * @return 1 on success. - * @return 0 on failure. + * @param [in, out] dh DH key to duplicate. + * @return NULL on failure. + * @return DH key on success. */ -int wolfSSL_RSA_verify_mgf(int hashAlg, const unsigned char* hash, - unsigned int hLen, const unsigned char* sig, unsigned int sigLen, - WOLFSSL_RSA* rsa, int padding, int mgf1Hash, int saltLen) +WOLFSSL_DH* wolfSSL_DH_dup(WOLFSSL_DH* dh) { - int ret = 1; -#ifdef WOLFSSL_SMALL_STACK - unsigned char* encodedSig = NULL; -#else - unsigned char encodedSig[MAX_ENCODED_SIG_SZ]; -#endif - unsigned char* sigDec = NULL; - unsigned int len = MAX_ENCODED_SIG_SZ; - int verLen = 0; -#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 1)) && !defined(HAVE_SELFTEST) - enum wc_HashType hType = WC_HASH_TYPE_NONE; -#endif + WOLFSSL_DH* ret = NULL; + int err = 0; - WOLFSSL_ENTER("wolfSSL_RSA_verify_mgf"); + WOLFSSL_ENTER("wolfSSL_DH_dup"); /* Validate parameters. */ - if ((hash == NULL) || (sig == NULL) || (rsa == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = 0; + if (dh == NULL) { + WOLFSSL_ERROR_MSG("Bad parameter"); + err = 1; } - if (ret == 1) { - /* Allocate memory for decrypted signature. */ - sigDec = (unsigned char *)XMALLOC(sigLen, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (sigDec == NULL) { - WOLFSSL_ERROR_MSG("Memory allocation failure"); - ret = 0; - } - } - if (ret == 1 && padding == WC_RSA_PKCS1_PSS_PADDING) { - #if defined(WC_RSA_PSS) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,1)) - RsaKey* key = (RsaKey*)rsa->internal; - enum wc_HashType mgf1; - hType = wc_OidGetHash((int)nid2oid(hashAlg, oidHashType)); - if (mgf1Hash == WC_NID_undef) - mgf1Hash = hashAlg; - mgf1 = wc_OidGetHash((int)nid2oid(mgf1Hash, oidHashType)); - - /* handle compat layer salt special cases */ - saltLen = rsa_pss_calc_salt(saltLen, wc_HashGetDigestSize(hType), - wolfSSL_RSA_size(rsa)); - - verLen = wc_RsaPSS_Verify_ex((byte*)sig, sigLen, sigDec, sigLen, - hType, wc_hash2mgf(mgf1), saltLen, key); - if (verLen > 0) { - /* Check PSS padding is valid. */ - if (wc_RsaPSS_CheckPadding_ex(hash, hLen, sigDec, (word32)verLen, - hType, saltLen, mp_count_bits(&key->n)) != 0) { - WOLFSSL_ERROR_MSG("wc_RsaPSS_CheckPadding_ex error"); - ret = WOLFSSL_FAILURE; - } - else { - /* Success! Free resources and return early */ - XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return WOLFSSL_SUCCESS; - } - } - else { - WOLFSSL_ERROR_MSG("wc_RsaPSS_Verify_ex failed!"); - ret = WOLFSSL_FAILURE; - } - #else - (void)mgf1Hash; - (void)saltLen; - WOLFSSL_ERROR_MSG("RSA PSS not compiled in!"); - ret = WOLFSSL_FAILURE; - #endif + /* Ensure internal DH key is set. */ + if ((!err) && (dh->inSet == 0) && (SetDhInternal(dh) != 1)) { + WOLFSSL_ERROR_MSG("Bad DH set internal"); + err = 1; } -#ifdef WOLFSSL_SMALL_STACK - if (ret == 1) { - /* Allocate memory for encoded signature. */ - encodedSig = (unsigned char *)XMALLOC(len, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (encodedSig == NULL) { - WOLFSSL_ERROR_MSG("Memory allocation failure"); - ret = 0; - } - } -#endif - if (ret == 1) { - /* Make encoded signature to compare with decrypted signature. */ - if (wolfssl_rsa_sig_encode(hashAlg, hash, hLen, encodedSig, &len, - padding) <= 0) { - WOLFSSL_ERROR_MSG("Message Digest Error"); - ret = 0; - } + /* Create a new DH key object. */ + if ((!err) && (!(ret = wolfSSL_DH_new()))) { + WOLFSSL_ERROR_MSG("wolfSSL_DH_new error"); + err = 1; } - if (ret == 1) { - /* Decrypt signature */ - #if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 1)) && \ - !defined(HAVE_SELFTEST) - hType = wc_OidGetHash((int)nid2oid(hashAlg, oidHashType)); - if ((verLen = wc_RsaSSL_Verify_ex2(sig, sigLen, (unsigned char *)sigDec, - sigLen, (RsaKey*)rsa->internal, padding, hType)) <= 0) { - WOLFSSL_ERROR_MSG("RSA Decrypt error"); - ret = 0; - } - #else - verLen = wc_RsaSSL_Verify(sig, sigLen, (unsigned char *)sigDec, sigLen, - (RsaKey*)rsa->internal); - if (verLen < 0) { - ret = 0; - } - #endif + /* Copy internal DH key from original to new. */ + if ((!err) && (wc_DhKeyCopy((DhKey*)dh->internal, (DhKey*)ret->internal) != + MP_OKAY)) { + WOLFSSL_ERROR_MSG("wc_DhKeyCopy error"); + err = 1; } - if (ret == 1) { - /* Compare decrypted signature to encoded signature. */ - if (((int)len != verLen) || - (XMEMCMP(encodedSig, sigDec, (size_t)verLen) != 0)) { - WOLFSSL_ERROR_MSG("wolfSSL_RSA_verify_ex failed"); - ret = 0; + if (!err) { + ret->inSet = 1; + + /* Synchronize the internal into external DH key's parameters. */ + if (SetDhExternal(ret) != 1) { + WOLFSSL_ERROR_MSG("SetDhExternal error"); + err = 1; } } - /* Dispose of any allocated data. */ - WC_FREE_VAR_EX(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER); - - WOLFSSL_LEAVE("wolfSSL_RSA_verify_mgf", ret); + /* Dispose of any allocated DH key on error. */ + if (err && (ret != NULL)) { + wolfSSL_DH_free(ret); + ret = NULL; + } return ret; } +#endif /* WOLFSSL_DH_EXTRA */ -/* - * RSA public/private encrypt/decrypt APIs - */ +#endif -/* Encrypt with the RSA public key. +/* Allocate and initialize a new DH key with 2048-bit parameters. * - * Return compliant with OpenSSL. + * See RFC 5114 section 2.3, "2048-bit MODP Group with 256-bit Prime Order + * Subgroup." * - * @param [in] len Length of data to encrypt. - * @param [in] from Data to encrypt. - * @param [out] to Encrypted data. - * @param [in] rsa RSA key. - * @param [in] padding Type of padding to place around plaintext. - * @return Size of encrypted data on success. - * @return -1 on failure. + * @return NULL on failure. + * @return DH Key on success. */ -int wolfSSL_RSA_public_encrypt(int len, const unsigned char* from, - unsigned char* to, WOLFSSL_RSA* rsa, int padding) +WOLFSSL_DH* wolfSSL_DH_get_2048_256(void) { - int ret = 0; - int initTmpRng = 0; - WC_RNG *rng = NULL; -#ifdef WOLFSSL_SMALL_STACK - WC_RNG* tmpRng = NULL; -#else - WC_RNG _tmpRng[1]; - WC_RNG* tmpRng = _tmpRng; -#endif -#if !defined(HAVE_FIPS) - int mgf = WC_MGF1NONE; - enum wc_HashType hash = WC_HASH_TYPE_NONE; - int pad_type = WC_RSA_NO_PAD; -#endif - int outLen = 0; - - WOLFSSL_ENTER("wolfSSL_RSA_public_encrypt"); + WOLFSSL_DH* dh; + int err = 0; + static const byte pHex[] = { + 0x87, 0xA8, 0xE6, 0x1D, 0xB4, 0xB6, 0x66, 0x3C, 0xFF, 0xBB, 0xD1, 0x9C, + 0x65, 0x19, 0x59, 0x99, 0x8C, 0xEE, 0xF6, 0x08, 0x66, 0x0D, 0xD0, 0xF2, + 0x5D, 0x2C, 0xEE, 0xD4, 0x43, 0x5E, 0x3B, 0x00, 0xE0, 0x0D, 0xF8, 0xF1, + 0xD6, 0x19, 0x57, 0xD4, 0xFA, 0xF7, 0xDF, 0x45, 0x61, 0xB2, 0xAA, 0x30, + 0x16, 0xC3, 0xD9, 0x11, 0x34, 0x09, 0x6F, 0xAA, 0x3B, 0xF4, 0x29, 0x6D, + 0x83, 0x0E, 0x9A, 0x7C, 0x20, 0x9E, 0x0C, 0x64, 0x97, 0x51, 0x7A, 0xBD, + 0x5A, 0x8A, 0x9D, 0x30, 0x6B, 0xCF, 0x67, 0xED, 0x91, 0xF9, 0xE6, 0x72, + 0x5B, 0x47, 0x58, 0xC0, 0x22, 0xE0, 0xB1, 0xEF, 0x42, 0x75, 0xBF, 0x7B, + 0x6C, 0x5B, 0xFC, 0x11, 0xD4, 0x5F, 0x90, 0x88, 0xB9, 0x41, 0xF5, 0x4E, + 0xB1, 0xE5, 0x9B, 0xB8, 0xBC, 0x39, 0xA0, 0xBF, 0x12, 0x30, 0x7F, 0x5C, + 0x4F, 0xDB, 0x70, 0xC5, 0x81, 0xB2, 0x3F, 0x76, 0xB6, 0x3A, 0xCA, 0xE1, + 0xCA, 0xA6, 0xB7, 0x90, 0x2D, 0x52, 0x52, 0x67, 0x35, 0x48, 0x8A, 0x0E, + 0xF1, 0x3C, 0x6D, 0x9A, 0x51, 0xBF, 0xA4, 0xAB, 0x3A, 0xD8, 0x34, 0x77, + 0x96, 0x52, 0x4D, 0x8E, 0xF6, 0xA1, 0x67, 0xB5, 0xA4, 0x18, 0x25, 0xD9, + 0x67, 0xE1, 0x44, 0xE5, 0x14, 0x05, 0x64, 0x25, 0x1C, 0xCA, 0xCB, 0x83, + 0xE6, 0xB4, 0x86, 0xF6, 0xB3, 0xCA, 0x3F, 0x79, 0x71, 0x50, 0x60, 0x26, + 0xC0, 0xB8, 0x57, 0xF6, 0x89, 0x96, 0x28, 0x56, 0xDE, 0xD4, 0x01, 0x0A, + 0xBD, 0x0B, 0xE6, 0x21, 0xC3, 0xA3, 0x96, 0x0A, 0x54, 0xE7, 0x10, 0xC3, + 0x75, 0xF2, 0x63, 0x75, 0xD7, 0x01, 0x41, 0x03, 0xA4, 0xB5, 0x43, 0x30, + 0xC1, 0x98, 0xAF, 0x12, 0x61, 0x16, 0xD2, 0x27, 0x6E, 0x11, 0x71, 0x5F, + 0x69, 0x38, 0x77, 0xFA, 0xD7, 0xEF, 0x09, 0xCA, 0xDB, 0x09, 0x4A, 0xE9, + 0x1E, 0x1A, 0x15, 0x97 + }; + static const byte gHex[] = { + 0x3F, 0xB3, 0x2C, 0x9B, 0x73, 0x13, 0x4D, 0x0B, 0x2E, 0x77, 0x50, 0x66, + 0x60, 0xED, 0xBD, 0x48, 0x4C, 0xA7, 0xB1, 0x8F, 0x21, 0xEF, 0x20, 0x54, + 0x07, 0xF4, 0x79, 0x3A, 0x1A, 0x0B, 0xA1, 0x25, 0x10, 0xDB, 0xC1, 0x50, + 0x77, 0xBE, 0x46, 0x3F, 0xFF, 0x4F, 0xED, 0x4A, 0xAC, 0x0B, 0xB5, 0x55, + 0xBE, 0x3A, 0x6C, 0x1B, 0x0C, 0x6B, 0x47, 0xB1, 0xBC, 0x37, 0x73, 0xBF, + 0x7E, 0x8C, 0x6F, 0x62, 0x90, 0x12, 0x28, 0xF8, 0xC2, 0x8C, 0xBB, 0x18, + 0xA5, 0x5A, 0xE3, 0x13, 0x41, 0x00, 0x0A, 0x65, 0x01, 0x96, 0xF9, 0x31, + 0xC7, 0x7A, 0x57, 0xF2, 0xDD, 0xF4, 0x63, 0xE5, 0xE9, 0xEC, 0x14, 0x4B, + 0x77, 0x7D, 0xE6, 0x2A, 0xAA, 0xB8, 0xA8, 0x62, 0x8A, 0xC3, 0x76, 0xD2, + 0x82, 0xD6, 0xED, 0x38, 0x64, 0xE6, 0x79, 0x82, 0x42, 0x8E, 0xBC, 0x83, + 0x1D, 0x14, 0x34, 0x8F, 0x6F, 0x2F, 0x91, 0x93, 0xB5, 0x04, 0x5A, 0xF2, + 0x76, 0x71, 0x64, 0xE1, 0xDF, 0xC9, 0x67, 0xC1, 0xFB, 0x3F, 0x2E, 0x55, + 0xA4, 0xBD, 0x1B, 0xFF, 0xE8, 0x3B, 0x9C, 0x80, 0xD0, 0x52, 0xB9, 0x85, + 0xD1, 0x82, 0xEA, 0x0A, 0xDB, 0x2A, 0x3B, 0x73, 0x13, 0xD3, 0xFE, 0x14, + 0xC8, 0x48, 0x4B, 0x1E, 0x05, 0x25, 0x88, 0xB9, 0xB7, 0xD2, 0xBB, 0xD2, + 0xDF, 0x01, 0x61, 0x99, 0xEC, 0xD0, 0x6E, 0x15, 0x57, 0xCD, 0x09, 0x15, + 0xB3, 0x35, 0x3B, 0xBB, 0x64, 0xE0, 0xEC, 0x37, 0x7F, 0xD0, 0x28, 0x37, + 0x0D, 0xF9, 0x2B, 0x52, 0xC7, 0x89, 0x14, 0x28, 0xCD, 0xC6, 0x7E, 0xB6, + 0x18, 0x4B, 0x52, 0x3D, 0x1D, 0xB2, 0x46, 0xC3, 0x2F, 0x63, 0x07, 0x84, + 0x90, 0xF0, 0x0E, 0xF8, 0xD6, 0x47, 0xD1, 0x48, 0xD4, 0x79, 0x54, 0x51, + 0x5E, 0x23, 0x27, 0xCF, 0xEF, 0x98, 0xC5, 0x82, 0x66, 0x4B, 0x4C, 0x0F, + 0x6C, 0xC4, 0x16, 0x59 + }; + static const byte qHex[] = { + 0x8C, 0xF8, 0x36, 0x42, 0xA7, 0x09, 0xA0, 0x97, 0xB4, 0x47, 0x99, 0x76, + 0x40, 0x12, 0x9D, 0xA2, 0x99, 0xB1, 0xA4, 0x7D, 0x1E, 0xB3, 0x75, 0x0B, + 0xA3, 0x08, 0xB0, 0xFE, 0x64, 0xF5, 0xFB, 0xD3 + }; - /* Validate parameters. */ - if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || - (from == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = WOLFSSL_FATAL_ERROR; + /* Create a new DH key to return. */ + dh = wolfSSL_DH_new(); + if (dh == NULL) { + err = 1; } - - if (ret == 0) { - #if !defined(HAVE_FIPS) - /* Convert to wolfCrypt padding, hash and MGF. */ - switch (padding) { - case WC_RSA_PKCS1_PADDING: - pad_type = WC_RSA_PKCSV15_PAD; - break; - case WC_RSA_PKCS1_OAEP_PADDING: - pad_type = WC_RSA_OAEP_PAD; - hash = WC_HASH_TYPE_SHA; - mgf = WC_MGF1SHA1; - break; - case WC_RSA_NO_PAD: - pad_type = WC_RSA_NO_PAD; - break; - default: - WOLFSSL_ERROR_MSG("RSA_public_encrypt doesn't support padding " - "scheme"); - ret = WOLFSSL_FATAL_ERROR; - } - #else - /* Check for supported padding schemes in FIPS. */ - /* TODO: Do we support more schemes in later versions of FIPS? */ - if (padding != WC_RSA_PKCS1_PADDING) { - WOLFSSL_ERROR_MSG("RSA_public_encrypt pad type not supported in " - "FIPS"); - ret = WOLFSSL_FATAL_ERROR; + if (!err) { + /* Set prime. */ + dh->p = wolfSSL_BN_bin2bn(pHex, (int)sizeof(pHex), NULL); + if (dh->p == NULL) { + WOLFSSL_ERROR_MSG("Error converting p hex to WOLFSSL_BIGNUM."); + err = 1; } - #endif - } - - /* Set wolfCrypt RSA key data from external if not already done. */ - if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { - ret = WOLFSSL_FATAL_ERROR; } - - if (ret == 0) { - /* Calculate maximum length of encrypted data. */ - outLen = wolfSSL_RSA_size(rsa); - if (outLen == 0) { - WOLFSSL_ERROR_MSG("Bad RSA size"); - ret = WOLFSSL_FATAL_ERROR; + if (!err) { + /* Set generator. */ + dh->g = wolfSSL_BN_bin2bn(gHex, (int)sizeof(gHex), NULL); + if (dh->g == NULL) { + WOLFSSL_ERROR_MSG("Error converting g hex to WOLFSSL_BIGNUM."); + err = 1; } } - - if (ret == 0) { - /* Get an RNG. */ - rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); - if (rng == NULL) { - ret = WOLFSSL_FATAL_ERROR; + if (!err) { + /* Set order. */ + dh->q = wolfSSL_BN_bin2bn(qHex, (int)sizeof(qHex), NULL); + if (dh->q == NULL) { + WOLFSSL_ERROR_MSG("Error converting q hex to WOLFSSL_BIGNUM."); + err = 1; } } - - if (ret == 0) { - /* Use wolfCrypt to public-encrypt with RSA key. */ - #if !defined(HAVE_FIPS) - ret = wc_RsaPublicEncrypt_ex(from, (word32)len, to, (word32)outLen, - (RsaKey*)rsa->internal, rng, pad_type, hash, mgf, NULL, 0); - #else - ret = wc_RsaPublicEncrypt(from, (word32)len, to, (word32)outLen, - (RsaKey*)rsa->internal, rng); - #endif + /* Set values into wolfSSL DH key. */ + if ((!err) && (SetDhInternal(dh) != 1)) { + WOLFSSL_ERROR_MSG("Error setting DH parameters."); + err = 1; } - - /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ - if (initTmpRng) { - wc_FreeRng(tmpRng); + if (!err) { + /* External DH key parameters were set. */ + dh->exSet = 1; } - WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); - /* wolfCrypt error means return -1. */ - if (ret <= 0) { - ret = WOLFSSL_FATAL_ERROR; + /* Dispose of any allocated DH key on error. */ + if (err && (dh != NULL)) { + wolfSSL_DH_free(dh); + dh = NULL; } - WOLFSSL_LEAVE("wolfSSL_RSA_public_encrypt", ret); - return ret; + + return dh; } -/* Decrypt with the RSA public key. +/* TODO: consider changing strings to byte arrays. */ + +/* Returns a big number with the 768-bit prime from RFC 2409. * - * Return compliant with OpenSSL. + * @param [in, out] bn If not NULL then this BN is set and returned. + * If NULL then a new BN is created, set and returned. * - * @param [in] len Length of encrypted data. - * @param [in] from Encrypted data. - * @param [out] to Decrypted data. - * @param [in] rsa RSA key. - * @param [in] padding Type of padding to around plaintext to remove. - * @return Size of decrypted data on success. - * @return -1 on failure. + * @return NULL on failure. + * @return WOLFSSL_BIGNUM with value set to 768-bit prime on success. */ -int wolfSSL_RSA_private_decrypt(int len, const unsigned char* from, - unsigned char* to, WOLFSSL_RSA* rsa, int padding) +WOLFSSL_BIGNUM* wolfSSL_DH_768_prime(WOLFSSL_BIGNUM* bn) { - int ret = 0; -#if !defined(HAVE_FIPS) - int mgf = WC_MGF1NONE; - enum wc_HashType hash = WC_HASH_TYPE_NONE; - int pad_type = WC_RSA_NO_PAD; -#endif - int outLen = 0; - - WOLFSSL_ENTER("wolfSSL_RSA_private_decrypt"); - - /* Validate parameters. */ - if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || - (from == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 0) { - #if !defined(HAVE_FIPS) - switch (padding) { - case WC_RSA_PKCS1_PADDING: - pad_type = WC_RSA_PKCSV15_PAD; - break; - case WC_RSA_PKCS1_OAEP_PADDING: - pad_type = WC_RSA_OAEP_PAD; - hash = WC_HASH_TYPE_SHA; - mgf = WC_MGF1SHA1; - break; - case WC_RSA_NO_PAD: - pad_type = WC_RSA_NO_PAD; - break; - default: - WOLFSSL_ERROR_MSG("RSA_private_decrypt unsupported padding"); - ret = WOLFSSL_FATAL_ERROR; - } - #else - /* Check for supported padding schemes in FIPS. */ - /* TODO: Do we support more schemes in later versions of FIPS? */ - if (padding != WC_RSA_PKCS1_PADDING) { - WOLFSSL_ERROR_MSG("RSA_public_encrypt pad type not supported in " - "FIPS"); - ret = WOLFSSL_FATAL_ERROR; - } - #endif - } - - /* Set wolfCrypt RSA key data from external if not already done. */ - if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { - ret = WOLFSSL_FATAL_ERROR; - } +#if WOLFSSL_MAX_BN_BITS >= 768 + static const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A63A3620FFFFFFFFFFFFFFFF" + }; - if (ret == 0) { - /* Calculate maximum length of decrypted data. */ - outLen = wolfSSL_RSA_size(rsa); - if (outLen == 0) { - WOLFSSL_ERROR_MSG("Bad RSA size"); - ret = WOLFSSL_FATAL_ERROR; - } - } + WOLFSSL_ENTER("wolfSSL_DH_768_prime"); - if (ret == 0) { - /* Use wolfCrypt to private-decrypt with RSA key. - * Size of 'to' buffer must be size of RSA key */ - #if !defined(HAVE_FIPS) - ret = wc_RsaPrivateDecrypt_ex(from, (word32)len, to, (word32)outLen, - (RsaKey*)rsa->internal, pad_type, hash, mgf, NULL, 0); - #else - ret = wc_RsaPrivateDecrypt(from, (word32)len, to, (word32)outLen, - (RsaKey*)rsa->internal); - #endif + /* Set prime into BN. Creates a new BN when bn is NULL. */ + if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { + WOLFSSL_ERROR_MSG("Error converting DH 768 prime to big number"); + bn = NULL; } - /* wolfCrypt error means return -1. */ - if (ret <= 0) { - ret = WOLFSSL_FATAL_ERROR; - } - WOLFSSL_LEAVE("wolfSSL_RSA_private_decrypt", ret); - return ret; + return bn; +#else + (void)bn; + return NULL; +#endif } -/* Decrypt with the RSA public key. +/* Returns a big number with the 1024-bit prime from RFC 2409. * - * @param [in] len Length of encrypted data. - * @param [in] from Encrypted data. - * @param [out] to Decrypted data. - * @param [in] rsa RSA key. - * @param [in] padding Type of padding to around plaintext to remove. - * @return Size of decrypted data on success. - * @return -1 on failure. + * @param [in, out] bn If not NULL then this BN is set and returned. + * If NULL then a new BN is created, set and returned. + * + * @return NULL on failure. + * @return WOLFSSL_BIGNUM with value set to 1024-bit prime on success. */ -int wolfSSL_RSA_public_decrypt(int len, const unsigned char* from, - unsigned char* to, WOLFSSL_RSA* rsa, int padding) +WOLFSSL_BIGNUM* wolfSSL_DH_1024_prime(WOLFSSL_BIGNUM* bn) { - int ret = 0; -#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - int pad_type = WC_RSA_NO_PAD; -#endif - int outLen = 0; - - WOLFSSL_ENTER("wolfSSL_RSA_public_decrypt"); - - /* Validate parameters. */ - if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || - (from == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 0) { - #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - switch (padding) { - case WC_RSA_PKCS1_PADDING: - pad_type = WC_RSA_PKCSV15_PAD; - break; - case WC_RSA_NO_PAD: - pad_type = WC_RSA_NO_PAD; - break; - /* TODO: RSA_X931_PADDING not supported */ - default: - WOLFSSL_ERROR_MSG("RSA_public_decrypt unsupported padding"); - ret = WOLFSSL_FATAL_ERROR; - } - #else - if (padding != WC_RSA_PKCS1_PADDING) { - WOLFSSL_ERROR_MSG("RSA_public_decrypt pad type not supported in " - "FIPS"); - ret = WOLFSSL_FATAL_ERROR; - } - #endif - } - - /* Set wolfCrypt RSA key data from external if not already done. */ - if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { - ret = WOLFSSL_FATAL_ERROR; - } +#if WOLFSSL_MAX_BN_BITS >= 1024 + static const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE65381FFFFFFFFFFFFFFFF" + }; - if (ret == 0) { - /* Calculate maximum length of encrypted data. */ - outLen = wolfSSL_RSA_size(rsa); - if (outLen == 0) { - WOLFSSL_ERROR_MSG("Bad RSA size"); - ret = WOLFSSL_FATAL_ERROR; - } - } + WOLFSSL_ENTER("wolfSSL_DH_1024_prime"); - if (ret == 0) { - /* Use wolfCrypt to public-decrypt with RSA key. */ - #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - /* Size of 'to' buffer must be size of RSA key. */ - ret = wc_RsaSSL_Verify_ex(from, (word32)len, to, (word32)outLen, - (RsaKey*)rsa->internal, pad_type); - #else - /* For FIPS v1/v2 only PKCSV15 padding is supported */ - ret = wc_RsaSSL_Verify(from, (word32)len, to, (word32)outLen, - (RsaKey*)rsa->internal); - #endif + /* Set prime into BN. Creates a new BN when bn is NULL. */ + if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { + WOLFSSL_ERROR_MSG("Error converting DH 1024 prime to big number"); + bn = NULL; } - /* wolfCrypt error means return -1. */ - if (ret <= 0) { - ret = WOLFSSL_FATAL_ERROR; - } - WOLFSSL_LEAVE("wolfSSL_RSA_public_decrypt", ret); - return ret; + return bn; +#else + (void)bn; + return NULL; +#endif } -/* Encrypt with the RSA private key. +/* Returns a big number with the 1536-bit prime from RFC 3526. * - * Calls wc_RsaSSL_Sign. + * @param [in, out] bn If not NULL then this BN is set and returned. + * If NULL then a new BN is created, set and returned. * - * @param [in] len Length of data to encrypt. - * @param [in] from Data to encrypt. - * @param [out] to Encrypted data. - * @param [in] rsa RSA key. - * @param [in] padding Type of padding to place around plaintext. - * @return Size of encrypted data on success. - * @return -1 on failure. + * @return NULL on failure. + * @return WOLFSSL_BIGNUM with value set to 1536-bit prime on success. */ -int wolfSSL_RSA_private_encrypt(int len, const unsigned char* from, - unsigned char* to, WOLFSSL_RSA* rsa, int padding) +WOLFSSL_BIGNUM* wolfSSL_DH_1536_prime(WOLFSSL_BIGNUM* bn) { - int ret = 0; - int initTmpRng = 0; - WC_RNG *rng = NULL; -#ifdef WOLFSSL_SMALL_STACK - WC_RNG* tmpRng = NULL; -#else - WC_RNG _tmpRng[1]; - WC_RNG* tmpRng = _tmpRng; -#endif - - WOLFSSL_ENTER("wolfSSL_RSA_private_encrypt"); - - /* Validate parameters. */ - if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || - (from == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 0) { - switch (padding) { - case WC_RSA_PKCS1_PADDING: - #ifdef WC_RSA_NO_PADDING - case WC_RSA_NO_PAD: - #endif - break; - /* TODO: RSA_X931_PADDING not supported */ - default: - WOLFSSL_ERROR_MSG("RSA_private_encrypt unsupported padding"); - ret = WOLFSSL_FATAL_ERROR; - } - } - - /* Set wolfCrypt RSA key data from external if not already done. */ - if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 0) { - /* Get an RNG. */ - rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); - if (rng == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - } +#if WOLFSSL_MAX_BN_BITS >= 1536 + static const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF05" + "98DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB" + "9ED529077096966D670C354E4ABC9804" + "F1746C08CA237327FFFFFFFFFFFFFFFF" + }; - if (ret == 0) { - /* Use wolfCrypt to private-encrypt with RSA key. - * Size of output buffer must be size of RSA key. */ - if (padding == WC_RSA_PKCS1_PADDING) { - ret = wc_RsaSSL_Sign(from, (word32)len, to, - (word32)wolfSSL_RSA_size(rsa), (RsaKey*)rsa->internal, rng); - } - #ifdef WC_RSA_NO_PADDING - else if (padding == WC_RSA_NO_PAD) { - word32 outLen = (word32)wolfSSL_RSA_size(rsa); - ret = wc_RsaFunction(from, (word32)len, to, &outLen, - RSA_PRIVATE_ENCRYPT, (RsaKey*)rsa->internal, rng); - if (ret == 0) - ret = (int)outLen; - } - #endif - } + WOLFSSL_ENTER("wolfSSL_DH_1536_prime"); - /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ - if (initTmpRng) { - wc_FreeRng(tmpRng); + /* Set prime into BN. Creates a new BN when bn is NULL. */ + if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { + WOLFSSL_ERROR_MSG("Error converting DH 1536 prime to big number"); + bn = NULL; } - WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); - /* wolfCrypt error means return -1. */ - if (ret <= 0) { - ret = WOLFSSL_FATAL_ERROR; - } - WOLFSSL_LEAVE("wolfSSL_RSA_private_encrypt", ret); - return ret; + return bn; +#else + (void)bn; + return NULL; +#endif } -/* - * RSA misc operation APIs - */ - -/* Calculate d mod p-1 and q-1 into BNs. +/* Returns a big number with the 2048-bit prime from RFC 3526. * - * Not OpenSSL API. + * @param [in, out] bn If not NULL then this BN is set and returned. + * If NULL then a new BN is created, set and returned. * - * @param [in, out] rsa RSA key. - * @return 1 on success. - * @return -1 on failure. + * @return NULL on failure. + * @return WOLFSSL_BIGNUM with value set to 2048-bit prime on success. */ -int wolfSSL_RSA_GenAdd(WOLFSSL_RSA* rsa) +WOLFSSL_BIGNUM* wolfSSL_DH_2048_prime(WOLFSSL_BIGNUM* bn) { - int ret = 1; - int err; - mp_int* t = NULL; - WC_DECLARE_VAR(tmp, mp_int, 1, 0); +#if WOLFSSL_MAX_BN_BITS >= 2048 + static const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF05" + "98DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB" + "9ED529077096966D670C354E4ABC9804" + "F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28F" + "B5C55DF06F4C52C9DE2BCBF695581718" + "3995497CEA956AE515D2261898FA0510" + "15728E5A8AACAA68FFFFFFFFFFFFFFFF" + }; - WOLFSSL_ENTER("wolfSSL_RsaGenAdd"); + WOLFSSL_ENTER("wolfSSL_DH_2048_prime"); - /* Validate parameters. */ - if ((rsa == NULL) || (rsa->p == NULL) || (rsa->q == NULL) || - (rsa->d == NULL) || (rsa->dmp1 == NULL) || (rsa->dmq1 == NULL)) { - WOLFSSL_ERROR_MSG("rsa no init error"); - ret = WOLFSSL_FATAL_ERROR; + /* Set prime into BN. Creates a new BN when bn is NULL. */ + if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { + WOLFSSL_ERROR_MSG("Error converting DH 2048 prime to big number"); + bn = NULL; } -#ifdef WOLFSSL_SMALL_STACK - if (ret == 1) { - tmp = (mp_int *)XMALLOC(sizeof(*tmp), rsa->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (tmp == NULL) { - WOLFSSL_ERROR_MSG("Memory allocation failure"); - ret = WOLFSSL_FATAL_ERROR; - } - } + return bn; +#else + (void)bn; + return NULL; #endif +} - if (ret == 1) { - /* Initialize temp MP integer. */ - if (mp_init(tmp) != MP_OKAY) { - WOLFSSL_ERROR_MSG("mp_init error"); - ret = WOLFSSL_FATAL_ERROR; - } - } +/* Returns a big number with the 3072-bit prime from RFC 3526. + * + * @param [in, out] bn If not NULL then this BN is set and returned. + * If NULL then a new BN is created, set and returned. + * + * @return NULL on failure. + * @return WOLFSSL_BIGNUM with value set to 3072-bit prime on success. + */ +WOLFSSL_BIGNUM* wolfSSL_DH_3072_prime(WOLFSSL_BIGNUM* bn) +{ +#if WOLFSSL_MAX_BN_BITS >= 3072 + static const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF05" + "98DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB" + "9ED529077096966D670C354E4ABC9804" + "F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28F" + "B5C55DF06F4C52C9DE2BCBF695581718" + "3995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33" + "A85521ABDF1CBA64ECFB850458DBEF0A" + "8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619D" + "CEE3D2261AD2EE6BF12FFA06D98A0864" + "D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E2" + "08E24FA074E5AB3143DB5BFCE0FD108E" + "4B82D120A93AD2CAFFFFFFFFFFFFFFFF" + }; - if (ret == 1) { - t = tmp; + WOLFSSL_ENTER("wolfSSL_DH_3072_prime"); - /* Sub 1 from p into temp. */ - err = mp_sub_d((mp_int*)rsa->p->internal, 1, tmp); - if (err != MP_OKAY) { - WOLFSSL_ERROR_MSG("mp_sub_d error"); - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 1) { - /* Calculate d mod (p - 1) into dmp1 MP integer of BN. */ - err = mp_mod((mp_int*)rsa->d->internal, tmp, - (mp_int*)rsa->dmp1->internal); - if (err != MP_OKAY) { - WOLFSSL_ERROR_MSG("mp_mod error"); - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 1) { - /* Sub 1 from q into temp. */ - err = mp_sub_d((mp_int*)rsa->q->internal, 1, tmp); - if (err != MP_OKAY) { - WOLFSSL_ERROR_MSG("mp_sub_d error"); - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 1) { - /* Calculate d mod (q - 1) into dmq1 MP integer of BN. */ - err = mp_mod((mp_int*)rsa->d->internal, tmp, - (mp_int*)rsa->dmq1->internal); - if (err != MP_OKAY) { - WOLFSSL_ERROR_MSG("mp_mod error"); - ret = WOLFSSL_FATAL_ERROR; - } + /* Set prime into BN. Creates a new BN when bn is NULL. */ + if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { + WOLFSSL_ERROR_MSG("Error converting DH 3072 prime to big number"); + bn = NULL; } - mp_clear(t); - -#ifdef WOLFSSL_SMALL_STACK - if (rsa != NULL) { - XFREE(tmp, rsa->heap, DYNAMIC_TYPE_TMP_BUFFER); - } + return bn; +#else + (void)bn; + return NULL; #endif - - return ret; } - -#ifndef NO_WOLFSSL_STUB -/* Enable blinding for RSA key operations. +/* Returns a big number with the 4096-bit prime from RFC 3526. * - * Blinding is a compile time option in wolfCrypt. + * @param [in, out] bn If not NULL then this BN is set and returned. + * If NULL then a new BN is created, set and returned. * - * @param [in] rsa RSA key. Unused. - * @param [in] bnCtx BN context to use for blinding. Unused. - * @return 1 always. + * @return NULL on failure. + * @return WOLFSSL_BIGNUM with value set to 4096-bit prime on success. */ -int wolfSSL_RSA_blinding_on(WOLFSSL_RSA* rsa, WOLFSSL_BN_CTX* bnCtx) +WOLFSSL_BIGNUM* wolfSSL_DH_4096_prime(WOLFSSL_BIGNUM* bn) { - WOLFSSL_STUB("RSA_blinding_on"); - WOLFSSL_ENTER("wolfSSL_RSA_blinding_on"); - - (void)rsa; - (void)bnCtx; - - return 1; /* on by default */ -} -#endif - -#endif /* OPENSSL_EXTRA */ - -#endif /* !NO_RSA */ - -/******************************************************************************* - * END OF RSA API - ******************************************************************************/ - - -/******************************************************************************* - * START OF DSA API - ******************************************************************************/ - -#ifndef NO_DSA - -#if defined(OPENSSL_EXTRA) && defined(XFPRINTF) && !defined(NO_FILESYSTEM) && \ - !defined(NO_STDIO_FILESYSTEM) -/* return code compliant with OpenSSL : - * 1 if success, 0 if error - */ -int wolfSSL_DSA_print_fp(XFILE fp, WOLFSSL_DSA* dsa, int indent) -{ - int ret = 1; - - WOLFSSL_ENTER("wolfSSL_DSA_print_fp"); - - if (fp == XBADFILE || dsa == NULL) { - ret = 0; - } - - if (ret == 1 && dsa->p != NULL) { - int pBits = wolfSSL_BN_num_bits(dsa->p); - if (pBits == 0) { - ret = 0; - } - else { - if (XFPRINTF(fp, "%*s", indent, "") < 0) - ret = 0; - else if (XFPRINTF(fp, "Private-Key: (%d bit)\n", pBits) < 0) - ret = 0; - } - } - if (ret == 1 && dsa->priv_key != NULL) { - ret = pk_bn_field_print_fp(fp, indent, "priv", dsa->priv_key); - } - if (ret == 1 && dsa->pub_key != NULL) { - ret = pk_bn_field_print_fp(fp, indent, "pub", dsa->pub_key); - } - if (ret == 1 && dsa->p != NULL) { - ret = pk_bn_field_print_fp(fp, indent, "P", dsa->p); - } - if (ret == 1 && dsa->q != NULL) { - ret = pk_bn_field_print_fp(fp, indent, "Q", dsa->q); - } - if (ret == 1 && dsa->g != NULL) { - ret = pk_bn_field_print_fp(fp, indent, "G", dsa->g); - } - - WOLFSSL_LEAVE("wolfSSL_DSA_print_fp", ret); - - return ret; -} -#endif /* OPENSSL_EXTRA && XSNPRINTF && !NO_FILESYSTEM && NO_STDIO_FILESYSTEM */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -static void InitwolfSSL_DSA(WOLFSSL_DSA* dsa) -{ - if (dsa) { - dsa->p = NULL; - dsa->q = NULL; - dsa->g = NULL; - dsa->pub_key = NULL; - dsa->priv_key = NULL; - dsa->internal = NULL; - dsa->inSet = 0; - dsa->exSet = 0; - } -} - - -WOLFSSL_DSA* wolfSSL_DSA_new(void) -{ - WOLFSSL_DSA* external; - DsaKey* key; - - WOLFSSL_MSG("wolfSSL_DSA_new"); - - key = (DsaKey*) XMALLOC(sizeof(DsaKey), NULL, DYNAMIC_TYPE_DSA); - if (key == NULL) { - WOLFSSL_MSG("wolfSSL_DSA_new malloc DsaKey failure"); - return NULL; - } - - external = (WOLFSSL_DSA*) XMALLOC(sizeof(WOLFSSL_DSA), NULL, - DYNAMIC_TYPE_DSA); - if (external == NULL) { - WOLFSSL_MSG("wolfSSL_DSA_new malloc WOLFSSL_DSA failure"); - XFREE(key, NULL, DYNAMIC_TYPE_DSA); - return NULL; - } - - InitwolfSSL_DSA(external); - if (wc_InitDsaKey(key) != 0) { - WOLFSSL_MSG("wolfSSL_DSA_new InitDsaKey failure"); - XFREE(key, NULL, DYNAMIC_TYPE_DSA); - wolfSSL_DSA_free(external); - return NULL; - } - external->internal = key; - - return external; -} - - -void wolfSSL_DSA_free(WOLFSSL_DSA* dsa) -{ - WOLFSSL_MSG("wolfSSL_DSA_free"); - - if (dsa) { - if (dsa->internal) { - FreeDsaKey((DsaKey*)dsa->internal); - XFREE(dsa->internal, NULL, DYNAMIC_TYPE_DSA); - dsa->internal = NULL; - } - wolfSSL_BN_free(dsa->priv_key); - wolfSSL_BN_free(dsa->pub_key); - wolfSSL_BN_free(dsa->g); - wolfSSL_BN_free(dsa->q); - wolfSSL_BN_free(dsa->p); - InitwolfSSL_DSA(dsa); /* set back to NULLs for safety */ - - XFREE(dsa, NULL, DYNAMIC_TYPE_DSA); - - /* dsa = NULL, don't try to access or double free it */ - } -} - -/* wolfSSL -> OpenSSL */ -int SetDsaExternal(WOLFSSL_DSA* dsa) -{ - DsaKey* key; - WOLFSSL_MSG("Entering SetDsaExternal"); - - if (dsa == NULL || dsa->internal == NULL) { - WOLFSSL_MSG("dsa key NULL error"); - return WOLFSSL_FATAL_ERROR; - } - - key = (DsaKey*)dsa->internal; - - if (wolfssl_bn_set_value(&dsa->p, &key->p) != 1) { - WOLFSSL_MSG("dsa p key error"); - return WOLFSSL_FATAL_ERROR; - } - - if (wolfssl_bn_set_value(&dsa->q, &key->q) != 1) { - WOLFSSL_MSG("dsa q key error"); - return WOLFSSL_FATAL_ERROR; - } - - if (wolfssl_bn_set_value(&dsa->g, &key->g) != 1) { - WOLFSSL_MSG("dsa g key error"); - return WOLFSSL_FATAL_ERROR; - } - - if (wolfssl_bn_set_value(&dsa->pub_key, &key->y) != 1) { - WOLFSSL_MSG("dsa y key error"); - return WOLFSSL_FATAL_ERROR; - } - - if (wolfssl_bn_set_value(&dsa->priv_key, &key->x) != 1) { - WOLFSSL_MSG("dsa x key error"); - return WOLFSSL_FATAL_ERROR; - } - - dsa->exSet = 1; - - return 1; -} -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - -#ifdef OPENSSL_EXTRA -/* Openssl -> WolfSSL */ -int SetDsaInternal(WOLFSSL_DSA* dsa) -{ - DsaKey* key; - WOLFSSL_MSG("Entering SetDsaInternal"); - - if (dsa == NULL || dsa->internal == NULL) { - WOLFSSL_MSG("dsa key NULL error"); - return WOLFSSL_FATAL_ERROR; - } - - key = (DsaKey*)dsa->internal; - - if (dsa->p != NULL && - wolfssl_bn_get_value(dsa->p, &key->p) != 1) { - WOLFSSL_MSG("rsa p key error"); - return WOLFSSL_FATAL_ERROR; - } - - if (dsa->q != NULL && - wolfssl_bn_get_value(dsa->q, &key->q) != 1) { - WOLFSSL_MSG("rsa q key error"); - return WOLFSSL_FATAL_ERROR; - } - - if (dsa->g != NULL && - wolfssl_bn_get_value(dsa->g, &key->g) != 1) { - WOLFSSL_MSG("rsa g key error"); - return WOLFSSL_FATAL_ERROR; - } - - if (dsa->pub_key != NULL) { - if (wolfssl_bn_get_value(dsa->pub_key, &key->y) != 1) { - WOLFSSL_MSG("rsa pub_key error"); - return WOLFSSL_FATAL_ERROR; - } - - /* public key */ - key->type = DSA_PUBLIC; - } - - if (dsa->priv_key != NULL) { - if (wolfssl_bn_get_value(dsa->priv_key, &key->x) != 1) { - WOLFSSL_MSG("rsa priv_key error"); - return WOLFSSL_FATAL_ERROR; - } - - /* private key */ - key->type = DSA_PRIVATE; - } - - dsa->inSet = 1; - - return 1; -} - -/* return code compliant with OpenSSL : - * 1 if success, 0 if error - */ -int wolfSSL_DSA_generate_key(WOLFSSL_DSA* dsa) -{ - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_DSA_generate_key"); - - if (dsa == NULL || dsa->internal == NULL) { - WOLFSSL_MSG("Bad arguments"); - return 0; - } - - if (dsa->inSet == 0) { - WOLFSSL_MSG("No DSA internal set, do it"); - - if (SetDsaInternal(dsa) != 1) { - WOLFSSL_MSG("SetDsaInternal failed"); - return ret; - } - } - -#ifdef WOLFSSL_KEY_GEN - { - int initTmpRng = 0; - WC_RNG *rng = NULL; - WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); - - WC_ALLOC_VAR_EX(tmpRng, WC_RNG, 1, NULL, DYNAMIC_TYPE_RNG, - return WOLFSSL_FATAL_ERROR); - if (wc_InitRng(tmpRng) == 0) { - rng = tmpRng; - initTmpRng = 1; - } - else { - WOLFSSL_MSG("Bad RNG Init, trying global"); - rng = wolfssl_get_global_rng(); - } - - if (rng) { - /* These were allocated above by SetDsaInternal(). They should - * be cleared before wc_MakeDsaKey() which reinitializes - * x and y. */ - mp_clear(&((DsaKey*)dsa->internal)->x); - mp_clear(&((DsaKey*)dsa->internal)->y); - - if (wc_MakeDsaKey(rng, (DsaKey*)dsa->internal) != MP_OKAY) - WOLFSSL_MSG("wc_MakeDsaKey failed"); - else if (SetDsaExternal(dsa) != 1) - WOLFSSL_MSG("SetDsaExternal failed"); - else - ret = 1; - } - - if (initTmpRng) - wc_FreeRng(tmpRng); - - WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); - } -#else /* WOLFSSL_KEY_GEN */ - WOLFSSL_MSG("No Key Gen built in"); -#endif - return ret; -} - - -/* Returns a pointer to a new WOLFSSL_DSA structure on success and NULL on fail - */ -WOLFSSL_DSA* wolfSSL_DSA_generate_parameters(int bits, unsigned char* seed, - int seedLen, int* counterRet, unsigned long* hRet, - WOLFSSL_BN_CB cb, void* CBArg) -{ - WOLFSSL_DSA* dsa; - - WOLFSSL_ENTER("wolfSSL_DSA_generate_parameters"); - - (void)cb; - (void)CBArg; - dsa = wolfSSL_DSA_new(); - if (dsa == NULL) { - return NULL; - } - - if (wolfSSL_DSA_generate_parameters_ex(dsa, bits, seed, seedLen, - counterRet, hRet, NULL) != 1) { - wolfSSL_DSA_free(dsa); - return NULL; - } - - return dsa; -} - - -/* return code compliant with OpenSSL : - * 1 if success, 0 if error - */ -int wolfSSL_DSA_generate_parameters_ex(WOLFSSL_DSA* dsa, int bits, - unsigned char* seed, int seedLen, - int* counterRet, - unsigned long* hRet, void* cb) -{ - int ret = 0; - - (void)bits; - (void)seed; - (void)seedLen; - (void)counterRet; - (void)hRet; - (void)cb; - - WOLFSSL_ENTER("wolfSSL_DSA_generate_parameters_ex"); - - if (dsa == NULL || dsa->internal == NULL) { - WOLFSSL_MSG("Bad arguments"); - return 0; - } - -#ifdef WOLFSSL_KEY_GEN - { - int initTmpRng = 0; - WC_RNG *rng = NULL; - WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); - - WC_ALLOC_VAR_EX(tmpRng, WC_RNG, 1, NULL, DYNAMIC_TYPE_RNG, - return WOLFSSL_FATAL_ERROR); - if (wc_InitRng(tmpRng) == 0) { - rng = tmpRng; - initTmpRng = 1; - } - else { - WOLFSSL_MSG("Bad RNG Init, trying global"); - rng = wolfssl_get_global_rng(); - } - - if (rng) { - if (wc_MakeDsaParameters(rng, bits, - (DsaKey*)dsa->internal) != MP_OKAY) - WOLFSSL_MSG("wc_MakeDsaParameters failed"); - else if (SetDsaExternal(dsa) != 1) - WOLFSSL_MSG("SetDsaExternal failed"); - else - ret = 1; - } - - if (initTmpRng) - wc_FreeRng(tmpRng); - - WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); - } -#else /* WOLFSSL_KEY_GEN */ - WOLFSSL_MSG("No Key Gen built in"); -#endif - - return ret; -} - -void wolfSSL_DSA_get0_pqg(const WOLFSSL_DSA *d, const WOLFSSL_BIGNUM **p, - const WOLFSSL_BIGNUM **q, const WOLFSSL_BIGNUM **g) -{ - WOLFSSL_ENTER("wolfSSL_DSA_get0_pqg"); - if (d != NULL) { - if (p != NULL) - *p = d->p; - if (q != NULL) - *q = d->q; - if (g != NULL) - *g = d->g; - } -} - -int wolfSSL_DSA_set0_pqg(WOLFSSL_DSA *d, WOLFSSL_BIGNUM *p, - WOLFSSL_BIGNUM *q, WOLFSSL_BIGNUM *g) -{ - WOLFSSL_ENTER("wolfSSL_DSA_set0_pqg"); - if (d == NULL || p == NULL || q == NULL || g == NULL) { - WOLFSSL_MSG("Bad parameter"); - return 0; - } - wolfSSL_BN_free(d->p); - wolfSSL_BN_free(d->q); - wolfSSL_BN_free(d->g); - d->p = p; - d->q = q; - d->g = g; - return 1; -} - -void wolfSSL_DSA_get0_key(const WOLFSSL_DSA *d, - const WOLFSSL_BIGNUM **pub_key, const WOLFSSL_BIGNUM **priv_key) -{ - WOLFSSL_ENTER("wolfSSL_DSA_get0_key"); - if (d != NULL) { - if (pub_key != NULL) - *pub_key = d->pub_key; - if (priv_key != NULL) - *priv_key = d->priv_key; - } -} - -int wolfSSL_DSA_set0_key(WOLFSSL_DSA *d, WOLFSSL_BIGNUM *pub_key, - WOLFSSL_BIGNUM *priv_key) -{ - WOLFSSL_ENTER("wolfSSL_DSA_set0_key"); - - /* The private key may be NULL */ - if (d->pub_key == NULL && pub_key == NULL) { - WOLFSSL_MSG("Bad parameter"); - return 0; - } - - if (pub_key != NULL) { - wolfSSL_BN_free(d->pub_key); - d->pub_key = pub_key; - } - if (priv_key != NULL) { - wolfSSL_BN_free(d->priv_key); - d->priv_key = priv_key; - } - - return 1; -} - -WOLFSSL_DSA_SIG* wolfSSL_DSA_SIG_new(void) -{ - WOLFSSL_DSA_SIG* sig; - WOLFSSL_ENTER("wolfSSL_DSA_SIG_new"); - sig = (WOLFSSL_DSA_SIG*)XMALLOC(sizeof(WOLFSSL_DSA_SIG), NULL, - DYNAMIC_TYPE_OPENSSL); - if (sig) - XMEMSET(sig, 0, sizeof(WOLFSSL_DSA_SIG)); - return sig; -} - -void wolfSSL_DSA_SIG_free(WOLFSSL_DSA_SIG *sig) -{ - WOLFSSL_ENTER("wolfSSL_DSA_SIG_free"); - if (sig) { - if (sig->r) { - wolfSSL_BN_free(sig->r); - } - if (sig->s) { - wolfSSL_BN_free(sig->s); - } - XFREE(sig, NULL, DYNAMIC_TYPE_OPENSSL); - } -} - -void wolfSSL_DSA_SIG_get0(const WOLFSSL_DSA_SIG *sig, - const WOLFSSL_BIGNUM **r, const WOLFSSL_BIGNUM **s) -{ - WOLFSSL_ENTER("wolfSSL_DSA_SIG_get0"); - if (sig != NULL) { - *r = sig->r; - *s = sig->s; - } -} - -int wolfSSL_DSA_SIG_set0(WOLFSSL_DSA_SIG *sig, WOLFSSL_BIGNUM *r, - WOLFSSL_BIGNUM *s) -{ - WOLFSSL_ENTER("wolfSSL_DSA_SIG_set0"); - if (r == NULL || s == NULL) { - WOLFSSL_MSG("Bad parameter"); - return 0; - } - - wolfSSL_BN_clear_free(sig->r); - wolfSSL_BN_clear_free(sig->s); - sig->r = r; - sig->s = s; - - return 1; -} - -#ifndef HAVE_SELFTEST -/** - * - * @param sig The input signature to encode - * @param out The output buffer. If *out is NULL then a new buffer is - * allocated. Otherwise the output is written to the buffer. - * @return length on success and -1 on error - */ -int wolfSSL_i2d_DSA_SIG(const WOLFSSL_DSA_SIG *sig, byte **out) -{ - /* Space for sequence + two asn ints */ - byte buf[MAX_SEQ_SZ + 2*(ASN_TAG_SZ + MAX_LENGTH_SZ + DSA_MAX_HALF_SIZE)]; - word32 bufLen = sizeof(buf); - - WOLFSSL_ENTER("wolfSSL_i2d_DSA_SIG"); - - if (sig == NULL || sig->r == NULL || sig->s == NULL || - out == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FATAL_ERROR; - } - - if (StoreECC_DSA_Sig(buf, &bufLen, - (mp_int*)sig->r->internal, (mp_int*)sig->s->internal) != 0) { - WOLFSSL_MSG("StoreECC_DSA_Sig error"); - return WOLFSSL_FATAL_ERROR; - } - - if (*out == NULL) { - byte* tmp = (byte*)XMALLOC(bufLen, NULL, DYNAMIC_TYPE_ASN1); - if (tmp == NULL) { - WOLFSSL_MSG("malloc error"); - return WOLFSSL_FATAL_ERROR; - } - *out = tmp; - } - - XMEMCPY(*out, buf, bufLen); - - return (int)bufLen; -} - -/** - * Same as wolfSSL_DSA_SIG_new but also initializes the internal bignums as well. - * @return New WOLFSSL_DSA_SIG with r and s created as well - */ -static WOLFSSL_DSA_SIG* wolfSSL_DSA_SIG_new_bn(void) -{ - WOLFSSL_DSA_SIG* ret; - - if ((ret = wolfSSL_DSA_SIG_new()) == NULL) { - WOLFSSL_MSG("wolfSSL_DSA_SIG_new error"); - return NULL; - } - - if ((ret->r = wolfSSL_BN_new()) == NULL) { - WOLFSSL_MSG("wolfSSL_BN_new error"); - wolfSSL_DSA_SIG_free(ret); - return NULL; - } - - if ((ret->s = wolfSSL_BN_new()) == NULL) { - WOLFSSL_MSG("wolfSSL_BN_new error"); - wolfSSL_DSA_SIG_free(ret); - return NULL; - } - - return ret; -} - -/** - * This parses a DER encoded ASN.1 structure. The ASN.1 encoding is: - * ASN1_SEQUENCE - * ASN1_INTEGER (DSA r) - * ASN1_INTEGER (DSA s) - * Alternatively, if the input is DSA_160_SIG_SIZE or DSA_256_SIG_SIZE in - * length then this API interprets this as two unsigned binary numbers. - * @param sig If non-null then free'd first and then newly created - * WOLFSSL_DSA_SIG is assigned - * @param pp Input buffer that is moved forward on success - * @param length Length of input buffer - * @return Newly created WOLFSSL_DSA_SIG on success or NULL on failure - */ -WOLFSSL_DSA_SIG* wolfSSL_d2i_DSA_SIG(WOLFSSL_DSA_SIG **sig, - const unsigned char **pp, long length) -{ - WOLFSSL_DSA_SIG* ret; - mp_int* r; - mp_int* s; - - WOLFSSL_ENTER("wolfSSL_d2i_DSA_SIG"); - - if (pp == NULL || *pp == NULL || length < 0) { - WOLFSSL_MSG("Bad function arguments"); - return NULL; - } - - if ((ret = wolfSSL_DSA_SIG_new_bn()) == NULL) { - WOLFSSL_MSG("wolfSSL_DSA_SIG_new_bn error"); - return NULL; - } - - r = (mp_int*)ret->r->internal; - s = (mp_int*)ret->s->internal; - - if (DecodeECC_DSA_Sig(*pp, (word32)length, r, s) != 0) { - if (length == DSA_160_SIG_SIZE || length == DSA_256_SIG_SIZE) { - /* Two raw numbers of length/2 size each */ - if (mp_read_unsigned_bin(r, *pp, (word32)length/2) != 0) { - WOLFSSL_MSG("r mp_read_unsigned_bin error"); - wolfSSL_DSA_SIG_free(ret); - return NULL; - } - - if (mp_read_unsigned_bin(s, *pp + (length/2), (word32)length/2) != - 0) { - WOLFSSL_MSG("s mp_read_unsigned_bin error"); - wolfSSL_DSA_SIG_free(ret); - return NULL; - } - - *pp += length; - } - else { - WOLFSSL_MSG("DecodeECC_DSA_Sig error"); - wolfSSL_DSA_SIG_free(ret); - return NULL; - } - } - else { - /* DecodeECC_DSA_Sig success move pointer forward */ -#ifndef NO_STRICT_ECDSA_LEN - *pp += length; -#else - { - /* We need to figure out how much to move by ourselves */ - word32 idx = 0; - int len = 0; - if (GetSequence(*pp, &idx, &len, (word32)length) < 0) { - WOLFSSL_MSG("GetSequence error"); - wolfSSL_DSA_SIG_free(ret); - return NULL; - } - *pp += len; - } -#endif - } - - if (sig != NULL) { - if (*sig != NULL) - wolfSSL_DSA_SIG_free(*sig); - *sig = ret; - } - - return ret; -} - -#endif /* !HAVE_SELFTEST */ - -static int dsa_do_sign(const unsigned char* d, int dLen, unsigned char* sigRet, - WOLFSSL_DSA* dsa) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); - int initTmpRng = 0; - WC_RNG* rng = NULL; - WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); - - if (d == NULL || sigRet == NULL || dsa == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FATAL_ERROR; - } - - if (dsa->inSet == 0) { - WOLFSSL_MSG("No DSA internal set, do it"); - if (SetDsaInternal(dsa) != 1) { - WOLFSSL_MSG("SetDsaInternal failed"); - return WOLFSSL_FATAL_ERROR; - } - } - - WC_ALLOC_VAR_EX(tmpRng, WC_RNG, 1, NULL, DYNAMIC_TYPE_RNG, - return WOLFSSL_FATAL_ERROR); - - if (wc_InitRng(tmpRng) == 0) { - rng = tmpRng; - initTmpRng = 1; - } - else { - WOLFSSL_MSG("Bad RNG Init, trying global"); -#ifdef WOLFSSL_SMALL_STACK - XFREE(tmpRng, NULL, DYNAMIC_TYPE_RNG); - tmpRng = NULL; -#endif - rng = wolfssl_get_global_rng(); - if (! rng) - return WOLFSSL_FATAL_ERROR; - } - - if (rng) { -#ifdef HAVE_SELFTEST - if (dLen != WC_SHA_DIGEST_SIZE || - wc_DsaSign(d, sigRet, (DsaKey*)dsa->internal, rng) < 0) { - WOLFSSL_MSG("wc_DsaSign failed or dLen wrong length"); - ret = WOLFSSL_FATAL_ERROR; - } -#else - if (wc_DsaSign_ex(d, dLen, sigRet, (DsaKey*)dsa->internal, rng) < 0) { - WOLFSSL_MSG("wc_DsaSign_ex failed"); - ret = WOLFSSL_FATAL_ERROR; - } -#endif - else - ret = WOLFSSL_SUCCESS; - } - - if (initTmpRng) - wc_FreeRng(tmpRng); - WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); - - return ret; -} - -/* return 1 on success, < 0 otherwise */ -int wolfSSL_DSA_do_sign(const unsigned char* d, unsigned char* sigRet, - WOLFSSL_DSA* dsa) -{ - WOLFSSL_ENTER("wolfSSL_DSA_do_sign"); - - return dsa_do_sign(d, WC_SHA_DIGEST_SIZE, sigRet, dsa); -} - -#ifndef HAVE_SELFTEST -WOLFSSL_DSA_SIG* wolfSSL_DSA_do_sign_ex(const unsigned char* digest, - int inLen, WOLFSSL_DSA* dsa) -{ - byte sigBin[DSA_MAX_SIG_SIZE]; - const byte *tmp = sigBin; - int sigLen; - - WOLFSSL_ENTER("wolfSSL_DSA_do_sign_ex"); - - if (!digest || !dsa) { - WOLFSSL_MSG("Bad function arguments"); - return NULL; - } - - if (dsa_do_sign(digest, inLen, sigBin, dsa) != 1) { - WOLFSSL_MSG("wolfSSL_DSA_do_sign error"); - return NULL; - } - - if (dsa->internal == NULL) { - WOLFSSL_MSG("dsa->internal is null"); - return NULL; - } - - sigLen = mp_unsigned_bin_size(&((DsaKey*)dsa->internal)->q); - if (sigLen <= 0) { - WOLFSSL_MSG("mp_unsigned_bin_size error"); - return NULL; - } - - /* 2 * sigLen for the two points r and s */ - return wolfSSL_d2i_DSA_SIG(NULL, &tmp, 2 * sigLen); -} -#endif - -static int dsa_do_verify(const unsigned char* d, int dLen, unsigned char* sig, - WOLFSSL_DSA* dsa, int *dsacheck) -{ - int ret; - - if (d == NULL || sig == NULL || dsa == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FATAL_ERROR; - } - if (dsa->inSet == 0) - { - WOLFSSL_MSG("No DSA internal set, do it"); - - if (SetDsaInternal(dsa) != 1) { - WOLFSSL_MSG("SetDsaInternal failed"); - return WOLFSSL_FATAL_ERROR; - } - } - -#ifdef HAVE_SELFTEST - ret = dLen == WC_SHA_DIGEST_SIZE ? - wc_DsaVerify(d, sig, (DsaKey*)dsa->internal, dsacheck) : BAD_FUNC_ARG; -#else - ret = wc_DsaVerify_ex(d, (word32)dLen, sig, (DsaKey*)dsa->internal, - dsacheck); -#endif - if (ret != 0) { - WOLFSSL_MSG("DsaVerify failed"); - return WOLFSSL_FATAL_ERROR; - } - if (*dsacheck != 1) { - WOLFSSL_MSG("DsaVerify sig failed"); - return WOLFSSL_FAILURE; - } - - return WOLFSSL_SUCCESS; -} - -int wolfSSL_DSA_do_verify(const unsigned char* d, unsigned char* sig, - WOLFSSL_DSA* dsa, int *dsacheck) -{ - WOLFSSL_ENTER("wolfSSL_DSA_do_verify"); - - return dsa_do_verify(d, WC_SHA_DIGEST_SIZE, sig, dsa, dsacheck); -} - - -int wolfSSL_DSA_bits(const WOLFSSL_DSA *d) -{ - if (!d) - return 0; - if (!d->exSet && SetDsaExternal((WOLFSSL_DSA*)d) != 1) - return 0; - return wolfSSL_BN_num_bits(d->p); -} - -#ifndef HAVE_SELFTEST -int wolfSSL_DSA_do_verify_ex(const unsigned char* digest, int digest_len, - WOLFSSL_DSA_SIG* sig, WOLFSSL_DSA* dsa) -{ - int dsacheck, sz; - byte sigBin[DSA_MAX_SIG_SIZE]; - byte* sigBinPtr = sigBin; - DsaKey* key; - int qSz; - - WOLFSSL_ENTER("wolfSSL_DSA_do_verify_ex"); - - if (!digest || !sig || !dsa) { - WOLFSSL_MSG("Bad function arguments"); - return 0; - } - - if (!sig->r || !sig->s) { - WOLFSSL_MSG("No signature found in DSA_SIG"); - return 0; - } - - if (dsa->inSet == 0) { - WOLFSSL_MSG("No DSA internal set, do it"); - if (SetDsaInternal(dsa) != 1) { - WOLFSSL_MSG("SetDsaInternal failed"); - return 0; - } - } - - key = (DsaKey*)dsa->internal; - - if (key == NULL) { - WOLFSSL_MSG("dsa->internal is null"); - return 0; - } - - qSz = mp_unsigned_bin_size(&key->q); - if (qSz < 0 || qSz > DSA_MAX_HALF_SIZE) { - WOLFSSL_MSG("mp_unsigned_bin_size error"); - return 0; - } - - /* read r */ - /* front pad with zeros */ - if ((sz = wolfSSL_BN_num_bytes(sig->r)) < 0 || sz > DSA_MAX_HALF_SIZE) - return 0; - while (sz++ < qSz) - *sigBinPtr++ = 0; - if (wolfSSL_BN_bn2bin(sig->r, sigBinPtr) == -1) - return 0; - - /* Move to s */ - sigBinPtr = sigBin + qSz; - - /* read s */ - /* front pad with zeros */ - if ((sz = wolfSSL_BN_num_bytes(sig->s)) < 0 || sz > DSA_MAX_HALF_SIZE) - return 0; - while (sz++ < qSz) - *sigBinPtr++ = 0; - if (wolfSSL_BN_bn2bin(sig->s, sigBinPtr) == -1) - return 0; - - if ((dsa_do_verify(digest, digest_len, sigBin, dsa, &dsacheck) - != 1) || dsacheck != 1) { - return 0; - } - - return 1; -} -#endif - -int wolfSSL_i2d_DSAparams(const WOLFSSL_DSA* dsa, - unsigned char** out) -{ - int ret = 0; - word32 derLen = 0; - int preAllocated = 1; - DsaKey* key = NULL; - - WOLFSSL_ENTER("wolfSSL_i2d_DSAparams"); - - if (dsa == NULL || dsa->internal == NULL || out == NULL) { - ret = BAD_FUNC_ARG; - } - - if (ret == 0) { - key = (DsaKey*)dsa->internal; - ret = wc_DsaKeyToParamsDer_ex(key, NULL, &derLen); - if (ret == WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { - ret = 0; - } - } - if (ret == 0 && *out == NULL) { - /* If we're allocating out for the caller, we don't increment out just - past the end of the DER buffer. If out is already allocated, we do. - (OpenSSL convention) */ - preAllocated = 0; - *out = (unsigned char*)XMALLOC(derLen, key->heap, DYNAMIC_TYPE_OPENSSL); - if (*out == NULL) { - ret = MEMORY_E; - } - } - if (ret == 0) { - ret = wc_DsaKeyToParamsDer_ex(key, *out, &derLen); - } - if (ret >= 0 && preAllocated == 1) { - *out += derLen; - } - - if (ret < 0 && preAllocated == 0) { - XFREE(*out, key ? key->heap : NULL, DYNAMIC_TYPE_OPENSSL); - } - - WOLFSSL_LEAVE("wolfSSL_i2d_DSAparams", ret); - - return ret; -} - -WOLFSSL_DSA* wolfSSL_d2i_DSAparams(WOLFSSL_DSA** dsa, const unsigned char** der, - long derLen) -{ - WOLFSSL_DSA* ret = NULL; - int err = 0; - word32 idx = 0; - int asnLen; - DsaKey* internalKey = NULL; - - WOLFSSL_ENTER("wolfSSL_d2i_DSAparams"); - - if (der == NULL || *der == NULL || derLen <= 0) { - err = 1; - } - if (err == 0) { - ret = wolfSSL_DSA_new(); - err = ret == NULL; - } - if (err == 0) { - err = GetSequence(*der, &idx, &asnLen, (word32)derLen) <= 0; - } - if (err == 0) { - internalKey = (DsaKey*)ret->internal; - err = GetInt(&internalKey->p, *der, &idx, (word32)derLen) != 0; - } - if (err == 0) { - err = GetInt(&internalKey->q, *der, &idx, (word32)derLen) != 0; - } - if (err == 0) { - err = GetInt(&internalKey->g, *der, &idx, (word32)derLen) != 0; - } - if (err == 0) { - err = wolfssl_bn_set_value(&ret->p, &internalKey->p) - != 1; - } - if (err == 0) { - err = wolfssl_bn_set_value(&ret->q, &internalKey->q) - != 1; - } - if (err == 0) { - err = wolfssl_bn_set_value(&ret->g, &internalKey->g) - != 1; - } - if (err == 0 && dsa != NULL) { - *dsa = ret; - } - - if (err != 0 && ret != NULL) { - wolfSSL_DSA_free(ret); - ret = NULL; - } - - return ret; -} - -#if defined(WOLFSSL_KEY_GEN) -#ifndef NO_BIO - -/* Takes a DSA Privatekey and writes it out to a WOLFSSL_BIO - * Returns 1 or 0 - */ -int wolfSSL_PEM_write_bio_DSAPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_DSA* dsa, - const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, - wc_pem_password_cb* cb, void* arg) -{ - int ret = 1; - byte *pem = NULL; - int pLen = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_write_bio_DSAPrivateKey"); - - (void)cb; - (void)arg; - - /* Validate parameters. */ - if ((bio == NULL) || (dsa == NULL)) { - WOLFSSL_MSG("Bad Function Arguments"); - ret = 0; - } - - if (ret == 1) { - ret = wolfSSL_PEM_write_mem_DSAPrivateKey(dsa, cipher, passwd, passwdSz, - &pem, &pLen); - } - - /* Write PEM to BIO. */ - if ((ret == 1) && (wolfSSL_BIO_write(bio, pem, pLen) != pLen)) { - WOLFSSL_ERROR_MSG("DSA private key BIO write failed"); - ret = 0; - } - - XFREE(pem, NULL, DYNAMIC_TYPE_KEY); - return ret; -} - -#ifndef HAVE_SELFTEST -/* Encode the DSA public key as DER. - * - * @param [in] key DSA key to encode. - * @param [out] der Pointer through which buffer is returned. - * @param [in] heap Heap hint. - * @return Size of encoding on success. - * @return 0 on error. - */ -static int wolfssl_dsa_key_to_pubkey_der(WOLFSSL_DSA* key, unsigned char** der, - void* heap) -{ - int sz; - unsigned char* buf = NULL; - - /* Use maximum encoded size to allocate. */ - sz = MAX_DSA_PUBKEY_SZ; - /* Allocate memory to hold encoding. */ - buf = (byte*)XMALLOC((size_t)sz, heap, DYNAMIC_TYPE_TMP_BUFFER); - if (buf == NULL) { - WOLFSSL_MSG("malloc failed"); - sz = 0; - } - if (sz > 0) { - /* Encode public key to DER using wolfSSL. */ - sz = wc_DsaKeyToPublicDer((DsaKey*)key->internal, buf, (word32)sz); - if (sz < 0) { - WOLFSSL_MSG("wc_DsaKeyToPublicDer failed"); - sz = 0; - } - } - - /* Return buffer on success. */ - if (sz > 0) { - *der = buf; - } - else { - /* Dispose of any dynamically allocated data not returned. */ - XFREE(buf, heap, DYNAMIC_TYPE_TMP_BUFFER); - } - - return sz; -} - -/* Takes a DSA public key and writes it out to a WOLFSSL_BIO - * Returns 1 or 0 - */ -int wolfSSL_PEM_write_bio_DSA_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_DSA* dsa) -{ - int ret = 1; - unsigned char* derBuf = NULL; - int derSz = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_write_bio_DSA_PUBKEY"); - - /* Validate parameters. */ - if ((bio == NULL) || (dsa == NULL)) { - WOLFSSL_MSG("Bad Function Arguments"); - return 0; - } - - /* Encode public key in EC key as DER. */ - derSz = wolfssl_dsa_key_to_pubkey_der(dsa, &derBuf, bio->heap); - if (derSz == 0) { - ret = 0; - } - - /* Write out to BIO the PEM encoding of the DSA public key. */ - if ((ret == 1) && (der_write_to_bio_as_pem(derBuf, derSz, bio, - PUBLICKEY_TYPE) != 1)) { - ret = 0; - } - - /* Dispose of any dynamically allocated data. */ - XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - - return ret; -} -#endif /* HAVE_SELFTEST */ -#endif /* !NO_BIO */ - -/* return code compliant with OpenSSL : - * 1 if success, 0 if error - */ -int wolfSSL_PEM_write_mem_DSAPrivateKey(WOLFSSL_DSA* dsa, - const WOLFSSL_EVP_CIPHER* cipher, - unsigned char* passwd, int passwdSz, - unsigned char **pem, int *pLen) -{ -#if (defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)) && \ - !defined(NO_MD5) - byte *derBuf, *tmp, *cipherInfo = NULL; - int der_max_len = 0, derSz = 0; - const int type = DSA_PRIVATEKEY_TYPE; - const char* header = NULL; - const char* footer = NULL; - - WOLFSSL_MSG("wolfSSL_PEM_write_mem_DSAPrivateKey"); - - if (pem == NULL || pLen == NULL || dsa == NULL || dsa->internal == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return 0; - } - - if (wc_PemGetHeaderFooter(type, &header, &footer) != 0) - return 0; - - if (dsa->inSet == 0) { - WOLFSSL_MSG("No DSA internal set, do it"); - - if (SetDsaInternal(dsa) != 1) { - WOLFSSL_MSG("SetDsaInternal failed"); - return 0; - } - } - - der_max_len = MAX_DSA_PRIVKEY_SZ; - - derBuf = (byte*)XMALLOC((size_t)der_max_len, NULL, DYNAMIC_TYPE_DER); - if (derBuf == NULL) { - WOLFSSL_MSG("malloc failed"); - return 0; - } - - /* Key to DER */ - derSz = wc_DsaKeyToDer((DsaKey*)dsa->internal, derBuf, (word32)der_max_len); - if (derSz < 0) { - WOLFSSL_MSG("wc_DsaKeyToDer failed"); - XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); - return 0; - } - - /* encrypt DER buffer if required */ - if (passwd != NULL && passwdSz > 0 && cipher != NULL) { - int ret; - - ret = EncryptDerKey(derBuf, &derSz, cipher, passwd, passwdSz, - &cipherInfo, der_max_len, WC_MD5); - if (ret != 1) { - WOLFSSL_MSG("EncryptDerKey failed"); - XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); - return ret; - } - /* tmp buffer with a max size */ - *pLen = (derSz * 2) + (int)XSTRLEN(header) + 1 + - (int)XSTRLEN(footer) + 1 + HEADER_ENCRYPTED_KEY_SIZE; - } - else { /* tmp buffer with a max size */ - *pLen = (derSz * 2) + (int)XSTRLEN(header) + 1 + - (int)XSTRLEN(footer) + 1; - } - - tmp = (byte*)XMALLOC((size_t)*pLen, NULL, DYNAMIC_TYPE_PEM); - if (tmp == NULL) { - WOLFSSL_MSG("malloc failed"); - XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); - XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); - return 0; - } - - /* DER to PEM */ - *pLen = wc_DerToPemEx(derBuf, (word32)derSz, tmp, (word32)*pLen, cipherInfo, - type); - if (*pLen <= 0) { - WOLFSSL_MSG("wc_DerToPemEx failed"); - XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); - XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); - XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); - return 0; - } - XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); - XFREE(cipherInfo, NULL, DYNAMIC_TYPE_STRING); - - *pem = (byte*)XMALLOC((size_t)((*pLen)+1), NULL, DYNAMIC_TYPE_KEY); - if (*pem == NULL) { - WOLFSSL_MSG("malloc failed"); - XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); - return 0; - } - XMEMSET(*pem, 0, (size_t)((*pLen)+1)); - - if (XMEMCPY(*pem, tmp, (size_t)*pLen) == NULL) { - WOLFSSL_MSG("XMEMCPY failed"); - XFREE(pem, NULL, DYNAMIC_TYPE_KEY); - XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); - return 0; - } - XFREE(tmp, NULL, DYNAMIC_TYPE_PEM); - - return 1; -#else - (void)dsa; - (void)cipher; - (void)passwd; - (void)passwdSz; - (void)pem; - (void)pLen; - return 0; -#endif /* (WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM) && !NO_MD5 */ -} - -#ifndef NO_FILESYSTEM -/* return code compliant with OpenSSL : - * 1 if success, 0 if error - */ -int wolfSSL_PEM_write_DSAPrivateKey(XFILE fp, WOLFSSL_DSA *dsa, - const WOLFSSL_EVP_CIPHER *enc, - unsigned char *kstr, int klen, - wc_pem_password_cb *cb, void *u) -{ - byte *pem; - int pLen, ret; - - (void)cb; - (void)u; - - WOLFSSL_MSG("wolfSSL_PEM_write_DSAPrivateKey"); - - if (fp == XBADFILE || dsa == NULL || dsa->internal == NULL) { - WOLFSSL_MSG("Bad function arguments"); - return 0; - } - - ret = wolfSSL_PEM_write_mem_DSAPrivateKey(dsa, enc, kstr, klen, &pem, - &pLen); - if (ret != 1) { - WOLFSSL_MSG("wolfSSL_PEM_write_mem_DSAPrivateKey failed"); - return 0; - } - - ret = (int)XFWRITE(pem, (size_t)pLen, 1, fp); - if (ret != 1) { - WOLFSSL_MSG("DSA private key file write failed"); - return 0; - } - - XFREE(pem, NULL, DYNAMIC_TYPE_KEY); - return 1; -} - -#endif /* NO_FILESYSTEM */ -#endif /* defined(WOLFSSL_KEY_GEN) */ - -#ifndef NO_FILESYSTEM -/* return code compliant with OpenSSL : - * 1 if success, 0 if error - */ -#ifndef NO_WOLFSSL_STUB -int wolfSSL_PEM_write_DSA_PUBKEY(XFILE fp, WOLFSSL_DSA *x) -{ - (void)fp; - (void)x; - WOLFSSL_STUB("PEM_write_DSA_PUBKEY"); - WOLFSSL_MSG("wolfSSL_PEM_write_DSA_PUBKEY not implemented"); - - return 0; -} -#endif -#endif /* NO_FILESYSTEM */ - -#ifndef NO_BIO - -#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL)) && (!defined(NO_CERTS) && \ - !defined(NO_FILESYSTEM) && defined(WOLFSSL_KEY_GEN)) -/* Uses the same format of input as wolfSSL_PEM_read_bio_PrivateKey but expects - * the results to be an DSA key. - * - * bio structure to read DSA private key from - * dsa if not null is then set to the result - * cb password callback for reading PEM - * pass password string - * - * returns a pointer to a new WOLFSSL_DSA structure on success and NULL on fail - */ -WOLFSSL_DSA* wolfSSL_PEM_read_bio_DSAPrivateKey(WOLFSSL_BIO* bio, - WOLFSSL_DSA** dsa, - wc_pem_password_cb* cb, - void* pass) -{ - WOLFSSL_EVP_PKEY* pkey = NULL; - WOLFSSL_DSA* local; - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_DSAPrivateKey"); - - - pkey = wolfSSL_PEM_read_bio_PrivateKey(bio, NULL, cb, pass); - if (pkey == NULL) { - WOLFSSL_MSG("Error in PEM_read_bio_PrivateKey"); - return NULL; - } - /* Since the WOLFSSL_DSA structure is being taken from WOLFSSL_EVP_PKEY the - * flag indicating that the WOLFSSL_DSA structure is owned should be FALSE - * to avoid having it free'd */ - pkey->ownDsa = 0; - local = pkey->dsa; - if (dsa != NULL) { - *dsa = local; - } - wolfSSL_EVP_PKEY_free(pkey); - return local; -} - -/* Reads an DSA public key from a WOLFSSL_BIO into a WOLFSSL_DSA. - * Returns 1 or 0 - */ -WOLFSSL_DSA *wolfSSL_PEM_read_bio_DSA_PUBKEY(WOLFSSL_BIO* bio,WOLFSSL_DSA** dsa, - wc_pem_password_cb* cb, void* pass) -{ - WOLFSSL_EVP_PKEY* pkey; - WOLFSSL_DSA* local; - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_DSA_PUBKEY"); - - pkey = wolfSSL_PEM_read_bio_PUBKEY(bio, NULL, cb, pass); - if (pkey == NULL) { - WOLFSSL_MSG("wolfSSL_PEM_read_bio_PUBKEY failed"); - return NULL; - } - - /* Since the WOLFSSL_DSA structure is being taken from WOLFSSL_EVP_PKEY the - * flag indicating that the WOLFSSL_DSA structure is owned should be FALSE - * to avoid having it free'd */ - pkey->ownDsa = 0; - local = pkey->dsa; - if (dsa != NULL) { - *dsa = local; - } - - wolfSSL_EVP_PKEY_free(pkey); - return local; -} -#endif /* (OPENSSL_EXTRA || OPENSSL_ALL) && (!NO_CERTS && - !NO_FILESYSTEM && WOLFSSL_KEY_GEN) */ - -#endif /* NO_BIO */ - -#endif /* OPENSSL_EXTRA */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -/* return 1 if success, -1 if error */ -int wolfSSL_DSA_LoadDer(WOLFSSL_DSA* dsa, const unsigned char* derBuf, int derSz) -{ - word32 idx = 0; - int ret; - - WOLFSSL_ENTER("wolfSSL_DSA_LoadDer"); - - if (dsa == NULL || dsa->internal == NULL || derBuf == NULL || derSz <= 0) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FATAL_ERROR; - } - - ret = DsaPrivateKeyDecode(derBuf, &idx, (DsaKey*)dsa->internal, - (word32)derSz); - if (ret < 0) { - WOLFSSL_MSG("DsaPrivateKeyDecode failed"); - return WOLFSSL_FATAL_ERROR; - } - - if (SetDsaExternal(dsa) != 1) { - WOLFSSL_MSG("SetDsaExternal failed"); - return WOLFSSL_FATAL_ERROR; - } - - dsa->inSet = 1; - - return 1; -} - -/* Loads DSA key from DER buffer. opt = DSA_LOAD_PRIVATE or DSA_LOAD_PUBLIC. - returns 1 on success, or 0 on failure. */ -int wolfSSL_DSA_LoadDer_ex(WOLFSSL_DSA* dsa, const unsigned char* derBuf, - int derSz, int opt) -{ - word32 idx = 0; - int ret; - - WOLFSSL_ENTER("wolfSSL_DSA_LoadDer"); - - if (dsa == NULL || dsa->internal == NULL || derBuf == NULL || derSz <= 0) { - WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FATAL_ERROR; - } - - if (opt == WOLFSSL_DSA_LOAD_PRIVATE) { - ret = DsaPrivateKeyDecode(derBuf, &idx, (DsaKey*)dsa->internal, - (word32)derSz); - } - else { - ret = DsaPublicKeyDecode(derBuf, &idx, (DsaKey*)dsa->internal, - (word32)derSz); - } - - if (ret < 0 && opt == WOLFSSL_DSA_LOAD_PRIVATE) { - WOLFSSL_ERROR_VERBOSE(ret); - WOLFSSL_MSG("DsaPrivateKeyDecode failed"); - return WOLFSSL_FATAL_ERROR; - } - else if (ret < 0 && opt == WOLFSSL_DSA_LOAD_PUBLIC) { - WOLFSSL_ERROR_VERBOSE(ret); - WOLFSSL_MSG("DsaPublicKeyDecode failed"); - return WOLFSSL_FATAL_ERROR; - } - - if (SetDsaExternal(dsa) != 1) { - WOLFSSL_MSG("SetDsaExternal failed"); - return WOLFSSL_FATAL_ERROR; - } - - dsa->inSet = 1; - - return 1; -} -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - -#ifdef OPENSSL_EXTRA -#ifndef NO_BIO -WOLFSSL_DSA *wolfSSL_PEM_read_bio_DSAparams(WOLFSSL_BIO *bp, WOLFSSL_DSA **x, - wc_pem_password_cb *cb, void *u) -{ - WOLFSSL_DSA* dsa; - DsaKey* key; - int length; - unsigned char* buf; - word32 bufSz; - int ret; - word32 idx = 0; - DerBuffer* pDer; - - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_DSAparams"); - - ret = wolfSSL_BIO_get_mem_data(bp, &buf); - if (ret <= 0) { - WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_DSAparams", ret); - return NULL; - } - - bufSz = (word32)ret; - - if (cb != NULL || u != NULL) { - /* - * cb is for a call back when encountering encrypted PEM files - * if cb == NULL and u != NULL then u = null terminated password string - */ - WOLFSSL_MSG("Not yet supporting call back or password for encrypted PEM"); - } - - if (PemToDer(buf, (long)bufSz, DSA_PARAM_TYPE, &pDer, NULL, NULL, - NULL) < 0 ) { - WOLFSSL_MSG("Issue converting from PEM to DER"); - return NULL; - } - - if (GetSequence(pDer->buffer, &idx, &length, pDer->length) < 0) { - WOLFSSL_LEAVE("wolfSSL_PEM_read_bio_DSAparams", ret); - FreeDer(&pDer); - return NULL; - } - - dsa = wolfSSL_DSA_new(); - if (dsa == NULL) { - FreeDer(&pDer); - WOLFSSL_MSG("Error creating DSA struct"); - return NULL; - } - - key = (DsaKey*)dsa->internal; - if (key == NULL) { - FreeDer(&pDer); - wolfSSL_DSA_free(dsa); - WOLFSSL_MSG("Error finding DSA key struct"); - return NULL; - } - - if (GetInt(&key->p, pDer->buffer, &idx, pDer->length) < 0 || - GetInt(&key->q, pDer->buffer, &idx, pDer->length) < 0 || - GetInt(&key->g, pDer->buffer, &idx, pDer->length) < 0 ) { - WOLFSSL_MSG("dsa key error"); - FreeDer(&pDer); - wolfSSL_DSA_free(dsa); - return NULL; - } - - if (wolfssl_bn_set_value(&dsa->p, &key->p) != 1) { - WOLFSSL_MSG("dsa p key error"); - FreeDer(&pDer); - wolfSSL_DSA_free(dsa); - return NULL; - } - - if (wolfssl_bn_set_value(&dsa->q, &key->q) != 1) { - WOLFSSL_MSG("dsa q key error"); - FreeDer(&pDer); - wolfSSL_DSA_free(dsa); - return NULL; - } - - if (wolfssl_bn_set_value(&dsa->g, &key->g) != 1) { - WOLFSSL_MSG("dsa g key error"); - FreeDer(&pDer); - wolfSSL_DSA_free(dsa); - return NULL; - } - - if (x != NULL) { - *x = dsa; - } - - FreeDer(&pDer); - return dsa; -} -#endif /* !NO_BIO */ - -#if !defined(NO_DH) -WOLFSSL_DH *wolfSSL_DSA_dup_DH(const WOLFSSL_DSA *dsa) -{ - WOLFSSL_DH* dh; - DhKey* key; - - WOLFSSL_ENTER("wolfSSL_DSA_dup_DH"); - - if (dsa == NULL) { - return NULL; - } - - dh = wolfSSL_DH_new(); - if (dh == NULL) { - return NULL; - } - key = (DhKey*)dh->internal; - - if (dsa->p != NULL && - wolfssl_bn_get_value(((WOLFSSL_DSA*)dsa)->p, &key->p) - != 1) { - WOLFSSL_MSG("rsa p key error"); - wolfSSL_DH_free(dh); - return NULL; - } - if (dsa->g != NULL && - wolfssl_bn_get_value(((WOLFSSL_DSA*)dsa)->g, &key->g) - != 1) { - WOLFSSL_MSG("rsa g key error"); - wolfSSL_DH_free(dh); - return NULL; - } - - if (wolfssl_bn_set_value(&dh->p, &key->p) != 1) { - WOLFSSL_MSG("dsa p key error"); - wolfSSL_DH_free(dh); - return NULL; - } - if (wolfssl_bn_set_value(&dh->g, &key->g) != 1) { - WOLFSSL_MSG("dsa g key error"); - wolfSSL_DH_free(dh); - return NULL; - } - - return dh; -} -#endif /* !NO_DH */ - -#endif /* OPENSSL_EXTRA */ - -#endif /* !NO_DSA */ - -/******************************************************************************* - * END OF DSA API - ******************************************************************************/ - - -/******************************************************************************* - * START OF DH API - ******************************************************************************/ - -#ifndef NO_DH - -#ifdef OPENSSL_EXTRA - -/* - * DH constructor/deconstructor APIs - */ - -/* Allocate and initialize a new DH key. - * - * @return DH key on success. - * @return NULL on failure. - */ -WOLFSSL_DH* wolfSSL_DH_new(void) -{ - int err = 0; - WOLFSSL_DH* dh = NULL; - DhKey* key = NULL; - - WOLFSSL_ENTER("wolfSSL_DH_new"); - - /* Allocate OpenSSL DH key. */ - dh = (WOLFSSL_DH*)XMALLOC(sizeof(WOLFSSL_DH), NULL, DYNAMIC_TYPE_DH); - if (dh == NULL) { - WOLFSSL_ERROR_MSG("wolfSSL_DH_new malloc WOLFSSL_DH failure"); - err = 1; - } - - if (!err) { - /* Clear key data. */ - XMEMSET(dh, 0, sizeof(WOLFSSL_DH)); - /* Initialize reference counting. */ - wolfSSL_RefInit(&dh->ref, &err); -#ifdef WOLFSSL_REFCNT_ERROR_RETURN - } - if (!err) { -#endif - /* Allocate wolfSSL DH key. */ - key = (DhKey*)XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH); - if (key == NULL) { - WOLFSSL_ERROR_MSG("wolfSSL_DH_new malloc DhKey failure"); - err = 1; - } - } - if (!err) { - /* Set and initialize wolfSSL DH key. */ - dh->internal = key; - if (wc_InitDhKey(key) != 0) { - WOLFSSL_ERROR_MSG("wolfSSL_DH_new InitDhKey failure"); - err = 1; - } - } - - if (err && (dh != NULL)) { - /* Dispose of the allocated memory. */ - XFREE(key, NULL, DYNAMIC_TYPE_DH); - wolfSSL_RefFree(&dh->ref); - XFREE(dh, NULL, DYNAMIC_TYPE_DH); - dh = NULL; - } - return dh; -} - -#if defined(HAVE_PUBLIC_FFDHE) || (defined(HAVE_FIPS) && FIPS_VERSION_EQ(2,0)) -/* Set the DH parameters based on the NID. - * - * @param [in, out] dh DH key to set. - * @param [in] nid Numeric ID of predefined DH parameters. - * @return 0 on success. - * @return 1 on failure. - */ -static int wolfssl_dh_set_nid(WOLFSSL_DH* dh, int nid) -{ - int err = 0; - const DhParams* params = NULL; - - /* HAVE_PUBLIC_FFDHE not required to expose wc_Dh_ffdhe* functions in - * FIPS v2 module */ - switch (nid) { -#ifdef HAVE_FFDHE_2048 - case WC_NID_ffdhe2048: - params = wc_Dh_ffdhe2048_Get(); - break; -#endif /* HAVE_FFDHE_2048 */ -#ifdef HAVE_FFDHE_3072 - case WC_NID_ffdhe3072: - params = wc_Dh_ffdhe3072_Get(); - break; -#endif /* HAVE_FFDHE_3072 */ -#ifdef HAVE_FFDHE_4096 - case WC_NID_ffdhe4096: - params = wc_Dh_ffdhe4096_Get(); - break; -#endif /* HAVE_FFDHE_4096 */ - default: - break; - } - if (params == NULL) { - WOLFSSL_ERROR_MSG("Unable to find DH params for nid."); - err = 1; - } - - if (!err) { - /* Set prime from data retrieved. */ - dh->p = wolfSSL_BN_bin2bn(params->p, (int)params->p_len, NULL); - if (dh->p == NULL) { - WOLFSSL_ERROR_MSG("Error converting p hex to WOLFSSL_BIGNUM."); - err = 1; - } - } - if (!err) { - /* Set generator from data retrieved. */ - dh->g = wolfSSL_BN_bin2bn(params->g, (int)params->g_len, NULL); - if (dh->g == NULL) { - WOLFSSL_ERROR_MSG("Error converting g hex to WOLFSSL_BIGNUM."); - err = 1; - } - } -#ifdef HAVE_FFDHE_Q - if (!err) { - /* Set order from data retrieved. */ - dh->q = wolfSSL_BN_bin2bn(params->q, params->q_len, NULL); - if (dh->q == NULL) { - WOLFSSL_ERROR_MSG("Error converting q hex to WOLFSSL_BIGNUM."); - err = 1; - } - } -#endif - - /* Synchronize the external into internal DH key's parameters. */ - if ((!err) && (SetDhInternal(dh) != 1)) { - WOLFSSL_ERROR_MSG("Failed to set internal DH params."); - err = 1; - } - if (!err) { - /* External DH key parameters were set. */ - dh->exSet = 1; - } - - if (err == 1) { - /* Dispose of any external parameters. */ - #ifdef HAVE_FFDHE_Q - wolfSSL_BN_free(dh->q); - dh->q = NULL; - #endif - wolfSSL_BN_free(dh->p); - dh->p = NULL; - wolfSSL_BN_free(dh->g); - dh->g = NULL; - } - - return err; -} -#elif !defined(HAVE_PUBLIC_FFDHE) && (!defined(HAVE_FIPS) || \ - FIPS_VERSION_GT(2,0)) -/* Set the DH parameters based on the NID. - * - * FIPS v2 and lower doesn't support wc_DhSetNamedKey. - * - * @param [in, out] dh DH key to set. - * @param [in] nid Numeric ID of predefined DH parameters. - * @return 0 on success. - * @return 1 on failure. - */ -static int wolfssl_dh_set_nid(WOLFSSL_DH* dh, int nid) -{ - int err = 0; - int name = 0; -#ifdef HAVE_FFDHE_Q - int elements = ELEMENT_P | ELEMENT_G | ELEMENT_Q; -#else - int elements = ELEMENT_P | ELEMENT_G; -#endif /* HAVE_FFDHE_Q */ - - switch (nid) { -#ifdef HAVE_FFDHE_2048 - case WC_NID_ffdhe2048: - name = WC_FFDHE_2048; - break; -#endif /* HAVE_FFDHE_2048 */ -#ifdef HAVE_FFDHE_3072 - case WC_NID_ffdhe3072: - name = WC_FFDHE_3072; - break; -#endif /* HAVE_FFDHE_3072 */ -#ifdef HAVE_FFDHE_4096 - case WC_NID_ffdhe4096: - name = WC_FFDHE_4096; - break; -#endif /* HAVE_FFDHE_4096 */ - default: - err = 1; - WOLFSSL_ERROR_MSG("Unable to find DH params for nid."); - break; - } - /* Set the internal DH key's parameters based on name. */ - if ((!err) && (wc_DhSetNamedKey((DhKey*)dh->internal, name) != 0)) { - WOLFSSL_ERROR_MSG("wc_DhSetNamedKey failed."); - err = 1; - } - /* Synchronize the internal into external DH key's parameters. */ - if (!err && (SetDhExternal_ex(dh, elements) != 1)) { - WOLFSSL_ERROR_MSG("Failed to set external DH params."); - err = 1; - } - - return err; -} -#else -/* Set the DH parameters based on the NID. - * - * Pre-defined DH parameters not available. - * - * @param [in, out] dh DH key to set. - * @param [in] nid Numeric ID of predefined DH parameters. - * @return 1 for failure. - */ -static int wolfssl_dh_set_nid(WOLFSSL_DH* dh, int nid) -{ - return 1; -} -#endif - -/* Allocate and initialize a new DH key with the parameters based on the NID. - * - * @param [in] nid Numeric ID of DH parameters. - * - * @return DH key on success. - * @return NULL on failure. - */ -WOLFSSL_DH* wolfSSL_DH_new_by_nid(int nid) -{ - WOLFSSL_DH* dh = NULL; - int err = 0; - - WOLFSSL_ENTER("wolfSSL_DH_new_by_nid"); - - /* Allocate a new DH key. */ - dh = wolfSSL_DH_new(); - if (dh == NULL) { - WOLFSSL_ERROR_MSG("Failed to create WOLFSSL_DH."); - err = 1; - } - if (!err) { - /* Set the parameters based on NID. */ - err = wolfssl_dh_set_nid(dh, nid); - } - - if (err && (dh != NULL)) { - /* Dispose of the key on failure to set. */ - wolfSSL_DH_free(dh); - dh = NULL; - } - - WOLFSSL_LEAVE("wolfSSL_DH_new_by_nid", err); - - return dh; -} - -/* Dispose of DH key and allocated data. - * - * Cannot use dh after this call. - * - * @param [in] dh DH key to free. - */ -void wolfSSL_DH_free(WOLFSSL_DH* dh) -{ - int doFree = 0; - - WOLFSSL_ENTER("wolfSSL_DH_free"); - - if (dh != NULL) { - int err; - - /* Only free if all references to it are done */ - wolfSSL_RefDec(&dh->ref, &doFree, &err); - /* Ignore errors - doFree will be 0 on error. */ - (void)err; - } - if (doFree) { - /* Dispose of allocated reference counting data. */ - wolfSSL_RefFree(&dh->ref); - - /* Dispose of wolfSSL DH key. */ - if (dh->internal) { - wc_FreeDhKey((DhKey*)dh->internal); - XFREE(dh->internal, NULL, DYNAMIC_TYPE_DH); - dh->internal = NULL; - } - - /* Dispose of any allocated BNs. */ - wolfSSL_BN_free(dh->priv_key); - wolfSSL_BN_free(dh->pub_key); - wolfSSL_BN_free(dh->g); - wolfSSL_BN_free(dh->p); - wolfSSL_BN_free(dh->q); - /* Set back to NULLs for safety. */ - XMEMSET(dh, 0, sizeof(WOLFSSL_DH)); - - XFREE(dh, NULL, DYNAMIC_TYPE_DH); - } -} - -/* Increments ref count of DH key. - * - * @param [in, out] dh DH key. - * @return 1 on success - * @return 0 on error - */ -int wolfSSL_DH_up_ref(WOLFSSL_DH* dh) -{ - int err = 1; - - WOLFSSL_ENTER("wolfSSL_DH_up_ref"); - - if (dh != NULL) { - wolfSSL_RefInc(&dh->ref, &err); - } - - return !err; -} - -#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH) || \ - defined(OPENSSL_EXTRA) - -#ifdef WOLFSSL_DH_EXTRA -/* Duplicate the DH key. - * - * Internal DH key in 'dh' is updated if necessary. - * - * @param [in, out] dh DH key to duplicate. - * @return NULL on failure. - * @return DH key on success. - */ -WOLFSSL_DH* wolfSSL_DH_dup(WOLFSSL_DH* dh) -{ - WOLFSSL_DH* ret = NULL; - int err = 0; - - WOLFSSL_ENTER("wolfSSL_DH_dup"); - - /* Validate parameters. */ - if (dh == NULL) { - WOLFSSL_ERROR_MSG("Bad parameter"); - err = 1; - } - - /* Ensure internal DH key is set. */ - if ((!err) && (dh->inSet == 0) && (SetDhInternal(dh) != 1)) { - WOLFSSL_ERROR_MSG("Bad DH set internal"); - err = 1; - } - - /* Create a new DH key object. */ - if ((!err) && (!(ret = wolfSSL_DH_new()))) { - WOLFSSL_ERROR_MSG("wolfSSL_DH_new error"); - err = 1; - } - /* Copy internal DH key from original to new. */ - if ((!err) && (wc_DhKeyCopy((DhKey*)dh->internal, (DhKey*)ret->internal) != - MP_OKAY)) { - WOLFSSL_ERROR_MSG("wc_DhKeyCopy error"); - err = 1; - } - if (!err) { - ret->inSet = 1; - - /* Synchronize the internal into external DH key's parameters. */ - if (SetDhExternal(ret) != 1) { - WOLFSSL_ERROR_MSG("SetDhExternal error"); - err = 1; - } - } - - /* Dispose of any allocated DH key on error. */ - if (err && (ret != NULL)) { - wolfSSL_DH_free(ret); - ret = NULL; - } - return ret; -} -#endif /* WOLFSSL_DH_EXTRA */ - -#endif - -/* Allocate and initialize a new DH key with 2048-bit parameters. - * - * See RFC 5114 section 2.3, "2048-bit MODP Group with 256-bit Prime Order - * Subgroup." - * - * @return NULL on failure. - * @return DH Key on success. - */ -WOLFSSL_DH* wolfSSL_DH_get_2048_256(void) -{ - WOLFSSL_DH* dh; - int err = 0; - static const byte pHex[] = { - 0x87, 0xA8, 0xE6, 0x1D, 0xB4, 0xB6, 0x66, 0x3C, 0xFF, 0xBB, 0xD1, 0x9C, - 0x65, 0x19, 0x59, 0x99, 0x8C, 0xEE, 0xF6, 0x08, 0x66, 0x0D, 0xD0, 0xF2, - 0x5D, 0x2C, 0xEE, 0xD4, 0x43, 0x5E, 0x3B, 0x00, 0xE0, 0x0D, 0xF8, 0xF1, - 0xD6, 0x19, 0x57, 0xD4, 0xFA, 0xF7, 0xDF, 0x45, 0x61, 0xB2, 0xAA, 0x30, - 0x16, 0xC3, 0xD9, 0x11, 0x34, 0x09, 0x6F, 0xAA, 0x3B, 0xF4, 0x29, 0x6D, - 0x83, 0x0E, 0x9A, 0x7C, 0x20, 0x9E, 0x0C, 0x64, 0x97, 0x51, 0x7A, 0xBD, - 0x5A, 0x8A, 0x9D, 0x30, 0x6B, 0xCF, 0x67, 0xED, 0x91, 0xF9, 0xE6, 0x72, - 0x5B, 0x47, 0x58, 0xC0, 0x22, 0xE0, 0xB1, 0xEF, 0x42, 0x75, 0xBF, 0x7B, - 0x6C, 0x5B, 0xFC, 0x11, 0xD4, 0x5F, 0x90, 0x88, 0xB9, 0x41, 0xF5, 0x4E, - 0xB1, 0xE5, 0x9B, 0xB8, 0xBC, 0x39, 0xA0, 0xBF, 0x12, 0x30, 0x7F, 0x5C, - 0x4F, 0xDB, 0x70, 0xC5, 0x81, 0xB2, 0x3F, 0x76, 0xB6, 0x3A, 0xCA, 0xE1, - 0xCA, 0xA6, 0xB7, 0x90, 0x2D, 0x52, 0x52, 0x67, 0x35, 0x48, 0x8A, 0x0E, - 0xF1, 0x3C, 0x6D, 0x9A, 0x51, 0xBF, 0xA4, 0xAB, 0x3A, 0xD8, 0x34, 0x77, - 0x96, 0x52, 0x4D, 0x8E, 0xF6, 0xA1, 0x67, 0xB5, 0xA4, 0x18, 0x25, 0xD9, - 0x67, 0xE1, 0x44, 0xE5, 0x14, 0x05, 0x64, 0x25, 0x1C, 0xCA, 0xCB, 0x83, - 0xE6, 0xB4, 0x86, 0xF6, 0xB3, 0xCA, 0x3F, 0x79, 0x71, 0x50, 0x60, 0x26, - 0xC0, 0xB8, 0x57, 0xF6, 0x89, 0x96, 0x28, 0x56, 0xDE, 0xD4, 0x01, 0x0A, - 0xBD, 0x0B, 0xE6, 0x21, 0xC3, 0xA3, 0x96, 0x0A, 0x54, 0xE7, 0x10, 0xC3, - 0x75, 0xF2, 0x63, 0x75, 0xD7, 0x01, 0x41, 0x03, 0xA4, 0xB5, 0x43, 0x30, - 0xC1, 0x98, 0xAF, 0x12, 0x61, 0x16, 0xD2, 0x27, 0x6E, 0x11, 0x71, 0x5F, - 0x69, 0x38, 0x77, 0xFA, 0xD7, 0xEF, 0x09, 0xCA, 0xDB, 0x09, 0x4A, 0xE9, - 0x1E, 0x1A, 0x15, 0x97 - }; - static const byte gHex[] = { - 0x3F, 0xB3, 0x2C, 0x9B, 0x73, 0x13, 0x4D, 0x0B, 0x2E, 0x77, 0x50, 0x66, - 0x60, 0xED, 0xBD, 0x48, 0x4C, 0xA7, 0xB1, 0x8F, 0x21, 0xEF, 0x20, 0x54, - 0x07, 0xF4, 0x79, 0x3A, 0x1A, 0x0B, 0xA1, 0x25, 0x10, 0xDB, 0xC1, 0x50, - 0x77, 0xBE, 0x46, 0x3F, 0xFF, 0x4F, 0xED, 0x4A, 0xAC, 0x0B, 0xB5, 0x55, - 0xBE, 0x3A, 0x6C, 0x1B, 0x0C, 0x6B, 0x47, 0xB1, 0xBC, 0x37, 0x73, 0xBF, - 0x7E, 0x8C, 0x6F, 0x62, 0x90, 0x12, 0x28, 0xF8, 0xC2, 0x8C, 0xBB, 0x18, - 0xA5, 0x5A, 0xE3, 0x13, 0x41, 0x00, 0x0A, 0x65, 0x01, 0x96, 0xF9, 0x31, - 0xC7, 0x7A, 0x57, 0xF2, 0xDD, 0xF4, 0x63, 0xE5, 0xE9, 0xEC, 0x14, 0x4B, - 0x77, 0x7D, 0xE6, 0x2A, 0xAA, 0xB8, 0xA8, 0x62, 0x8A, 0xC3, 0x76, 0xD2, - 0x82, 0xD6, 0xED, 0x38, 0x64, 0xE6, 0x79, 0x82, 0x42, 0x8E, 0xBC, 0x83, - 0x1D, 0x14, 0x34, 0x8F, 0x6F, 0x2F, 0x91, 0x93, 0xB5, 0x04, 0x5A, 0xF2, - 0x76, 0x71, 0x64, 0xE1, 0xDF, 0xC9, 0x67, 0xC1, 0xFB, 0x3F, 0x2E, 0x55, - 0xA4, 0xBD, 0x1B, 0xFF, 0xE8, 0x3B, 0x9C, 0x80, 0xD0, 0x52, 0xB9, 0x85, - 0xD1, 0x82, 0xEA, 0x0A, 0xDB, 0x2A, 0x3B, 0x73, 0x13, 0xD3, 0xFE, 0x14, - 0xC8, 0x48, 0x4B, 0x1E, 0x05, 0x25, 0x88, 0xB9, 0xB7, 0xD2, 0xBB, 0xD2, - 0xDF, 0x01, 0x61, 0x99, 0xEC, 0xD0, 0x6E, 0x15, 0x57, 0xCD, 0x09, 0x15, - 0xB3, 0x35, 0x3B, 0xBB, 0x64, 0xE0, 0xEC, 0x37, 0x7F, 0xD0, 0x28, 0x37, - 0x0D, 0xF9, 0x2B, 0x52, 0xC7, 0x89, 0x14, 0x28, 0xCD, 0xC6, 0x7E, 0xB6, - 0x18, 0x4B, 0x52, 0x3D, 0x1D, 0xB2, 0x46, 0xC3, 0x2F, 0x63, 0x07, 0x84, - 0x90, 0xF0, 0x0E, 0xF8, 0xD6, 0x47, 0xD1, 0x48, 0xD4, 0x79, 0x54, 0x51, - 0x5E, 0x23, 0x27, 0xCF, 0xEF, 0x98, 0xC5, 0x82, 0x66, 0x4B, 0x4C, 0x0F, - 0x6C, 0xC4, 0x16, 0x59 - }; - static const byte qHex[] = { - 0x8C, 0xF8, 0x36, 0x42, 0xA7, 0x09, 0xA0, 0x97, 0xB4, 0x47, 0x99, 0x76, - 0x40, 0x12, 0x9D, 0xA2, 0x99, 0xB1, 0xA4, 0x7D, 0x1E, 0xB3, 0x75, 0x0B, - 0xA3, 0x08, 0xB0, 0xFE, 0x64, 0xF5, 0xFB, 0xD3 - }; - - /* Create a new DH key to return. */ - dh = wolfSSL_DH_new(); - if (dh == NULL) { - err = 1; - } - if (!err) { - /* Set prime. */ - dh->p = wolfSSL_BN_bin2bn(pHex, (int)sizeof(pHex), NULL); - if (dh->p == NULL) { - WOLFSSL_ERROR_MSG("Error converting p hex to WOLFSSL_BIGNUM."); - err = 1; - } - } - if (!err) { - /* Set generator. */ - dh->g = wolfSSL_BN_bin2bn(gHex, (int)sizeof(gHex), NULL); - if (dh->g == NULL) { - WOLFSSL_ERROR_MSG("Error converting g hex to WOLFSSL_BIGNUM."); - err = 1; - } - } - if (!err) { - /* Set order. */ - dh->q = wolfSSL_BN_bin2bn(qHex, (int)sizeof(qHex), NULL); - if (dh->q == NULL) { - WOLFSSL_ERROR_MSG("Error converting q hex to WOLFSSL_BIGNUM."); - err = 1; - } - } - /* Set values into wolfSSL DH key. */ - if ((!err) && (SetDhInternal(dh) != 1)) { - WOLFSSL_ERROR_MSG("Error setting DH parameters."); - err = 1; - } - if (!err) { - /* External DH key parameters were set. */ - dh->exSet = 1; - } - - /* Dispose of any allocated DH key on error. */ - if (err && (dh != NULL)) { - wolfSSL_DH_free(dh); - dh = NULL; - } - - return dh; -} - -/* TODO: consider changing strings to byte arrays. */ - -/* Returns a big number with the 768-bit prime from RFC 2409. - * - * @param [in, out] bn If not NULL then this BN is set and returned. - * If NULL then a new BN is created, set and returned. - * - * @return NULL on failure. - * @return WOLFSSL_BIGNUM with value set to 768-bit prime on success. - */ -WOLFSSL_BIGNUM* wolfSSL_DH_768_prime(WOLFSSL_BIGNUM* bn) -{ -#if WOLFSSL_MAX_BN_BITS >= 768 - static const char prm[] = { - "FFFFFFFFFFFFFFFFC90FDAA22168C234" - "C4C6628B80DC1CD129024E088A67CC74" - "020BBEA63B139B22514A08798E3404DD" - "EF9519B3CD3A431B302B0A6DF25F1437" - "4FE1356D6D51C245E485B576625E7EC6" - "F44C42E9A63A3620FFFFFFFFFFFFFFFF" - }; - - WOLFSSL_ENTER("wolfSSL_DH_768_prime"); - - /* Set prime into BN. Creates a new BN when bn is NULL. */ - if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { - WOLFSSL_ERROR_MSG("Error converting DH 768 prime to big number"); - bn = NULL; - } - - return bn; -#else - (void)bn; - return NULL; -#endif -} - -/* Returns a big number with the 1024-bit prime from RFC 2409. - * - * @param [in, out] bn If not NULL then this BN is set and returned. - * If NULL then a new BN is created, set and returned. - * - * @return NULL on failure. - * @return WOLFSSL_BIGNUM with value set to 1024-bit prime on success. - */ -WOLFSSL_BIGNUM* wolfSSL_DH_1024_prime(WOLFSSL_BIGNUM* bn) -{ -#if WOLFSSL_MAX_BN_BITS >= 1024 - static const char prm[] = { - "FFFFFFFFFFFFFFFFC90FDAA22168C234" - "C4C6628B80DC1CD129024E088A67CC74" - "020BBEA63B139B22514A08798E3404DD" - "EF9519B3CD3A431B302B0A6DF25F1437" - "4FE1356D6D51C245E485B576625E7EC6" - "F44C42E9A637ED6B0BFF5CB6F406B7ED" - "EE386BFB5A899FA5AE9F24117C4B1FE6" - "49286651ECE65381FFFFFFFFFFFFFFFF" - }; - - WOLFSSL_ENTER("wolfSSL_DH_1024_prime"); - - /* Set prime into BN. Creates a new BN when bn is NULL. */ - if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { - WOLFSSL_ERROR_MSG("Error converting DH 1024 prime to big number"); - bn = NULL; - } - - return bn; -#else - (void)bn; - return NULL; -#endif -} - -/* Returns a big number with the 1536-bit prime from RFC 3526. - * - * @param [in, out] bn If not NULL then this BN is set and returned. - * If NULL then a new BN is created, set and returned. - * - * @return NULL on failure. - * @return WOLFSSL_BIGNUM with value set to 1536-bit prime on success. - */ -WOLFSSL_BIGNUM* wolfSSL_DH_1536_prime(WOLFSSL_BIGNUM* bn) -{ -#if WOLFSSL_MAX_BN_BITS >= 1536 - static const char prm[] = { - "FFFFFFFFFFFFFFFFC90FDAA22168C234" - "C4C6628B80DC1CD129024E088A67CC74" - "020BBEA63B139B22514A08798E3404DD" - "EF9519B3CD3A431B302B0A6DF25F1437" - "4FE1356D6D51C245E485B576625E7EC6" - "F44C42E9A637ED6B0BFF5CB6F406B7ED" - "EE386BFB5A899FA5AE9F24117C4B1FE6" - "49286651ECE45B3DC2007CB8A163BF05" - "98DA48361C55D39A69163FA8FD24CF5F" - "83655D23DCA3AD961C62F356208552BB" - "9ED529077096966D670C354E4ABC9804" - "F1746C08CA237327FFFFFFFFFFFFFFFF" - }; - - WOLFSSL_ENTER("wolfSSL_DH_1536_prime"); - - /* Set prime into BN. Creates a new BN when bn is NULL. */ - if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { - WOLFSSL_ERROR_MSG("Error converting DH 1536 prime to big number"); - bn = NULL; - } - - return bn; -#else - (void)bn; - return NULL; -#endif -} - -/* Returns a big number with the 2048-bit prime from RFC 3526. - * - * @param [in, out] bn If not NULL then this BN is set and returned. - * If NULL then a new BN is created, set and returned. - * - * @return NULL on failure. - * @return WOLFSSL_BIGNUM with value set to 2048-bit prime on success. - */ -WOLFSSL_BIGNUM* wolfSSL_DH_2048_prime(WOLFSSL_BIGNUM* bn) -{ -#if WOLFSSL_MAX_BN_BITS >= 2048 - static const char prm[] = { - "FFFFFFFFFFFFFFFFC90FDAA22168C234" - "C4C6628B80DC1CD129024E088A67CC74" - "020BBEA63B139B22514A08798E3404DD" - "EF9519B3CD3A431B302B0A6DF25F1437" - "4FE1356D6D51C245E485B576625E7EC6" - "F44C42E9A637ED6B0BFF5CB6F406B7ED" - "EE386BFB5A899FA5AE9F24117C4B1FE6" - "49286651ECE45B3DC2007CB8A163BF05" - "98DA48361C55D39A69163FA8FD24CF5F" - "83655D23DCA3AD961C62F356208552BB" - "9ED529077096966D670C354E4ABC9804" - "F1746C08CA18217C32905E462E36CE3B" - "E39E772C180E86039B2783A2EC07A28F" - "B5C55DF06F4C52C9DE2BCBF695581718" - "3995497CEA956AE515D2261898FA0510" - "15728E5A8AACAA68FFFFFFFFFFFFFFFF" - }; - - WOLFSSL_ENTER("wolfSSL_DH_2048_prime"); - - /* Set prime into BN. Creates a new BN when bn is NULL. */ - if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { - WOLFSSL_ERROR_MSG("Error converting DH 2048 prime to big number"); - bn = NULL; - } - - return bn; -#else - (void)bn; - return NULL; -#endif -} - -/* Returns a big number with the 3072-bit prime from RFC 3526. - * - * @param [in, out] bn If not NULL then this BN is set and returned. - * If NULL then a new BN is created, set and returned. - * - * @return NULL on failure. - * @return WOLFSSL_BIGNUM with value set to 3072-bit prime on success. - */ -WOLFSSL_BIGNUM* wolfSSL_DH_3072_prime(WOLFSSL_BIGNUM* bn) -{ -#if WOLFSSL_MAX_BN_BITS >= 3072 - static const char prm[] = { - "FFFFFFFFFFFFFFFFC90FDAA22168C234" - "C4C6628B80DC1CD129024E088A67CC74" - "020BBEA63B139B22514A08798E3404DD" - "EF9519B3CD3A431B302B0A6DF25F1437" - "4FE1356D6D51C245E485B576625E7EC6" - "F44C42E9A637ED6B0BFF5CB6F406B7ED" - "EE386BFB5A899FA5AE9F24117C4B1FE6" - "49286651ECE45B3DC2007CB8A163BF05" - "98DA48361C55D39A69163FA8FD24CF5F" - "83655D23DCA3AD961C62F356208552BB" - "9ED529077096966D670C354E4ABC9804" - "F1746C08CA18217C32905E462E36CE3B" - "E39E772C180E86039B2783A2EC07A28F" - "B5C55DF06F4C52C9DE2BCBF695581718" - "3995497CEA956AE515D2261898FA0510" - "15728E5A8AAAC42DAD33170D04507A33" - "A85521ABDF1CBA64ECFB850458DBEF0A" - "8AEA71575D060C7DB3970F85A6E1E4C7" - "ABF5AE8CDB0933D71E8C94E04A25619D" - "CEE3D2261AD2EE6BF12FFA06D98A0864" - "D87602733EC86A64521F2B18177B200C" - "BBE117577A615D6C770988C0BAD946E2" - "08E24FA074E5AB3143DB5BFCE0FD108E" - "4B82D120A93AD2CAFFFFFFFFFFFFFFFF" - }; - - WOLFSSL_ENTER("wolfSSL_DH_3072_prime"); - - /* Set prime into BN. Creates a new BN when bn is NULL. */ - if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { - WOLFSSL_ERROR_MSG("Error converting DH 3072 prime to big number"); - bn = NULL; - } - - return bn; -#else - (void)bn; - return NULL; -#endif -} - -/* Returns a big number with the 4096-bit prime from RFC 3526. - * - * @param [in, out] bn If not NULL then this BN is set and returned. - * If NULL then a new BN is created, set and returned. - * - * @return NULL on failure. - * @return WOLFSSL_BIGNUM with value set to 4096-bit prime on success. - */ -WOLFSSL_BIGNUM* wolfSSL_DH_4096_prime(WOLFSSL_BIGNUM* bn) -{ -#if WOLFSSL_MAX_BN_BITS >= 4096 - static const char prm[] = { - "FFFFFFFFFFFFFFFFC90FDAA22168C234" - "C4C6628B80DC1CD129024E088A67CC74" - "020BBEA63B139B22514A08798E3404DD" - "EF9519B3CD3A431B302B0A6DF25F1437" - "4FE1356D6D51C245E485B576625E7EC6" - "F44C42E9A637ED6B0BFF5CB6F406B7ED" - "EE386BFB5A899FA5AE9F24117C4B1FE6" - "49286651ECE45B3DC2007CB8A163BF05" - "98DA48361C55D39A69163FA8FD24CF5F" - "83655D23DCA3AD961C62F356208552BB" - "9ED529077096966D670C354E4ABC9804" - "F1746C08CA18217C32905E462E36CE3B" - "E39E772C180E86039B2783A2EC07A28F" - "B5C55DF06F4C52C9DE2BCBF695581718" - "3995497CEA956AE515D2261898FA0510" - "15728E5A8AAAC42DAD33170D04507A33" - "A85521ABDF1CBA64ECFB850458DBEF0A" - "8AEA71575D060C7DB3970F85A6E1E4C7" - "ABF5AE8CDB0933D71E8C94E04A25619D" - "CEE3D2261AD2EE6BF12FFA06D98A0864" - "D87602733EC86A64521F2B18177B200C" - "BBE117577A615D6C770988C0BAD946E2" - "08E24FA074E5AB3143DB5BFCE0FD108E" - "4B82D120A92108011A723C12A787E6D7" - "88719A10BDBA5B2699C327186AF4E23C" - "1A946834B6150BDA2583E9CA2AD44CE8" - "DBBBC2DB04DE8EF92E8EFC141FBECAA6" - "287C59474E6BC05D99B2964FA090C3A2" - "233BA186515BE7ED1F612970CEE2D7AF" - "B81BDD762170481CD0069127D5B05AA9" - "93B4EA988D8FDDC186FFB7DC90A6C08F" - "4DF435C934063199FFFFFFFFFFFFFFFF" - }; - - WOLFSSL_ENTER("wolfSSL_DH_4096_prime"); - - /* Set prime into BN. Creates a new BN when bn is NULL. */ - if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { - WOLFSSL_ERROR_MSG("Error converting DH 4096 prime to big number"); - bn = NULL; - } - - return bn; -#else - (void)bn; - return NULL; -#endif -} - -/* Returns a big number with the 6144-bit prime from RFC 3526. - * - * @param [in, out] bn If not NULL then this BN is set and returned. - * If NULL then a new BN is created, set and returned. - * - * @return NULL on failure. - * @return WOLFSSL_BIGNUM with value set to 6144-bit prime on success. - */ -WOLFSSL_BIGNUM* wolfSSL_DH_6144_prime(WOLFSSL_BIGNUM* bn) -{ -#if WOLFSSL_MAX_BN_BITS >= 6144 - static const char prm[] = { - "FFFFFFFFFFFFFFFFC90FDAA22168C234" - "C4C6628B80DC1CD129024E088A67CC74" - "020BBEA63B139B22514A08798E3404DD" - "EF9519B3CD3A431B302B0A6DF25F1437" - "4FE1356D6D51C245E485B576625E7EC6" - "F44C42E9A637ED6B0BFF5CB6F406B7ED" - "EE386BFB5A899FA5AE9F24117C4B1FE6" - "49286651ECE45B3DC2007CB8A163BF05" - "98DA48361C55D39A69163FA8FD24CF5F" - "83655D23DCA3AD961C62F356208552BB" - "9ED529077096966D670C354E4ABC9804" - "F1746C08CA18217C32905E462E36CE3B" - "E39E772C180E86039B2783A2EC07A28F" - "B5C55DF06F4C52C9DE2BCBF695581718" - "3995497CEA956AE515D2261898FA0510" - "15728E5A8AAAC42DAD33170D04507A33" - "A85521ABDF1CBA64ECFB850458DBEF0A" - "8AEA71575D060C7DB3970F85A6E1E4C7" - "ABF5AE8CDB0933D71E8C94E04A25619D" - "CEE3D2261AD2EE6BF12FFA06D98A0864" - "D87602733EC86A64521F2B18177B200C" - "BBE117577A615D6C770988C0BAD946E2" - "08E24FA074E5AB3143DB5BFCE0FD108E" - "4B82D120A92108011A723C12A787E6D7" - "88719A10BDBA5B2699C327186AF4E23C" - "1A946834B6150BDA2583E9CA2AD44CE8" - "DBBBC2DB04DE8EF92E8EFC141FBECAA6" - "287C59474E6BC05D99B2964FA090C3A2" - "233BA186515BE7ED1F612970CEE2D7AF" - "B81BDD762170481CD0069127D5B05AA9" - "93B4EA988D8FDDC186FFB7DC90A6C08F" - "4DF435C93402849236C3FAB4D27C7026" - "C1D4DCB2602646DEC9751E763DBA37BD" - "F8FF9406AD9E530EE5DB382F413001AE" - "B06A53ED9027D831179727B0865A8918" - "DA3EDBEBCF9B14ED44CE6CBACED4BB1B" - "DB7F1447E6CC254B332051512BD7AF42" - "6FB8F401378CD2BF5983CA01C64B92EC" - "F032EA15D1721D03F482D7CE6E74FEF6" - "D55E702F46980C82B5A84031900B1C9E" - "59E7C97FBEC7E8F323A97A7E36CC88BE" - "0F1D45B7FF585AC54BD407B22B4154AA" - "CC8F6D7EBF48E1D814CC5ED20F8037E0" - "A79715EEF29BE32806A1D58BB7C5DA76" - "F550AA3D8A1FBFF0EB19CCB1A313D55C" - "DA56C9EC2EF29632387FE8D76E3C0468" - "043E8F663F4860EE12BF2D5B0B7474D6" - "E694F91E6DCC4024FFFFFFFFFFFFFFFF" - }; - - WOLFSSL_ENTER("wolfSSL_DH_6144_prime"); - - /* Set prime into BN. Creates a new BN when bn is NULL. */ - if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { - WOLFSSL_ERROR_MSG("Error converting DH 6144 prime to big number"); - bn = NULL; - } - - return bn; -#else - (void)bn; - return NULL; -#endif -} - - -/* Returns a big number with the 8192-bit prime from RFC 3526. - * - * @param [in, out] bn If not NULL then this BN is set and returned. - * If NULL then a new BN is created, set and returned. - * - * @return NULL on failure. - * @return WOLFSSL_BIGNUM with value set to 8192-bit prime on success. - */ -WOLFSSL_BIGNUM* wolfSSL_DH_8192_prime(WOLFSSL_BIGNUM* bn) -{ -#if WOLFSSL_MAX_BN_BITS >= 8192 - static const char prm[] = { - "FFFFFFFFFFFFFFFFC90FDAA22168C234" - "C4C6628B80DC1CD129024E088A67CC74" - "020BBEA63B139B22514A08798E3404DD" - "EF9519B3CD3A431B302B0A6DF25F1437" - "4FE1356D6D51C245E485B576625E7EC6" - "F44C42E9A637ED6B0BFF5CB6F406B7ED" - "EE386BFB5A899FA5AE9F24117C4B1FE6" - "49286651ECE45B3DC2007CB8A163BF05" - "98DA48361C55D39A69163FA8FD24CF5F" - "83655D23DCA3AD961C62F356208552BB" - "9ED529077096966D670C354E4ABC9804" - "F1746C08CA18217C32905E462E36CE3B" - "E39E772C180E86039B2783A2EC07A28F" - "B5C55DF06F4C52C9DE2BCBF695581718" - "3995497CEA956AE515D2261898FA0510" - "15728E5A8AAAC42DAD33170D04507A33" - "A85521ABDF1CBA64ECFB850458DBEF0A" - "8AEA71575D060C7DB3970F85A6E1E4C7" - "ABF5AE8CDB0933D71E8C94E04A25619D" - "CEE3D2261AD2EE6BF12FFA06D98A0864" - "D87602733EC86A64521F2B18177B200C" - "BBE117577A615D6C770988C0BAD946E2" - "08E24FA074E5AB3143DB5BFCE0FD108E" - "4B82D120A92108011A723C12A787E6D7" - "88719A10BDBA5B2699C327186AF4E23C" - "1A946834B6150BDA2583E9CA2AD44CE8" - "DBBBC2DB04DE8EF92E8EFC141FBECAA6" - "287C59474E6BC05D99B2964FA090C3A2" - "233BA186515BE7ED1F612970CEE2D7AF" - "B81BDD762170481CD0069127D5B05AA9" - "93B4EA988D8FDDC186FFB7DC90A6C08F" - "4DF435C93402849236C3FAB4D27C7026" - "C1D4DCB2602646DEC9751E763DBA37BD" - "F8FF9406AD9E530EE5DB382F413001AE" - "B06A53ED9027D831179727B0865A8918" - "DA3EDBEBCF9B14ED44CE6CBACED4BB1B" - "DB7F1447E6CC254B332051512BD7AF42" - "6FB8F401378CD2BF5983CA01C64B92EC" - "F032EA15D1721D03F482D7CE6E74FEF6" - "D55E702F46980C82B5A84031900B1C9E" - "59E7C97FBEC7E8F323A97A7E36CC88BE" - "0F1D45B7FF585AC54BD407B22B4154AA" - "CC8F6D7EBF48E1D814CC5ED20F8037E0" - "A79715EEF29BE32806A1D58BB7C5DA76" - "F550AA3D8A1FBFF0EB19CCB1A313D55C" - "DA56C9EC2EF29632387FE8D76E3C0468" - "043E8F663F4860EE12BF2D5B0B7474D6" - "E694F91E6DBE115974A3926F12FEE5E4" - "38777CB6A932DF8CD8BEC4D073B931BA" - "3BC832B68D9DD300741FA7BF8AFC47ED" - "2576F6936BA424663AAB639C5AE4F568" - "3423B4742BF1C978238F16CBE39D652D" - "E3FDB8BEFC848AD922222E04A4037C07" - "13EB57A81A23F0C73473FC646CEA306B" - "4BCBC8862F8385DDFA9D4B7FA2C087E8" - "79683303ED5BDD3A062B3CF5B3A278A6" - "6D2A13F83F44F82DDF310EE074AB6A36" - "4597E899A0255DC164F31CC50846851D" - "F9AB48195DED7EA1B1D510BD7EE74D73" - "FAF36BC31ECFA268359046F4EB879F92" - "4009438B481C6CD7889A002ED5EE382B" - "C9190DA6FC026E479558E4475677E9AA" - "9E3050E2765694DFC81F56E880B96E71" - "60C980DD98EDD3DFFFFFFFFFFFFFFFFF" - }; - - WOLFSSL_ENTER("wolfSSL_DH_8192_prime"); - - /* Set prime into BN. Creates a new BN when bn is NULL. */ - if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { - WOLFSSL_ERROR_MSG("Error converting DH 8192 prime to big number"); - bn = NULL; - } - - return bn; -#else - (void)bn; - return NULL; -#endif -} - -/* - * DH to/from bin APIs - */ - -#ifndef NO_CERTS - -/* Load the DER encoded DH parameters into DH key. - * - * @param [in, out] dh DH key to load parameters into. - * @param [in] der Buffer holding DER encoded parameters data. - * @param [in, out] idx On in, index at which DH key DER data starts. - * On out, index after DH key DER data. - * @param [in] derSz Size of DER buffer in bytes. - * - * @return 0 on success. - * @return 1 when decoding DER or setting the external key fails. - */ -static int wolfssl_dh_load_params(WOLFSSL_DH* dh, const unsigned char* der, - word32* idx, word32 derSz) -{ - int err = 0; - -#if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) - int ret; - - /* Decode DH parameters/key from DER. */ - ret = wc_DhKeyDecode(der, idx, (DhKey*)dh->internal, derSz); - if (ret != 0) { - WOLFSSL_ERROR_MSG("DhKeyDecode() failed"); - err = 1; - } - if (!err) { - /* wolfSSL DH key set. */ - dh->inSet = 1; - - /* Set the external DH key based on wolfSSL DH key. */ - if (SetDhExternal(dh) != 1) { - WOLFSSL_ERROR_MSG("SetDhExternal failed"); - err = 1; - } - } -#else - byte* p; - byte* g; - word32 pSz = MAX_DH_SIZE; - word32 gSz = MAX_DH_SIZE; - - /* Only DH parameters supported. */ - /* Load external and set internal. */ - p = (byte*)XMALLOC(pSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - g = (byte*)XMALLOC(gSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - if ((p == NULL) || (g == NULL)) { - err = 1; - } - /* Extract the p and g as data from the DER encoded DH parameters. */ - if ((!err) && (wc_DhParamsLoad(der + *idx, derSz - *idx, p, &pSz, g, - &gSz) < 0)) { - err = 1; - } - if (!err) { - /* Put p and g in as big numbers - free existing BNs. */ - if (dh->p != NULL) { - wolfSSL_BN_free(dh->p); - dh->p = NULL; - } - if (dh->g != NULL) { - wolfSSL_BN_free(dh->g); - dh->g = NULL; - } - dh->p = wolfSSL_BN_bin2bn(p, (int)pSz, NULL); - dh->g = wolfSSL_BN_bin2bn(g, (int)gSz, NULL); - if (dh->p == NULL || dh->g == NULL) { - err = 1; - } - else { - /* External DH key parameters were set. */ - dh->exSet = 1; - } - } - - /* Set internal as the outside has been updated. */ - if ((!err) && (SetDhInternal(dh) != 1)) { - WOLFSSL_ERROR_MSG("Unable to set internal DH structure"); - err = 1; - } - - if (!err) { - *idx += wolfssl_der_length(der + *idx, derSz - *idx); - } - - XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - XFREE(g, NULL, DYNAMIC_TYPE_PUBLIC_KEY); -#endif - - return err; -} - -#ifdef OPENSSL_ALL - -#if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) -/* Convert DER encoded DH parameters to a WOLFSSL_DH structure. - * - * @param [out] dh DH key to put parameters into. May be NULL. - * @param [in, out] pp Pointer to DER encoded DH parameters. - * Value updated to end of data when dh is not NULL. - * @param [in] length Length of data available in bytes. - * - * @return DH key on success. - * @return NULL on failure. - */ -WOLFSSL_DH *wolfSSL_d2i_DHparams(WOLFSSL_DH** dh, const unsigned char** pp, - long length) -{ - WOLFSSL_DH *newDh = NULL; - word32 idx = 0; - int err = 0; - - WOLFSSL_ENTER("wolfSSL_d2i_DHparams"); - - /* Validate parameters. */ - if ((pp == NULL) || (length <= 0)) { - WOLFSSL_ERROR_MSG("bad argument"); - err = 1; - } - - /* Create new DH key to return. */ - if ((!err) && ((newDh = wolfSSL_DH_new()) == NULL)) { - WOLFSSL_ERROR_MSG("wolfSSL_DH_new() failed"); - err = 1; - } - if ((!err) && (wolfssl_dh_load_params(newDh, *pp, &idx, - (word32)length) != 0)) { - WOLFSSL_ERROR_MSG("Loading DH parameters failed"); - err = 1; - } - - if ((!err) && (dh != NULL)) { - /* Return through parameter too. */ - *dh = newDh; - /* Move buffer on by the used amount. */ - *pp += idx; - } - - if (err && (newDh != NULL)) { - /* Dispose of any created DH key. */ - wolfSSL_DH_free(newDh); - newDh = NULL; - } - return newDh; -} -#endif /* !HAVE_FIPS || FIPS_VERSION_GT(2,0) */ - -/* Converts internal WOLFSSL_DH structure to DER encoded DH parameters. - * - * @params [in] dh DH key with parameters to encode. - * @params [in, out] out Pointer to buffer to encode into. - * When NULL or pointer to NULL, only length returned. - * @return 0 on error. - * @return Size of DER encoding in bytes on success. - */ -int wolfSSL_i2d_DHparams(const WOLFSSL_DH *dh, unsigned char **out) -{ -#if (!defined(HAVE_FIPS) || FIPS_VERSION_GT(5,0)) && defined(WOLFSSL_DH_EXTRA) - /* Set length to an arbitrarily large value for wc_DhParamsToDer(). */ - word32 len = (word32)-1; - int err = 0; - - /* Validate parameters. */ - if (dh == NULL) { - WOLFSSL_ERROR_MSG("Bad parameters"); - err = 1; - } - - /* Push external DH data into internal DH key if not set. */ - if ((!err) && (!dh->inSet) && (SetDhInternal((WOLFSSL_DH*)dh) != 1)) { - WOLFSSL_ERROR_MSG("Bad DH set internal"); - err = 1; - } - if (!err) { - int ret; - unsigned char* der = NULL; - - /* Use *out when available otherwise NULL. */ - if (out != NULL) { - der = *out; - } - /* Get length and/or encode. */ - ret = wc_DhParamsToDer((DhKey*)dh->internal, der, &len); - /* Length of encoded data is returned on success. */ - if (ret > 0) { - *out += len; - } - /* An error occurred unless only length returned. */ - else if (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { - err = 1; - } - } - - /* Set return to 0 on error. */ - if (err) { - len = 0; - } - return (int)len; -#else - word32 len; - int ret = 0; - int pSz; - int gSz; - - WOLFSSL_ENTER("wolfSSL_i2d_DHparams"); - - /* Validate parameters. */ - if (dh == NULL) { - WOLFSSL_ERROR_MSG("Bad parameters"); - len = 0; - } - else { - /* SEQ - * INT [0x00] - * INT [0x00] - * Integers have 0x00 prepended if the top bit of positive number is - * set. - */ - /* Get total length of prime including any prepended zeros. */ - pSz = mp_unsigned_bin_size((mp_int*)dh->p->internal) + - mp_leading_bit((mp_int*)dh->p->internal); - /* Get total length of generator including any prepended zeros. */ - gSz = mp_unsigned_bin_size((mp_int*)dh->g->internal) + - mp_leading_bit((mp_int*)dh->g->internal); - /* Calculate length of data in sequence. */ - len = 1 + ASN_LEN_SIZE(pSz) + pSz + - 1 + ASN_LEN_SIZE(gSz) + gSz; - /* Add in the length of the SEQUENCE. */ - len += 1 + ASN_LEN_SIZE(len); - - if ((out != NULL) && (*out != NULL)) { - /* Encode parameters. */ - ret = StoreDHparams(*out, &len, (mp_int*)dh->p->internal, - (mp_int*)dh->g->internal); - if (ret != MP_OKAY) { - WOLFSSL_ERROR_MSG("StoreDHparams error"); - len = 0; - } - else { - /* Move pointer on if encoded. */ - *out += len; - } - } - } - - return (int)len; -#endif -} - -#endif /* OPENSSL_ALL */ - -#endif /* !NO_CERTS */ - -#endif /* OPENSSL_EXTRA */ - -#if defined(OPENSSL_EXTRA) || \ - ((!defined(NO_BIO) || !defined(NO_FILESYSTEM)) && \ - defined(HAVE_LIGHTY) || defined(HAVE_STUNNEL) || \ - defined(WOLFSSL_MYSQL_COMPATIBLE)) - -/* Load the DER encoded DH parameters into DH key. - * - * @param [in, out] dh DH key to load parameters into. - * @param [in] derBuf Buffer holding DER encoded parameters data. - * @param [in] derSz Size of DER data in buffer in bytes. - * - * @return 1 on success. - * @return -1 when DH or derBuf is NULL, - * internal DH key in DH is NULL, - * derSz is 0 or less, - * error decoding DER data or - * setting external parameter values fails. - */ -int wolfSSL_DH_LoadDer(WOLFSSL_DH* dh, const unsigned char* derBuf, int derSz) -{ - int ret = 1; - word32 idx = 0; - - /* Validate parameters. */ - if ((dh == NULL) || (dh->internal == NULL) || (derBuf == NULL) || - (derSz <= 0)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = WOLFSSL_FATAL_ERROR; - } - - if ((ret == 1) && (wolfssl_dh_load_params(dh, derBuf, &idx, - (word32)derSz) != 0)) { - WOLFSSL_ERROR_MSG("DH key decode failed"); - ret = WOLFSSL_FATAL_ERROR; - } - - return ret; -} - -#endif - -/* - * DH PEM APIs - */ - -#if defined(HAVE_LIGHTY) || defined(HAVE_STUNNEL) \ - || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA) - -#if !defined(NO_BIO) || !defined(NO_FILESYSTEM) -/* Create a DH key by reading the PEM encoded data from the BIO. - * - * @param [in] bio BIO object to read from. - * @param [in, out] dh DH key to use. May be NULL. - * @param [in] pem PEM data to decode. - * @param [in] pemSz Size of PEM data in bytes. - * @param [in] memAlloced Indicates that pem was allocated and is to be - * freed after use. - * @return DH key on success. - * @return NULL on failure. - */ -static WOLFSSL_DH *wolfssl_dhparams_read_pem(WOLFSSL_DH **dh, - unsigned char* pem, int pemSz, int memAlloced) -{ - WOLFSSL_DH* localDh = NULL; - DerBuffer *der = NULL; - int err = 0; - - /* Convert PEM to DER assuming DH Parameter format. */ - if ((!err) && (PemToDer(pem, pemSz, DH_PARAM_TYPE, &der, NULL, NULL, - NULL) < 0)) { - /* Convert PEM to DER assuming X9.42 DH Parameter format. */ - if (PemToDer(pem, pemSz, X942_PARAM_TYPE, &der, NULL, NULL, NULL) - != 0) { - err = 1; - } - /* If Success on X9.42 DH format, clear error from failed DH format */ - else { - unsigned long error; - CLEAR_ASN_NO_PEM_HEADER_ERROR(error); - } - } - if (memAlloced) { - /* PEM data no longer needed. */ - XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); - } - - if (!err) { - /* Use the DH key passed in or allocate a new one. */ - if (dh != NULL) { - localDh = *dh; - } - if (localDh == NULL) { - localDh = wolfSSL_DH_new(); - if (localDh == NULL) { - err = 1; - } - } - } - /* Load the DER encoded DH parameters from buffer into a DH key. */ - if ((!err) && (wolfSSL_DH_LoadDer(localDh, der->buffer, (int)der->length) - != 1)) { - /* Free an allocated DH key. */ - if ((dh == NULL) || (localDh != *dh)) { - wolfSSL_DH_free(localDh); - } - localDh = NULL; - err = 1; - } - /* Return the DH key on success. */ - if ((!err) && (dh != NULL)) { - *dh = localDh; - } - - /* Dispose of DER data. */ - if (der != NULL) { - FreeDer(&der); - } - return localDh; -} -#endif /* !NO_BIO || !NO_FILESYSTEM */ - -#ifndef NO_BIO -/* Create a DH key by reading the PEM encoded data from the BIO. - * - * DH parameters are public data and are not expected to be encrypted. - * - * @param [in] bio BIO object to read from. - * @param [in, out] dh DH key to When pointer to - * NULL, a new DH key is created. - * @param [in] cb Password callback when PEM encrypted. Not used. - * @param [in] pass NUL terminated string for passphrase when PEM - * encrypted. Not used. - * @return DH key on success. - * @return NULL on failure. - */ -WOLFSSL_DH *wolfSSL_PEM_read_bio_DHparams(WOLFSSL_BIO *bio, WOLFSSL_DH **dh, - wc_pem_password_cb *cb, void *pass) -{ - WOLFSSL_DH* localDh = NULL; - int err = 0; - unsigned char* mem = NULL; - int size = 0; - int memAlloced = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_DHparams"); - - (void)cb; - (void)pass; - - /* Validate parameters. */ - if (bio == NULL) { - WOLFSSL_ERROR_MSG("Bad Function Argument bio is NULL"); - err = 1; - } - - /* Get buffer of data from BIO or read data from the BIO into a new buffer. - */ - if ((!err) && (wolfssl_read_bio(bio, (char**)&mem, &size, &memAlloced) - != 0)) { - err = 1; - } - if (!err) { - /* Create a DH key from the PEM - try two different headers. */ - localDh = wolfssl_dhparams_read_pem(dh, mem, size, memAlloced); - } - - return localDh; -} - -#endif /* !NO_BIO */ - -#ifndef NO_FILESYSTEM -/* Read DH parameters from a file pointer into DH key. - * - * DH parameters are public data and are not expected to be encrypted. - * - * @param [in] fp File pointer to read DH parameter file from. - * @param [in, out] dh DH key with parameters if not NULL. When pointer to - * NULL, a new DH key is created. - * @param [in] cb Password callback when PEM encrypted. Not used. - * @param [in] pass NUL terminated string for passphrase when PEM - * encrypted. Not used. - * - * @return NULL on failure. - * @return DH key with parameters set on success. - */ -WOLFSSL_DH* wolfSSL_PEM_read_DHparams(XFILE fp, WOLFSSL_DH** dh, - wc_pem_password_cb* cb, void* pass) -{ - WOLFSSL_DH* localDh = NULL; - int err = 0; - unsigned char* mem = NULL; - int size = 0; - - (void)cb; - (void)pass; - - /* Read data from file pointer. */ - if (wolfssl_read_file(fp, (char**)&mem, &size) != 0) { - err = 1; - } - if (!err) { - localDh = wolfssl_dhparams_read_pem(dh, mem, size, 1); - } - - return localDh; -} -#endif /* !NO_FILESYSTEM */ - -#if defined(WOLFSSL_DH_EXTRA) && !defined(NO_FILESYSTEM) -/* Encoded parameter data in DH key as DER. - * - * @param [in, out] dh DH key object to encode. - * @param [out] out Buffer containing DER encoding. - * @param [in] heap Heap hint. - * @return <0 on error. - * @return Length of DER encoded DH parameters in bytes. - */ -static int wolfssl_dhparams_to_der(WOLFSSL_DH* dh, unsigned char** out, - void* heap) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); - int err = 0; - byte* der = NULL; - word32 derSz = 0; - DhKey* key = NULL; - - (void)heap; - - /* Set internal parameters based on external parameters. */ - if ((dh->inSet == 0) && (SetDhInternal(dh) != 1)) { - WOLFSSL_ERROR_MSG("Unable to set internal DH structure"); - err = 1; - } - if (!err) { - /* Use wolfSSL API to get length of DER encode DH parameters. */ - key = (DhKey*)dh->internal; - ret = wc_DhParamsToDer(key, NULL, &derSz); - if (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { - WOLFSSL_ERROR_MSG("Failed to get size of DH params"); - err = 1; - } - } - - if (!err) { - /* Allocate memory for DER encoding. */ - der = (byte*)XMALLOC(derSz, heap, DYNAMIC_TYPE_TMP_BUFFER); - if (der == NULL) { - WOLFSSL_LEAVE("wolfssl_dhparams_to_der", MEMORY_E); - err = 1; - } - } - if (!err) { - /* Encode DH parameters into DER buffer. */ - ret = wc_DhParamsToDer(key, der, &derSz); - if (ret < 0) { - WOLFSSL_ERROR_MSG("Failed to export DH params"); - err = 1; - } - } - - if (!err) { - *out = der; - der = NULL; - } - XFREE(der, heap, DYNAMIC_TYPE_TMP_BUFFER); - - return ret; -} - -/* Writes the DH parameters in PEM format from "dh" out to the file pointer - * passed in. - * - * @param [in] fp File pointer to write to. - * @param [in] dh DH key to write. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_PEM_write_DHparams(XFILE fp, WOLFSSL_DH* dh) -{ - int ret = 1; - int derSz = 0; - byte* derBuf = NULL; - void* heap = NULL; - - WOLFSSL_ENTER("wolfSSL_PEM_write_DHparams"); - - /* Validate parameters. */ - if ((fp == XBADFILE) || (dh == NULL)) { - WOLFSSL_ERROR_MSG("Bad Function Arguments"); - ret = 0; - } - - if (ret == 1) { - DhKey* key = (DhKey*)dh->internal; - if (key) - heap = key->heap; - if ((derSz = wolfssl_dhparams_to_der(dh, &derBuf, heap)) < 0) { - WOLFSSL_ERROR_MSG("DER encoding failed"); - ret = 0; - } - if (derBuf == NULL) { - WOLFSSL_ERROR_MSG("DER encoding failed to get buffer"); - ret = 0; - } - } - if ((ret == 1) && (der_write_to_file_as_pem(derBuf, derSz, fp, - DH_PARAM_TYPE, NULL) != 1)) { - ret = 0; - } - - /* Dispose of DER buffer. */ - XFREE(derBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); - - WOLFSSL_LEAVE("wolfSSL_PEM_write_DHparams", ret); - - return ret; -} -#endif /* WOLFSSL_DH_EXTRA && !NO_FILESYSTEM */ - -#endif /* HAVE_LIGHTY || HAVE_STUNNEL || WOLFSSL_MYSQL_COMPATIBLE || - * OPENSSL_EXTRA */ - -/* - * DH get/set APIs - */ - -#ifdef OPENSSL_EXTRA - -#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) \ - || defined(WOLFSSL_OPENSSH) || defined(OPENSSL_EXTRA) - -/* Set the members of DhKey into WOLFSSL_DH - * Specify elements to set via the 2nd parameter - * - * @param [in, out] dh DH key to synchronize. - * @param [in] elm Elements to synchronize. - * @return 1 on success. - * @return -1 on failure. - */ -int SetDhExternal_ex(WOLFSSL_DH *dh, int elm) -{ - int ret = 1; - DhKey *key = NULL; - - WOLFSSL_ENTER("SetDhExternal_ex"); - - /* Validate parameters. */ - if ((dh == NULL) || (dh->internal == NULL)) { - WOLFSSL_ERROR_MSG("dh key NULL error"); - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 1) { - /* Get the wolfSSL DH key. */ - key = (DhKey*)dh->internal; - } - - if ((ret == 1) && (elm & ELEMENT_P)) { - /* Set the prime. */ - if (wolfssl_bn_set_value(&dh->p, &key->p) != 1) { - WOLFSSL_ERROR_MSG("dh param p error"); - ret = WOLFSSL_FATAL_ERROR; - } - } - if ((ret == 1) && (elm & ELEMENT_G)) { - /* Set the generator. */ - if (wolfssl_bn_set_value(&dh->g, &key->g) != 1) { - WOLFSSL_ERROR_MSG("dh param g error"); - ret = WOLFSSL_FATAL_ERROR; - } - } - if ((ret == 1) && (elm & ELEMENT_Q)) { - /* Set the order. */ - if (wolfssl_bn_set_value(&dh->q, &key->q) != 1) { - WOLFSSL_ERROR_MSG("dh param q error"); - ret = WOLFSSL_FATAL_ERROR; - } - } -#ifdef WOLFSSL_DH_EXTRA - if ((ret == 1) && (elm & ELEMENT_PRV)) { - /* Set the private key. */ - if (wolfssl_bn_set_value(&dh->priv_key, &key->priv) != 1) { - WOLFSSL_ERROR_MSG("No DH Private Key"); - ret = WOLFSSL_FATAL_ERROR; - } - } - if ((ret == 1) && (elm & ELEMENT_PUB)) { - /* Set the public key. */ - if (wolfssl_bn_set_value(&dh->pub_key, &key->pub) != 1) { - WOLFSSL_ERROR_MSG("No DH Public Key"); - ret = WOLFSSL_FATAL_ERROR; - } - } -#endif /* WOLFSSL_DH_EXTRA */ - - if (ret == 1) { - /* On success record that the external values have been set. */ - dh->exSet = 1; - } - - return ret; -} -/* Set the members of DhKey into WOLFSSL_DH - * DhKey was populated from wc_DhKeyDecode - * p, g, pub_key and priv_key are set. - * - * @param [in, out] dh DH key to synchronize. - * @return 1 on success. - * @return -1 on failure. - */ -int SetDhExternal(WOLFSSL_DH *dh) -{ - /* Assuming Q not required when using this API. */ - int elements = ELEMENT_P | ELEMENT_G | ELEMENT_PUB | ELEMENT_PRV; - WOLFSSL_ENTER("SetDhExternal"); - return SetDhExternal_ex(dh, elements); -} -#endif /* WOLFSSL_QT || OPENSSL_ALL || WOLFSSL_OPENSSH || OPENSSL_EXTRA */ - -/* Set the internal/wolfSSL DH key with data from the external parts. - * - * @param [in, out] dh DH key to synchronize. - * @return 1 on success. - * @return -1 on failure. - */ -int SetDhInternal(WOLFSSL_DH* dh) -{ - int ret = 1; - DhKey *key = NULL; - - WOLFSSL_ENTER("SetDhInternal"); - - /* Validate parameters. */ - if ((dh == NULL) || (dh->p == NULL) || (dh->g == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = WOLFSSL_FATAL_ERROR; - } - if (ret == 1) { - /* Get the wolfSSL DH key. */ - key = (DhKey*)dh->internal; - - /* Clear out key and initialize. */ - wc_FreeDhKey(key); - if (wc_InitDhKey(key) != 0) { - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 1) { - /* Transfer prime. */ - if (wolfssl_bn_get_value(dh->p, &key->p) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 1) { - /* Transfer generator. */ - if (wolfssl_bn_get_value(dh->g, &key->g) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - } -#ifdef HAVE_FFDHE_Q - /* Transfer order if available. */ - if ((ret == 1) && (dh->q != NULL)) { - if (wolfssl_bn_get_value(dh->q, &key->q) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - } -#endif -#ifdef WOLFSSL_DH_EXTRA - /* Transfer private key if available. */ - if ((ret == 1) && (dh->priv_key != NULL) && - (!wolfSSL_BN_is_zero(dh->priv_key))) { - if (wolfssl_bn_get_value(dh->priv_key, &key->priv) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - } - /* Transfer public key if available. */ - if ((ret == 1) && (dh->pub_key != NULL) && - (!wolfSSL_BN_is_zero(dh->pub_key))) { - if (wolfssl_bn_get_value(dh->pub_key, &key->pub) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - } -#endif /* WOLFSSL_DH_EXTRA */ - - if (ret == 1) { - /* On success record that the internal values have been set. */ - dh->inSet = 1; - } - - return ret; -} - -/* Get the size, in bytes, of the DH key. - * - * Return code compliant with OpenSSL. - * - * @param [in] dh DH key. - * @return -1 on error. - * @return Size of DH key in bytes on success. - */ -int wolfSSL_DH_size(WOLFSSL_DH* dh) -{ - WOLFSSL_ENTER("wolfSSL_DH_size"); - - if (dh == NULL) - return WOLFSSL_FATAL_ERROR; - - /* Validate parameter. */ - /* Size of key is size of prime in bytes. */ - return wolfSSL_BN_num_bytes(dh->p); -} - -/** - * Return parameters p, q and/or g of the DH key. - * - * @param [in] dh DH key to retrieve parameters from. - * @param [out] p Pointer to return prime in. May be NULL. - * @param [out] q Pointer to return order in. May be NULL. - * @param [out] g Pointer to return generator in. May be NULL. - */ -void wolfSSL_DH_get0_pqg(const WOLFSSL_DH *dh, const WOLFSSL_BIGNUM **p, - const WOLFSSL_BIGNUM **q, const WOLFSSL_BIGNUM **g) -{ - WOLFSSL_ENTER("wolfSSL_DH_get0_pqg"); - - if (dh != NULL) { - /* Return prime if required. */ - if (p != NULL) { - *p = dh->p; - } - /* Return order if required. */ - if (q != NULL) { - *q = dh->q; - } - /* Return generator if required. */ - if (g != NULL) { - *g = dh->g; - } - } -} - -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS) && !defined(WOLFSSL_DH_EXTRA)) \ - || (defined(HAVE_FIPS_VERSION) && FIPS_VERSION_GT(2,0)) -#if defined(OPENSSL_ALL) || \ - defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L -/* Sets the parameters p, g and optionally q into the DH key. - * - * Ownership of p, q and g get taken over by "dh" on success and should be - * free'd with a call to wolfSSL_DH_free -- not individually. - * - * @param [in, out] dh DH key to set. - * @param [in] p Prime value to set. May be NULL when value already - * present. - * @param [in] q Order value to set. May be NULL. - * @param [in] g Generator value to set. May be NULL when value already - * present. - * @return 1 on success. - * @return 0 on failure. - */ -int wolfSSL_DH_set0_pqg(WOLFSSL_DH *dh, WOLFSSL_BIGNUM *p, - WOLFSSL_BIGNUM *q, WOLFSSL_BIGNUM *g) -{ - int ret = 1; - - WOLFSSL_ENTER("wolfSSL_DH_set0_pqg"); - - /* Validate parameters - q is optional. */ - if (dh == NULL) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = 0; - } - /* p can be NULL if we already have one set. */ - if ((ret == 1) && (p == NULL) && (dh->p == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = 0; - } - /* g can be NULL if we already have one set. */ - if ((ret == 1) && (g == NULL) && (dh->g == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = 0; - } - - if (ret == 1) { - /* Invalidate internal key. */ - dh->inSet = 0; - - /* Free external representation of parameters and set with those passed - * in. */ - if (p != NULL) { - wolfSSL_BN_free(dh->p); - dh->p = p; - } - if (q != NULL) { - wolfSSL_BN_free(dh->q); - dh->q = q; - } - if (g != NULL) { - wolfSSL_BN_free(dh->g); - dh->g = g; - } - /* External DH key parameters were set. */ - dh->exSet = 1; - - /* Set internal/wolfSSL DH key as well. */ - if (SetDhInternal(dh) != 1) { - WOLFSSL_ERROR_MSG("Unable to set internal DH key"); - /* Don't keep parameters on failure. */ - dh->p = NULL; - dh->q = NULL; - dh->g = NULL; - /* Internal and external DH key not set. */ - dh->inSet = 0; - dh->exSet = 0; - ret = 0; - } - } - - return ret; -} - -/* Set the length of the DH private key in bits. - * - * Length field is checked at generation. - * - * @param [in, out] dh DH key to set. - * @param [in] len Length of DH private key in bytes. - * @return 0 on failure. - * @return 1 on success. - */ -int wolfSSL_DH_set_length(WOLFSSL_DH *dh, long len) -{ - int ret = 1; - - WOLFSSL_ENTER("wolfSSL_DH_set_length"); - - /* Validate parameter. */ - if (dh == NULL) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = 0; - } - else { - /* Store length. */ - dh->length = (int)len; - } - - return ret; -} -#endif /* OPENSSL_ALL || (v1.1.0 or later) */ -#endif - -/* Get the public and private keys requested. - * - * @param [in] dh DH key to get keys from. - * @param [out] pub_key Pointer to return public key in. May be NULL. - * @param [out] priv_key Pointer to return private key in. May be NULL. - */ -void wolfSSL_DH_get0_key(const WOLFSSL_DH *dh, const WOLFSSL_BIGNUM **pub_key, - const WOLFSSL_BIGNUM **priv_key) -{ - WOLFSSL_ENTER("wolfSSL_DH_get0_key"); - - /* Get only when valid DH passed in. */ - if (dh != NULL) { - /* Return public key if required and available. */ - if ((pub_key != NULL) && (dh->pub_key != NULL)) { - *pub_key = dh->pub_key; - } - /* Return private key if required and available. */ - if ((priv_key != NULL) && (dh->priv_key != NULL)) { - *priv_key = dh->priv_key; - } - } -} - -/* Set the public and/or private key. - * - * @param [in, out] dh DH key to have keys set into. - * @param [in] pub_key Public key to set. May be NULL. - * @param [in] priv_key Private key to set. May be NULL. - * @return 0 on failure. - * @return 1 on success. - */ -int wolfSSL_DH_set0_key(WOLFSSL_DH *dh, WOLFSSL_BIGNUM *pub_key, - WOLFSSL_BIGNUM *priv_key) -{ - int ret = 1; -#ifdef WOLFSSL_DH_EXTRA - DhKey *key = NULL; -#endif - - WOLFSSL_ENTER("wolfSSL_DH_set0_key"); - - /* Validate parameters. */ - if (dh == NULL) { - ret = 0; - } -#ifdef WOLFSSL_DH_EXTRA - else { - key = (DhKey*)dh->internal; - } -#endif - - /* Replace public key when one passed in. */ - if ((ret == 1) && (pub_key != NULL)) { - wolfSSL_BN_free(dh->pub_key); - dh->pub_key = pub_key; - #ifdef WOLFSSL_DH_EXTRA - if (wolfssl_bn_get_value(dh->pub_key, &key->pub) != 1) { - ret = 0; - } - #endif - } - - /* Replace private key when one passed in. */ - if ((ret == 1) && (priv_key != NULL)) { - wolfSSL_BN_clear_free(dh->priv_key); - dh->priv_key = priv_key; - #ifdef WOLFSSL_DH_EXTRA - if (wolfssl_bn_get_value(dh->priv_key, &key->priv) != 1) { - ret = 0; - } - #endif - } - - return ret; -} - -#endif /* OPENSSL_EXTRA */ - -/* - * DH check APIs - */ - -#ifdef OPENSSL_EXTRA - -#ifndef NO_CERTS - -#ifdef OPENSSL_ALL -/* Check whether BN number is a prime. - * - * @param [in] n Number to check. - * @param [out] isPrime MP_YES when prime and MP_NO when not. - * @return 1 on success. - * @return 0 on error. - */ -static int wolfssl_dh_check_prime(WOLFSSL_BIGNUM* n, int* isPrime) -{ - int ret = 1; - WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); - WC_RNG* rng; - int localRng; - - /* Make an RNG with tmpRng or get global. */ - rng = wolfssl_make_rng(tmpRng, &localRng); - if (rng == NULL) { - ret = 0; - } - if (ret == 1) { - mp_int* prime = (mp_int*)n->internal; - - if (mp_prime_is_prime_ex(prime, 8, isPrime, rng) != 0) { - ret = 0; - } - /* Free local random number generator if created. */ - if (localRng) { - wc_FreeRng(rng); - WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_TMP_BUFFER); - } - } - - return ret; -} - -/* Checks the Diffie-Hellman parameters. - * - * Checks that the generator and prime are available. - * Checks that the prime is prime. - * OpenSSL expects codes to be non-NULL. - * - * @param [in] dh DH key to check. - * @param [out] codes Codes of checks that failed. - * @return 1 on success. - * @return 0 when DH is NULL, there were errors or failed to create a random - * number generator. - */ -int wolfSSL_DH_check(const WOLFSSL_DH *dh, int *codes) -{ - int ret = 1; - int errors = 0; - - WOLFSSL_ENTER("wolfSSL_DH_check"); - - /* Validate parameters. */ - if (dh == NULL) { - ret = 0; - } - - /* Check generator available. */ - if ((ret == 1) && ((dh->g == NULL) || (dh->g->internal == NULL))) { - errors |= DH_NOT_SUITABLE_GENERATOR; - } - - if (ret == 1) { - /* Check prime available. */ - if ((dh->p == NULL) || (dh->p->internal == NULL)) { - errors |= DH_CHECK_P_NOT_PRIME; - } - else { - /* Test if dh->p is prime. */ - int isPrime = MP_NO; - ret = wolfssl_dh_check_prime(dh->p, &isPrime); - /* Set error code if parameter p is not prime. */ - if ((ret == 1) && (isPrime != MP_YES)) { - errors |= DH_CHECK_P_NOT_PRIME; - } - } - } - - /* Return errors when user wants exact issues. */ - if (codes != NULL) { - *codes = errors; - } - else if (errors) { - ret = 0; - } - - return ret; -} - -#endif /* OPENSSL_ALL */ - -#endif /* !NO_CERTS */ - -#endif /* OPENSSL_EXTRA */ - -/* - * DH generate APIs - */ - -#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ - (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ - defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ - defined(WOLFSSL_OPENSSH) || defined(HAVE_SBLIM_SFCB))) - -#if defined(WOLFSSL_KEY_GEN) && !defined(HAVE_SELFTEST) -/* Generate DH parameters. - * - * @param [in] prime_len Length of prime in bits. - * @param [in] generator Generator value to use. - * @param [in] callback Called with progress information. Unused. - * @param [in] cb_arg User callback argument. Unused. - * @return NULL on failure. - * @return DH key on success. - */ -WOLFSSL_DH *wolfSSL_DH_generate_parameters(int prime_len, int generator, - void (*callback) (int, int, void *), void *cb_arg) -{ - WOLFSSL_DH* dh = NULL; - - WOLFSSL_ENTER("wolfSSL_DH_generate_parameters"); - /* Not supported by wolfSSl APIs. */ - (void)callback; - (void)cb_arg; - - /* Create an empty DH key. */ - if ((dh = wolfSSL_DH_new()) == NULL) { - WOLFSSL_ERROR_MSG("wolfSSL_DH_new error"); - } - /* Generate parameters into DH key. */ - else if (wolfSSL_DH_generate_parameters_ex(dh, prime_len, generator, NULL) - != 1) { - WOLFSSL_ERROR_MSG("wolfSSL_DH_generate_parameters_ex error"); - wolfSSL_DH_free(dh); - dh = NULL; - } - - return dh; -} - -/* Generate DH parameters. - * - * @param [in] dh DH key to generate parameters into. - * @param [in] prime_len Length of prime in bits. - * @param [in] generator Generator value to use. - * @param [in] callback Called with progress information. Unused. - * @param [in] cb_arg User callback argument. Unused. - * @return 0 on failure. - * @return 1 on success. - */ -int wolfSSL_DH_generate_parameters_ex(WOLFSSL_DH* dh, int prime_len, - int generator, void (*callback) (int, int, void *)) -{ - int ret = 1; - DhKey* key = NULL; - WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); - WC_RNG* rng = NULL; - int localRng = 0; - - WOLFSSL_ENTER("wolfSSL_DH_generate_parameters_ex"); - /* Not supported by wolfSSL APIs. */ - (void)callback; - (void)generator; - - /* Validate parameters. */ - if (dh == NULL) { - WOLFSSL_ERROR_MSG("Bad parameter"); - ret = 0; - } - - if (ret == 1) { - /* Make an RNG with tmpRng or get global. */ - rng = wolfssl_make_rng(tmpRng, &localRng); - if (rng == NULL) { - WOLFSSL_ERROR_MSG("No RNG to use"); - ret = 0; - } - } - - if (ret == 1) { - /* Get internal/wolfSSL DH key. */ - key = (DhKey*)dh->internal; - - /* Clear out data from internal DH key. */ - wc_FreeDhKey(key); - /* Re-initialize internal DH key. */ - if (wc_InitDhKey(key) != 0) { - ret = 0; - } - } - if (ret == 1) { - /* Generate parameters into internal DH key. */ - if (wc_DhGenerateParams(rng, prime_len, key) != 0) { - WOLFSSL_ERROR_MSG("wc_DhGenerateParams error"); - ret = 0; - } - } - - /* Free local random number generator if created. */ - if (localRng) { - wc_FreeRng(rng); - WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_TMP_BUFFER); - } - - if (ret == 1) { - /* Internal parameters set by generation. */ - dh->inSet = 1; - - WOLFSSL_MSG("wolfSSL does not support using a custom generator."); - - /* Synchronize the external to the internal parameters. */ - if (SetDhExternal(dh) != 1) { - WOLFSSL_ERROR_MSG("SetDhExternal error"); - ret = 0; - } - } - - return ret; -} -#endif /* WOLFSSL_KEY_GEN && !HAVE_SELFTEST */ - -#endif /* OPENSSL_ALL || (OPENSSL_EXTRA && (HAVE_STUNNEL || WOLFSSL_NGINX || - * HAVE_LIGHTY || WOLFSSL_HAPROXY || WOLFSSL_OPENSSH || - * HAVE_SBLIM_SFCB)) */ - -#ifdef OPENSSL_EXTRA - -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS) && !defined(WOLFSSL_DH_EXTRA)) \ - || (defined(HAVE_FIPS_VERSION) && FIPS_VERSION_GT(2,0)) -/* Generate a public/private key pair base on parameters. - * - * @param [in, out] dh DH key to generate keys into. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_DH_generate_key(WOLFSSL_DH* dh) -{ - int ret = 1; - word32 pubSz = 0; - word32 privSz = 0; - int localRng = 0; - WC_RNG* rng = NULL; - WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); - unsigned char* pub = NULL; - unsigned char* priv = NULL; - - WOLFSSL_ENTER("wolfSSL_DH_generate_key"); - - /* Validate parameters. */ - if ((dh == NULL) || (dh->p == NULL) || (dh->g == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = 0; - } - - /* Synchronize the external and internal parameters. */ - if ((ret == 1) && (dh->inSet == 0) && (SetDhInternal(dh) != 1)) { - WOLFSSL_ERROR_MSG("Bad DH set internal"); - ret = 0; - } - - if (ret == 1) { - /* Make a new RNG or use global. */ - rng = wolfssl_make_rng(tmpRng, &localRng); - /* Check we have a random number generator. */ - if (rng == NULL) { - ret = 0; - } - } - - if (ret == 1) { - /* Get the size of the prime in bytes. */ - pubSz = (word32)wolfSSL_BN_num_bytes(dh->p); - if (pubSz == 0) { - WOLFSSL_ERROR_MSG("Prime parameter invalid"); - ret = 0; - } - } - if (ret == 1) { - /* Private key size can be as much as the size of the prime. */ - if (dh->length) { - privSz = (word32)(dh->length / 8); /* to bytes */ - /* Special case where priv key is larger than dh->length / 8 - * See GeneratePrivateDh */ - if (dh->length == 128) - privSz = 21; - } - else { - privSz = pubSz; - } - /* Allocate public and private key arrays. */ - pub = (unsigned char*)XMALLOC(pubSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - priv = (unsigned char*)XMALLOC(privSz, NULL, DYNAMIC_TYPE_PRIVATE_KEY); - if (pub == NULL || priv == NULL) { - WOLFSSL_ERROR_MSG("Unable to malloc memory"); - ret = 0; - } - } - if (ret == 1) { - /* Dispose of old public and private keys. */ - wolfSSL_BN_free(dh->pub_key); - wolfSSL_BN_free(dh->priv_key); - - /* Allocate new public and private keys. */ - dh->pub_key = wolfSSL_BN_new(); - dh->priv_key = wolfSSL_BN_new(); - if (dh->pub_key == NULL) { - WOLFSSL_ERROR_MSG("Bad DH new pub"); - ret = 0; - } - if (dh->priv_key == NULL) { - WOLFSSL_ERROR_MSG("Bad DH new priv"); - ret = 0; - } - } - - PRIVATE_KEY_UNLOCK(); - /* Generate public and private keys into arrays. */ - if ((ret == 1) && (wc_DhGenerateKeyPair((DhKey*)dh->internal, rng, priv, - &privSz, pub, &pubSz) < 0)) { - WOLFSSL_ERROR_MSG("Bad wc_DhGenerateKeyPair"); - ret = 0; - } - /* Set public key from array. */ - if ((ret == 1) && (wolfSSL_BN_bin2bn(pub, (int)pubSz, dh->pub_key) == - NULL)) { - WOLFSSL_ERROR_MSG("Bad DH bn2bin error pub"); - ret = 0; - } - /* Set private key from array. */ - if ((ret == 1) && (wolfSSL_BN_bin2bn(priv, (int)privSz, dh->priv_key) == - NULL)) { - WOLFSSL_ERROR_MSG("Bad DH bn2bin error priv"); - ret = 0; - } - PRIVATE_KEY_LOCK(); - - if (localRng) { - /* Free an initialized local random number generator. */ - wc_FreeRng(rng); - WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG); - } - /* Dispose of allocated data. */ - XFREE(pub, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - XFREE(priv, NULL, DYNAMIC_TYPE_PRIVATE_KEY); - - return ret; -} - - -static int _DH_compute_key(unsigned char* key, const WOLFSSL_BIGNUM* otherPub, - WOLFSSL_DH* dh, int ct) -{ - int ret = 0; - word32 keySz = 0; - int pubSz = MAX_DHKEY_SZ; - int privSz = MAX_DHKEY_SZ; - int sz = 0; -#ifdef WOLFSSL_SMALL_STACK - unsigned char* pub = NULL; - unsigned char* priv = NULL; -#else - unsigned char pub [MAX_DHKEY_SZ]; - unsigned char priv[MAX_DHKEY_SZ]; -#endif - - WOLFSSL_ENTER("wolfSSL_DH_compute_key"); - - /* Validate parameters. */ - if ((dh == NULL) || (dh->priv_key == NULL) || (otherPub == NULL)) { - WOLFSSL_ERROR_MSG("Bad function arguments"); - ret = WOLFSSL_FATAL_ERROR; - } - /* Get the maximum size of computed DH key. */ - if ((ret == 0) && ((keySz = (word32)wolfSSL_DH_size(dh)) == 0)) { - WOLFSSL_ERROR_MSG("Bad DH_size"); - ret = WOLFSSL_FATAL_ERROR; - } - if (ret == 0) { - /* Validate the size of the private key. */ - sz = wolfSSL_BN_num_bytes(dh->priv_key); - if (sz > privSz) { - WOLFSSL_ERROR_MSG("Bad priv internal size"); - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 0) { - #ifdef WOLFSSL_SMALL_STACK - /* Keep real private key size to minimize amount allocated. */ - privSz = sz; - #endif - - /* Validate the size of the public key. */ - sz = wolfSSL_BN_num_bytes(otherPub); - if (sz > pubSz) { - WOLFSSL_ERROR_MSG("Bad otherPub size"); - ret = WOLFSSL_FATAL_ERROR; - } - } - - if (ret == 0) { - #ifdef WOLFSSL_SMALL_STACK - /* Allocate memory for the public key array. */ - pub = (unsigned char*)XMALLOC((size_t)sz, NULL, - DYNAMIC_TYPE_PUBLIC_KEY); - if (pub == NULL) - ret = WOLFSSL_FATAL_ERROR; - } - if (ret == 0) { - /* Allocate memory for the private key array. */ - priv = (unsigned char*)XMALLOC((size_t)privSz, NULL, - DYNAMIC_TYPE_PRIVATE_KEY); - if (priv == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 0) { - #endif - /* Get the private key into the array. */ - privSz = wolfSSL_BN_bn2bin(dh->priv_key, priv); - if (privSz <= 0) { - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 0) { - /* Get the public key into the array. */ - pubSz = wolfSSL_BN_bn2bin(otherPub, pub); - if (pubSz <= 0) { - ret = WOLFSSL_FATAL_ERROR; - } - } - /* Synchronize the external into the internal parameters. */ - if ((ret == 0) && ((dh->inSet == 0) && (SetDhInternal(dh) != 1))) { - WOLFSSL_ERROR_MSG("Bad DH set internal"); - ret = WOLFSSL_FATAL_ERROR; - } - - PRIVATE_KEY_UNLOCK(); - /* Calculate shared secret from private and public keys. */ - if (ret == 0) { - word32 padded_keySz = keySz; -#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && !defined(HAVE_SELFTEST) - if (ct) { - if (wc_DhAgree_ct((DhKey*)dh->internal, key, &keySz, priv, - (word32)privSz, pub, (word32)pubSz) < 0) { - WOLFSSL_ERROR_MSG("wc_DhAgree_ct failed"); - ret = WOLFSSL_FATAL_ERROR; - } - } - else -#endif /* (!HAVE_FIPS || FIPS_VERSION_GE(7,0)) && !HAVE_SELFTEST */ - { - if (wc_DhAgree((DhKey*)dh->internal, key, &keySz, priv, - (word32)privSz, pub, (word32)pubSz) < 0) { - WOLFSSL_ERROR_MSG("wc_DhAgree failed"); - ret = WOLFSSL_FATAL_ERROR; - } - } - - if ((ret == 0) && ct) { - /* Arrange for correct fixed-length, right-justified key, even if - * the crypto back end doesn't support it. With some crypto back - * ends this forgoes formal constant-timeness on the key agreement, - * but assured that wolfSSL_DH_compute_key_padded() functions - * correctly. - */ - if (keySz < padded_keySz) { - XMEMMOVE(key, key + (padded_keySz - keySz), - padded_keySz - keySz); - XMEMSET(key, 0, padded_keySz - keySz); - keySz = padded_keySz; - } - } - } - if (ret == 0) { - /* Return actual length. */ - ret = (int)keySz; - } - PRIVATE_KEY_LOCK(); - - if (privSz > 0) { -#ifdef WOLFSSL_SMALL_STACK - if (priv != NULL) -#endif - { - /* Zeroize sensitive data. */ - ForceZero(priv, (word32)privSz); - } - } - WC_FREE_VAR_EX(pub, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - WC_FREE_VAR_EX(priv, NULL, DYNAMIC_TYPE_PRIVATE_KEY); - - WOLFSSL_LEAVE("wolfSSL_DH_compute_key", ret); - - return ret; -} - -/* Compute the shared key from the private key and peer's public key. - * - * Return code compliant with OpenSSL. - * OpenSSL returns 0 when number of bits in p are smaller than minimum - * supported. - * - * @param [out] key Buffer to place shared key. - * @param [in] otherPub Peer's public key. - * @param [in] dh DH key containing private key. - * @return -1 on error. - * @return Size of shared secret in bytes on success. - */ -int wolfSSL_DH_compute_key(unsigned char* key, const WOLFSSL_BIGNUM* otherPub, - WOLFSSL_DH* dh) -{ - return _DH_compute_key(key, otherPub, dh, 0); -} - -/* Compute the shared key from the private key and peer's public key as in - * wolfSSL_DH_compute_key, but using constant time processing, with an output - * key length fixed at the nominal DH key size. Leading zeros are retained. - * - * Return code compliant with OpenSSL. - * OpenSSL returns 0 when number of bits in p are smaller than minimum - * supported. - * - * @param [out] key Buffer to place shared key. - * @param [in] otherPub Peer's public key. - * @param [in] dh DH key containing private key. - * @return -1 on error. - * @return Size of shared secret in bytes on success. - */ -int wolfSSL_DH_compute_key_padded(unsigned char* key, - const WOLFSSL_BIGNUM* otherPub, WOLFSSL_DH* dh) -{ - return _DH_compute_key(key, otherPub, dh, 1); -} - -#endif /* !HAVE_FIPS || (HAVE_FIPS && !WOLFSSL_DH_EXTRA) || - * HAVE_FIPS_VERSION > 2 */ - -#endif /* OPENSSL_EXTRA */ - -#endif /* NO_DH */ - -/******************************************************************************* - * END OF DH API - ******************************************************************************/ - - -/******************************************************************************* - * START OF EC API - ******************************************************************************/ - -#ifdef HAVE_ECC - -#if defined(OPENSSL_EXTRA) - -/* Start EC_curve */ - -/* Get the NIST name for the numeric ID. - * - * @param [in] nid Numeric ID of an EC curve. - * @return String representing NIST name of EC curve on success. - * @return NULL on error. - */ -const char* wolfSSL_EC_curve_nid2nist(int nid) -{ - const char* name = NULL; - const WOLF_EC_NIST_NAME* nist_name; - - /* Attempt to find the curve info matching the NID passed in. */ - for (nist_name = kNistCurves; nist_name->name != NULL; nist_name++) { - if (nist_name->nid == nid) { - /* NID found - return name. */ - name = nist_name->name; - break; - } - } - - return name; -} - -/* Get the numeric ID for the NIST name. - * - * @param [in] name NIST name of EC curve. - * @return NID matching NIST name on success. - * @return 0 on error. - */ -int wolfSSL_EC_curve_nist2nid(const char* name) -{ - int nid = 0; - const WOLF_EC_NIST_NAME* nist_name; - - /* Attempt to find the curve info matching the NIST name passed in. */ - for (nist_name = kNistCurves; nist_name->name != NULL; nist_name++) { - if (XSTRCMP(nist_name->name, name) == 0) { - /* Name found - return NID. */ - nid = nist_name->nid; - break; - } - } - - return nid; -} - -#endif /* OPENSSL_EXTRA */ - -/* End EC_curve */ - -/* Start EC_METHOD */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -/* Get the EC method of the EC group object. - * - * wolfSSL doesn't use method tables. Implementation used is dependent upon - * the NID. - * - * @param [in] group EC group object. - * @return EC method. - */ -const WOLFSSL_EC_METHOD* wolfSSL_EC_GROUP_method_of( - const WOLFSSL_EC_GROUP *group) -{ - /* No method table used so just return the same object. */ - return group; -} - -/* Get field type for method. - * - * Only prime fields are supported. - * - * @param [in] meth EC method. - * @return X9.63 prime field NID on success. - * @return 0 on error. - */ -int wolfSSL_EC_METHOD_get_field_type(const WOLFSSL_EC_METHOD *meth) -{ - int nid = 0; - - if (meth != NULL) { - /* Only field type supported by code base. */ - nid = WC_NID_X9_62_prime_field; - } - - return nid; -} -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - -/* End EC_METHOD */ - -/* Start EC_GROUP */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -/* Converts ECC curve enum values in ecc_curve_id to the associated OpenSSL NID - * value. - * - * @param [in] n ECC curve id. - * @return ECC curve NID (OpenSSL compatible value). - */ -int EccEnumToNID(int n) -{ - WOLFSSL_ENTER("EccEnumToNID"); - - switch(n) { - case ECC_SECP192R1: - return WC_NID_X9_62_prime192v1; - case ECC_PRIME192V2: - return WC_NID_X9_62_prime192v2; - case ECC_PRIME192V3: - return WC_NID_X9_62_prime192v3; - case ECC_PRIME239V1: - return WC_NID_X9_62_prime239v1; - case ECC_PRIME239V2: - return WC_NID_X9_62_prime239v2; - case ECC_PRIME239V3: - return WC_NID_X9_62_prime239v3; - case ECC_SECP256R1: - return WC_NID_X9_62_prime256v1; - case ECC_SECP112R1: - return WC_NID_secp112r1; - case ECC_SECP112R2: - return WC_NID_secp112r2; - case ECC_SECP128R1: - return WC_NID_secp128r1; - case ECC_SECP128R2: - return WC_NID_secp128r2; - case ECC_SECP160R1: - return WC_NID_secp160r1; - case ECC_SECP160R2: - return WC_NID_secp160r2; - case ECC_SECP224R1: - return WC_NID_secp224r1; - case ECC_SECP384R1: - return WC_NID_secp384r1; - case ECC_SECP521R1: - return WC_NID_secp521r1; - case ECC_SECP160K1: - return WC_NID_secp160k1; - case ECC_SECP192K1: - return WC_NID_secp192k1; - case ECC_SECP224K1: - return WC_NID_secp224k1; - case ECC_SECP256K1: - return WC_NID_secp256k1; - case ECC_BRAINPOOLP160R1: - return WC_NID_brainpoolP160r1; - case ECC_BRAINPOOLP192R1: - return WC_NID_brainpoolP192r1; - case ECC_BRAINPOOLP224R1: - return WC_NID_brainpoolP224r1; - case ECC_BRAINPOOLP256R1: - return WC_NID_brainpoolP256r1; - case ECC_BRAINPOOLP320R1: - return WC_NID_brainpoolP320r1; - case ECC_BRAINPOOLP384R1: - return WC_NID_brainpoolP384r1; - case ECC_BRAINPOOLP512R1: - return WC_NID_brainpoolP512r1; - #ifdef WOLFSSL_SM2 - case ECC_SM2P256V1: - return WC_NID_sm2; - #endif - default: - WOLFSSL_MSG("NID not found"); - return WOLFSSL_FATAL_ERROR; - } -} -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) -/* Converts OpenSSL NID of EC curve to the enum value in ecc_curve_id - * - * Used by ecc_sets[]. - * - * @param [in] n OpenSSL NID of EC curve. - * @return wolfCrypt EC curve id. - * @return -1 on error. - */ -int NIDToEccEnum(int nid) -{ - int id; - - WOLFSSL_ENTER("NIDToEccEnum"); - - switch (nid) { - case WC_NID_X9_62_prime192v1: - id = ECC_SECP192R1; - break; - case WC_NID_X9_62_prime192v2: - id = ECC_PRIME192V2; - break; - case WC_NID_X9_62_prime192v3: - id = ECC_PRIME192V3; - break; - case WC_NID_X9_62_prime239v1: - id = ECC_PRIME239V1; - break; - case WC_NID_X9_62_prime239v2: - id = ECC_PRIME239V2; - break; - case WC_NID_X9_62_prime239v3: - id = ECC_PRIME239V3; - break; - case WC_NID_X9_62_prime256v1: - id = ECC_SECP256R1; - break; - case WC_NID_secp112r1: - id = ECC_SECP112R1; - break; - case WC_NID_secp112r2: - id = ECC_SECP112R2; - break; - case WC_NID_secp128r1: - id = ECC_SECP128R1; - break; - case WC_NID_secp128r2: - id = ECC_SECP128R2; - break; - case WC_NID_secp160r1: - id = ECC_SECP160R1; - break; - case WC_NID_secp160r2: - id = ECC_SECP160R2; - break; - case WC_NID_secp224r1: - id = ECC_SECP224R1; - break; - case WC_NID_secp384r1: - id = ECC_SECP384R1; - break; - case WC_NID_secp521r1: - id = ECC_SECP521R1; - break; - case WC_NID_secp160k1: - id = ECC_SECP160K1; - break; - case WC_NID_secp192k1: - id = ECC_SECP192K1; - break; - case WC_NID_secp224k1: - id = ECC_SECP224K1; - break; - case WC_NID_secp256k1: - id = ECC_SECP256K1; - break; - case WC_NID_brainpoolP160r1: - id = ECC_BRAINPOOLP160R1; - break; - case WC_NID_brainpoolP192r1: - id = ECC_BRAINPOOLP192R1; - break; - case WC_NID_brainpoolP224r1: - id = ECC_BRAINPOOLP224R1; - break; - case WC_NID_brainpoolP256r1: - id = ECC_BRAINPOOLP256R1; - break; - case WC_NID_brainpoolP320r1: - id = ECC_BRAINPOOLP320R1; - break; - case WC_NID_brainpoolP384r1: - id = ECC_BRAINPOOLP384R1; - break; - case WC_NID_brainpoolP512r1: - id = ECC_BRAINPOOLP512R1; - break; - default: - WOLFSSL_MSG("NID not found"); - /* -1 on error. */ - id = WOLFSSL_FATAL_ERROR; - } - - return id; -} - -/* Set the fields of the EC group based on numeric ID. - * - * @param [in, out] group EC group. - * @param [in] nid Numeric ID of an EC curve. - */ -static void ec_group_set_nid(WOLFSSL_EC_GROUP* group, int nid) -{ - int eccEnum; - int realNid; - - /* Convert ecc_curve_id enum to NID. */ - if ((realNid = EccEnumToNID(nid)) != -1) { - /* ecc_curve_id enum passed in - have real NID value set. */ - eccEnum = nid; - } - else { - /* NID passed in is OpenSSL type. */ - realNid = nid; - /* Convert NID to ecc_curve_id enum. */ - eccEnum = NIDToEccEnum(nid); - } - - /* Set the numeric ID of the curve */ - group->curve_nid = realNid; - /* Initialize index to -1 (i.e. wolfCrypt doesn't support curve). */ - group->curve_idx = -1; - - /* Find index and OID sum for curve if wolfCrypt supports it. */ - if (eccEnum != -1) { - int i; - - /* Find id and set the internal curve idx and OID sum. */ - for (i = 0; ecc_sets[i].size != 0; i++) { - if (ecc_sets[i].id == eccEnum) { - /* Found id in wolfCrypt supported EC curves. */ - group->curve_idx = i; - group->curve_oid = (int)ecc_sets[i].oidSum; - break; - } - } - } -} - -/* Create a new EC group with the numeric ID for an EC curve. - * - * @param [in] nid Numeric ID of an EC curve. - * @return New, allocated EC group on success. - * @return NULL on error. - */ -WOLFSSL_EC_GROUP* wolfSSL_EC_GROUP_new_by_curve_name(int nid) -{ - int err = 0; - WOLFSSL_EC_GROUP* group; - - WOLFSSL_ENTER("wolfSSL_EC_GROUP_new_by_curve_name"); - - /* Allocate EC group. */ - group = (WOLFSSL_EC_GROUP*)XMALLOC(sizeof(WOLFSSL_EC_GROUP), NULL, - DYNAMIC_TYPE_ECC); - if (group == NULL) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_new_by_curve_name malloc failure"); - err = 1; - } - - if (!err) { - /* Reset all fields. */ - XMEMSET(group, 0, sizeof(WOLFSSL_EC_GROUP)); - - /* Set the fields of group based on the numeric ID. */ - ec_group_set_nid(group, nid); - } - - return group; -} -#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -/* Dispose of the EC group. - * - * Cannot use group after this call. - * - * @param [in] group EC group to free. - */ -void wolfSSL_EC_GROUP_free(WOLFSSL_EC_GROUP *group) -{ - WOLFSSL_ENTER("wolfSSL_EC_GROUP_free"); - - /* Dispose of EC group. */ - XFREE(group, NULL, DYNAMIC_TYPE_ECC); -} -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - -#ifdef OPENSSL_EXTRA -#ifndef NO_BIO - -/* Creates an EC group from the DER encoding. - * - * Only named curves supported. - * - * @param [out] group Reference to EC group object. - * @param [in] in Buffer holding DER encoding of curve. - * @param [in] inSz Length of data in buffer. - * @return EC group on success. - * @return NULL on error. - */ -static WOLFSSL_EC_GROUP* wolfssl_ec_group_d2i(WOLFSSL_EC_GROUP** group, - const unsigned char** in_pp, long inSz) -{ - int err = 0; - WOLFSSL_EC_GROUP* ret = NULL; - word32 idx = 0; - word32 oid = 0; - int id = 0; - const unsigned char* in; - - if (in_pp == NULL || *in_pp == NULL) - return NULL; - - in = *in_pp; - - /* Use the group passed in. */ - if ((group != NULL) && (*group != NULL)) { - ret = *group; - } - - /* Only support named curves. */ - if (in[0] != ASN_OBJECT_ID) { - WOLFSSL_ERROR_MSG("Invalid or unsupported encoding"); - err = 1; - } - /* Decode the OBJECT ID - expecting an EC curve OID. */ - if ((!err) && (GetObjectId(in, &idx, &oid, oidCurveType, (word32)inSz) != - 0)) { - err = 1; - } - if (!err) { - /* Get the internal ID for OID. */ - id = wc_ecc_get_oid(oid, NULL, NULL); - if (id < 0) { - err = 1; - } - } - if (!err) { - /* Get the NID for the internal ID. */ - int nid = EccEnumToNID(id); - if (ret == NULL) { - /* Create a new EC group with the numeric ID. */ - ret = wolfSSL_EC_GROUP_new_by_curve_name(nid); - if (ret == NULL) { - err = 1; - } - } - else { - ec_group_set_nid(ret, nid); - } - } - if ((!err) && (group != NULL)) { - /* Return the EC group through reference. */ - *group = ret; - } - - if (err) { - if ((ret != NULL) && (ret != *group)) { - wolfSSL_EC_GROUP_free(ret); - } - ret = NULL; - } - else { - *in_pp += idx; - } - return ret; -} - -/* Creates a new EC group from the PEM encoding in the BIO. - * - * @param [in] bio BIO to read PEM encoding from. - * @param [out] group Reference to EC group object. - * @param [in] cb Password callback when PEM encrypted. - * @param [in] pass NUL terminated string for passphrase when PEM encrypted. - * @return EC group on success. - * @return NULL on error. - */ -WOLFSSL_EC_GROUP* wolfSSL_PEM_read_bio_ECPKParameters(WOLFSSL_BIO* bio, - WOLFSSL_EC_GROUP** group, wc_pem_password_cb* cb, void* pass) -{ - int err = 0; - WOLFSSL_EC_GROUP* ret = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; - - if (bio == NULL) { - err = 1; - } - - /* Read parameters from BIO and convert PEM to DER. */ - if ((!err) && (pem_read_bio_key(bio, cb, pass, ECC_PARAM_TYPE, - &keyFormat, &der) < 0)) { - err = 1; - } - if (!err) { - /* Create EC group from DER encoding. */ - const byte** p = (const byte**)&der->buffer; - ret = wolfssl_ec_group_d2i(group, p, der->length); - if (ret == NULL) { - WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_EC_GROUP"); - } - } - - /* Dispose of any allocated data. */ - FreeDer(&der); - return ret; -} - -WOLFSSL_EC_GROUP *wolfSSL_d2i_ECPKParameters(WOLFSSL_EC_GROUP **out, - const unsigned char **in, long len) -{ - return wolfssl_ec_group_d2i(out, in, len); -} - -int wolfSSL_i2d_ECPKParameters(const WOLFSSL_EC_GROUP* grp, unsigned char** pp) -{ - unsigned char* out = NULL; - int len = 0; - int idx; - const byte* oid = NULL; - word32 oidSz = 0; - - if (grp == NULL || !wc_ecc_is_valid_idx(grp->curve_idx) || - grp->curve_idx < 0) - return WOLFSSL_FATAL_ERROR; - - /* Get the actual DER encoding of the OID. ecc_sets[grp->curve_idx].oid - * is just the numerical representation. */ - if (wc_ecc_get_oid((word32)grp->curve_oid, &oid, &oidSz) < 0) - return WOLFSSL_FATAL_ERROR; - - len = SetObjectId((int)oidSz, NULL) + (int)oidSz; - - if (pp == NULL) - return len; - - if (*pp == NULL) { - out = (unsigned char*)XMALLOC((size_t)len, NULL, DYNAMIC_TYPE_ASN1); - if (out == NULL) - return WOLFSSL_FATAL_ERROR; - } - else { - out = *pp; - } - - idx = SetObjectId((int)oidSz, out); - XMEMCPY(out + idx, oid, oidSz); - if (*pp == NULL) - *pp = out; - else - *pp += len; - - return len; -} -#endif /* !NO_BIO */ - -#if defined(OPENSSL_ALL) && !defined(NO_CERTS) -/* Copy an EC group. - * - * Only used by wolfSSL_EC_KEY_dup at this time. - * - * @param [in, out] dst Destination EC group. - * @param [in] src Source EC group. - * @return 0 on success. - */ -static int wolfssl_ec_group_copy(WOLFSSL_EC_GROUP* dst, - const WOLFSSL_EC_GROUP* src) -{ - /* Copy the fields. */ - dst->curve_idx = src->curve_idx; - dst->curve_nid = src->curve_nid; - dst->curve_oid = src->curve_oid; - - return 0; -} -#endif /* OPENSSL_ALL && !NO_CERTS */ - -/* Copies ecc_key into new WOLFSSL_EC_GROUP object - * - * @param [in] src EC group to duplicate. - * - * @return EC group on success. - * @return NULL on error. - */ -WOLFSSL_EC_GROUP* wolfSSL_EC_GROUP_dup(const WOLFSSL_EC_GROUP *src) -{ - WOLFSSL_EC_GROUP* newGroup = NULL; - - if (src != NULL) { - /* Create new group base on NID in original EC group. */ - newGroup = wolfSSL_EC_GROUP_new_by_curve_name(src->curve_nid); - } - - return newGroup; -} - -/* Compare two EC groups. - * - * Return code compliant with OpenSSL. - * - * @param [in] a First EC group. - * @param [in] b Second EC group. - * @param [in] ctx Big number context to use when comparing fields. Unused. - * - * @return 0 if equal. - * @return 1 if not equal. - * @return -1 on error. - */ -int wolfSSL_EC_GROUP_cmp(const WOLFSSL_EC_GROUP *a, const WOLFSSL_EC_GROUP *b, - WOLFSSL_BN_CTX *ctx) -{ - int ret; - - /* No BN operations performed. */ - (void)ctx; - - WOLFSSL_ENTER("wolfSSL_EC_GROUP_cmp"); - - /* Validate parameters. */ - if ((a == NULL) || (b == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_cmp Bad arguments"); - /* Return error value. */ - ret = WOLFSSL_FATAL_ERROR; - } - /* Compare NID and wolfSSL curve index. */ - else { - /* 0 when same, 1 when not. */ - ret = ((a->curve_nid == b->curve_nid) && - (a->curve_idx == b->curve_idx)) ? 0 : 1; - } - - return ret; -} - -#ifndef NO_WOLFSSL_STUB -/* Set the ASN.1 flag that indicate encoding of curve. - * - * Stub function - flag not used elsewhere. - * Always encoded as named curve. - * - * @param [in] group EC group to modify. - * @param [in] flag ASN.1 flag to set. Valid values: - * OPENSSL_EC_EXPLICIT_CURVE, OPENSSL_EC_NAMED_CURVE - */ -void wolfSSL_EC_GROUP_set_asn1_flag(WOLFSSL_EC_GROUP *group, int flag) -{ - (void)group; - (void)flag; - - WOLFSSL_ENTER("wolfSSL_EC_GROUP_set_asn1_flag"); - WOLFSSL_STUB("EC_GROUP_set_asn1_flag"); -} -#endif - -/* Get the curve NID of the group. - * - * Return code compliant with OpenSSL. - * - * @param [in] group EC group. - * @return Curve NID on success. - * @return 0 on error. - */ -int wolfSSL_EC_GROUP_get_curve_name(const WOLFSSL_EC_GROUP *group) -{ - int nid = 0; - WOLFSSL_ENTER("wolfSSL_EC_GROUP_get_curve_name"); - - if (group == NULL) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_get_curve_name Bad arguments"); - } - else { - nid = group->curve_nid; - } - - return nid; -} - -/* Get the degree (curve size in bits) of the EC group. - * - * Return code compliant with OpenSSL. - * - * @return Degree of the curve on success. - * @return 0 on error. - */ -int wolfSSL_EC_GROUP_get_degree(const WOLFSSL_EC_GROUP *group) -{ - int degree = 0; - - WOLFSSL_ENTER("wolfSSL_EC_GROUP_get_degree"); - - if (group == NULL) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_get_degree Bad arguments"); - } - else { - switch (group->curve_nid) { - case WC_NID_secp112r1: - case WC_NID_secp112r2: - degree = 112; - break; - case WC_NID_secp128r1: - case WC_NID_secp128r2: - degree = 128; - break; - case WC_NID_secp160k1: - case WC_NID_secp160r1: - case WC_NID_secp160r2: - case WC_NID_brainpoolP160r1: - degree = 160; - break; - case WC_NID_secp192k1: - case WC_NID_brainpoolP192r1: - case WC_NID_X9_62_prime192v1: - case WC_NID_X9_62_prime192v2: - case WC_NID_X9_62_prime192v3: - degree = 192; - break; - case WC_NID_secp224k1: - case WC_NID_secp224r1: - case WC_NID_brainpoolP224r1: - degree = 224; - break; - case WC_NID_X9_62_prime239v1: - case WC_NID_X9_62_prime239v2: - case WC_NID_X9_62_prime239v3: - degree = 239; - break; - case WC_NID_secp256k1: - case WC_NID_brainpoolP256r1: - case WC_NID_X9_62_prime256v1: - degree = 256; - break; - case WC_NID_brainpoolP320r1: - degree = 320; - break; - case WC_NID_secp384r1: - case WC_NID_brainpoolP384r1: - degree = 384; - break; - case WC_NID_brainpoolP512r1: - degree = 512; - break; - case WC_NID_secp521r1: - degree = 521; - break; - } - } - - return degree; -} -#endif /* OPENSSL_EXTRA */ - -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) -/* Get the length of the order in bits of the EC group. - * - * TODO: consider switch statement or calculating directly from hex string - * array instead of using mp_int. - * - * @param [in] group EC group. - * @return Length of order in bits on success. - * @return 0 on error. - */ -int wolfSSL_EC_GROUP_order_bits(const WOLFSSL_EC_GROUP *group) -{ - int ret = 0; - WC_DECLARE_VAR(order, mp_int, 1, 0); - - /* Validate parameter. */ - if ((group == NULL) || (group->curve_idx < 0)) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_order_bits NULL error"); - ret = WOLFSSL_FATAL_ERROR; - } - -#ifdef WOLFSSL_SMALL_STACK - if (ret == 0) { - /* Allocate memory for mp_int that will hold order value. */ - order = (mp_int *)XMALLOC(sizeof(*order), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (order == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - } -#endif - - if (ret == 0) { - /* Initialize mp_int. */ - ret = mp_init(order); - } - - if (ret == 0) { - /* Read hex string of order from wolfCrypt array of curves. */ - ret = mp_read_radix(order, ecc_sets[group->curve_idx].order, - MP_RADIX_HEX); - if (ret == 0) { - /* Get bits of order. */ - ret = mp_count_bits(order); - } - /* Clear and free mp_int. */ - mp_clear(order); - } - - WC_FREE_VAR_EX(order, NULL, DYNAMIC_TYPE_TMP_BUFFER); - - /* Convert error code to length of 0. */ - if (ret < 0) { - ret = 0; - } - - return ret; -} -#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ - -#if defined(OPENSSL_EXTRA) -/* Get the order of the group as a BN. - * - * Return code compliant with OpenSSL. - * - * @param [in] group EC group. - * @param [in, out] order BN to hold order value. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_EC_GROUP_get_order(const WOLFSSL_EC_GROUP *group, - WOLFSSL_BIGNUM *order, WOLFSSL_BN_CTX *ctx) -{ - int ret = 1; - mp_int* mp = NULL; - - /* No BN operations performed - done with mp_int in BN. */ - (void)ctx; - - /* Validate parameters. */ - if ((group == NULL) || (order == NULL) || (order->internal == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order NULL error"); - ret = 0; - } - - if (ret == 1 && - (group->curve_idx < 0 || !wc_ecc_is_valid_idx(group->curve_idx))) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order Bad group idx"); - ret = 0; - } - - if (ret == 1) { - mp = (mp_int*)order->internal; - } - /* Initialize */ - if ((ret == 1) && (mp_init(mp) != MP_OKAY)) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order mp_init failure"); - ret = 0; - } - /* Read hex string of order from wolfCrypt array of curves. */ - if ((ret == 1) && (mp_read_radix(mp, ecc_sets[group->curve_idx].order, - MP_RADIX_HEX) != MP_OKAY)) { - WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order mp_read order failure"); - /* Zero out any partial value but don't free. */ - mp_zero(mp); - ret = 0; - } - - return ret; -} - -#endif /* OPENSSL_EXTRA */ - -/* End EC_GROUP */ - -/* Start EC_POINT */ - -#if defined(OPENSSL_EXTRA) - -/* Set data of EC point into internal, wolfCrypt EC point object. - * - * EC_POINT Openssl -> WolfSSL - * - * @param [in, out] p EC point to update. - * @return 1 on success. - * @return -1 on failure. - */ -static int ec_point_internal_set(WOLFSSL_EC_POINT *p) -{ - int ret = 1; - - WOLFSSL_ENTER("ec_point_internal_set"); - - /* Validate parameter. */ - if ((p == NULL) || (p->internal == NULL)) { - WOLFSSL_MSG("ECPoint NULL error"); - ret = WOLFSSL_FATAL_ERROR; - } - else { - /* Get internal point as a wolfCrypt EC point. */ - ecc_point* point = (ecc_point*)p->internal; - - /* Set X ordinate if available. */ - if ((p->X != NULL) && (wolfssl_bn_get_value(p->X, point->x) != 1)) { - WOLFSSL_MSG("ecc point X error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* Set Y ordinate if available. */ - if ((ret == 1) && (p->Y != NULL) && (wolfssl_bn_get_value(p->Y, - point->y) != 1)) { - WOLFSSL_MSG("ecc point Y error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* Set Z ordinate if available. */ - if ((ret == 1) && (p->Z != NULL) && (wolfssl_bn_get_value(p->Z, - point->z) != 1)) { - WOLFSSL_MSG("ecc point Z error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* Internal values set when operations succeeded. */ - p->inSet = (ret == 1); - } - - return ret; -} - -/* Set data of internal, wolfCrypt EC point object into EC point. - * - * EC_POINT WolfSSL -> OpenSSL - * - * @param [in, out] p EC point to update. - * @return 1 on success. - * @return -1 on failure. - */ -static int ec_point_external_set(WOLFSSL_EC_POINT *p) -{ - int ret = 1; - - WOLFSSL_ENTER("ec_point_external_set"); - - /* Validate parameter. */ - if ((p == NULL) || (p->internal == NULL)) { - WOLFSSL_MSG("ECPoint NULL error"); - ret = WOLFSSL_FATAL_ERROR; - } - else { - /* Get internal point as a wolfCrypt EC point. */ - ecc_point* point = (ecc_point*)p->internal; - - /* Set X ordinate. */ - if (wolfssl_bn_set_value(&p->X, point->x) != 1) { - WOLFSSL_MSG("ecc point X error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* Set Y ordinate. */ - if ((ret == 1) && (wolfssl_bn_set_value(&p->Y, point->y) != 1)) { - WOLFSSL_MSG("ecc point Y error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* Set Z ordinate. */ - if ((ret == 1) && (wolfssl_bn_set_value(&p->Z, point->z) != 1)) { - WOLFSSL_MSG("ecc point Z error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* External values set when operations succeeded. */ - p->exSet = (ret == 1); - } - - return ret; -} - -/* Setup internals of EC point. - * - * Assumes point is not NULL. - * - * @param [in, out] point EC point to update. - * @return 1 on success. - * @return 0 on failure. - */ -static int ec_point_setup(const WOLFSSL_EC_POINT *point) { - int ret = 1; - - /* Check if internal values need setting. */ - if (!point->inSet) { - WOLFSSL_MSG("No ECPoint internal set, do it"); - - /* Forcing to non-constant type to update internals. */ - if (ec_point_internal_set((WOLFSSL_EC_POINT *)point) != 1) { - WOLFSSL_MSG("ec_point_internal_set failed"); - ret = 0; - } - } - - return ret; -} - -/* Create a new EC point from the group. - * - * @param [in] group EC group. - * @return EC point on success. - * @return NULL on error. - */ -WOLFSSL_EC_POINT* wolfSSL_EC_POINT_new(const WOLFSSL_EC_GROUP* group) -{ - int err = 0; - WOLFSSL_EC_POINT* point = NULL; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_new"); - - /* Validate parameter. */ - if (group == NULL) { - WOLFSSL_MSG("wolfSSL_EC_POINT_new NULL error"); - err = 1; - } - - if (!err) { - /* Allocate memory for new EC point. */ - point = (WOLFSSL_EC_POINT*)XMALLOC(sizeof(WOLFSSL_EC_POINT), NULL, - DYNAMIC_TYPE_ECC); - if (point == NULL) { - WOLFSSL_MSG("wolfSSL_EC_POINT_new malloc ecc point failure"); - err = 1; - } - } - if (!err) { - /* Clear fields of EC point. */ - XMEMSET(point, 0, sizeof(WOLFSSL_EC_POINT)); - - /* Allocate internal EC point. */ - point->internal = wc_ecc_new_point(); - if (point->internal == NULL) { - WOLFSSL_MSG("ecc_new_point failure"); - err = 1; - } - } - - if (err) { - XFREE(point, NULL, DYNAMIC_TYPE_ECC); - point = NULL; - } - return point; -} - -#endif /* OPENSSL_EXTRA */ - -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) -/* Dispose of the EC point. - * - * Cannot use point after this call. - * - * @param [in, out] point EC point to free. - */ -void wolfSSL_EC_POINT_free(WOLFSSL_EC_POINT *point) -{ - WOLFSSL_ENTER("wolfSSL_EC_POINT_free"); - - if (point != NULL) { - if (point->internal != NULL) { - wc_ecc_del_point((ecc_point*)point->internal); - point->internal = NULL; - } - - /* Free ordinates. */ - wolfSSL_BN_free(point->X); - wolfSSL_BN_free(point->Y); - wolfSSL_BN_free(point->Z); - /* Clear fields. */ - point->X = NULL; - point->Y = NULL; - point->Z = NULL; - point->inSet = 0; - point->exSet = 0; - - /* Dispose of EC point. */ - XFREE(point, NULL, DYNAMIC_TYPE_ECC); - } -} -#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ - -#ifdef OPENSSL_EXTRA - -/* Clear and dispose of the EC point. - * - * Cannot use point after this call. - * - * @param [in, out] point EC point to free. - */ -void wolfSSL_EC_POINT_clear_free(WOLFSSL_EC_POINT *point) -{ - WOLFSSL_ENTER("wolfSSL_EC_POINT_clear_free"); - - if (point != NULL) { - if (point->internal != NULL) { - /* Force internal point to be zeros. */ - #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - wc_ecc_forcezero_point((ecc_point*)point->internal); - #else - ecc_point* p = (ecc_point*)point->internal; - mp_forcezero(p->x); - mp_forcezero(p->y); - mp_forcezero(p->z); - #endif - wc_ecc_del_point((ecc_point*)point->internal); - point->internal = NULL; - } - - /* Clear the ordinates before freeing. */ - wolfSSL_BN_clear_free(point->X); - wolfSSL_BN_clear_free(point->Y); - wolfSSL_BN_clear_free(point->Z); - /* Clear fields. */ - point->X = NULL; - point->Y = NULL; - point->Z = NULL; - point->inSet = 0; - point->exSet = 0; - - /* Dispose of EC point. */ - XFREE(point, NULL, DYNAMIC_TYPE_ECC); - } -} - -/* Print out the internals of EC point in debug and when logging callback set. - * - * Not an OpenSSL API. - * - * TODO: Use WOLFSSL_MSG_EX()? - * - * @param [in] msg Message to prepend. - * @param [in] point EC point to print. - */ -void wolfSSL_EC_POINT_dump(const char *msg, const WOLFSSL_EC_POINT *point) -{ -#if defined(DEBUG_WOLFSSL) - char *num; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_dump"); - - /* Only print when debugging on. */ - if (WOLFSSL_IS_DEBUG_ON()) { - if (point == NULL) { - /* No point passed in so just put out "NULL". */ - WOLFSSL_MSG_EX("%s = NULL\n", msg); - } - else { - /* Put out message and status of internal/external data set. */ - WOLFSSL_MSG_EX("%s:\n\tinSet=%d, exSet=%d\n", msg, point->inSet, - point->exSet); - /* Get x-ordinate as a hex string and print. */ - num = wolfSSL_BN_bn2hex(point->X); - WOLFSSL_MSG_EX("\tX = %s\n", num); - XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); - /* Get x-ordinate as a hex string and print. */ - num = wolfSSL_BN_bn2hex(point->Y); - WOLFSSL_MSG_EX("\tY = %s\n", num); - XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); - /* Get z-ordinate as a hex string and print. */ - num = wolfSSL_BN_bn2hex(point->Z); - WOLFSSL_MSG_EX("\tZ = %s\n", num); - XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); - } - } -#else - (void)msg; - (void)point; -#endif -} - -/* Convert EC point to hex string that as either uncompressed or compressed. - * - * ECC point compression types were not included in selftest ecc.h - * - * @param [in] group EC group for point. - * @param [in] point EC point to encode. - * @param [in] form Format of encoding. Valid values: - * POINT_CONVERSION_UNCOMPRESSED, POINT_CONVERSION_COMPRESSED - * @param [in] ctx Context to use for BN operations. Unused. - * @return Allocated hex string on success. - * @return NULL on error. - */ -char* wolfSSL_EC_POINT_point2hex(const WOLFSSL_EC_GROUP* group, - const WOLFSSL_EC_POINT* point, int form, WOLFSSL_BN_CTX* ctx) -{ - static const char* hexDigit = "0123456789ABCDEF"; - char* hex = NULL; - int i; - int sz = 0; - int len = 0; - int err = 0; - - /* No BN operations performed. */ - (void)ctx; - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL)) { - err = 1; - } - /* Get curve id expects a positive index. */ - if ((!err) && (group->curve_idx < 0)) { - err = 1; - } - - if (!err) { - /* Get curve id to look up ordinate size. */ - int id = wc_ecc_get_curve_id(group->curve_idx); - /* Get size of ordinate. */ - if ((sz = wc_ecc_get_curve_size_from_id(id)) < 0) { - err = 1; - } - } - if (!err) { - /* [] */ - len = sz + 1; - if (form == WC_POINT_CONVERSION_UNCOMPRESSED) { - /* Include y ordinate when uncompressed. */ - len += sz; - } - - /* Hex string: allocate 2 bytes to represent each byte plus 1 for '\0'. - */ - hex = (char*)XMALLOC((size_t)(2 * len + 1), NULL, DYNAMIC_TYPE_ECC); - if (hex == NULL) { - err = 1; - } - } - if (!err) { - /* Make bytes all zeros to allow for ordinate values less than max size. - */ - XMEMSET(hex, 0, (size_t)(2 * len + 1)); - - /* Calculate offset as leading zeros not encoded. */ - i = sz - mp_unsigned_bin_size((mp_int*)point->X->internal) + 1; - /* Put in x-ordinate after format byte. */ - if (mp_to_unsigned_bin((mp_int*)point->X->internal, (byte*)(hex + i)) < - 0) { - err = 1; - } - } - if (!err) { - if (form == WC_POINT_CONVERSION_COMPRESSED) { - /* Compressed format byte value dependent on whether y-ordinate is - * odd. - */ - hex[0] = mp_isodd((mp_int*)point->Y->internal) ? - ECC_POINT_COMP_ODD : ECC_POINT_COMP_EVEN; - /* No y-ordinate. */ - } - else { - /* Put in uncompressed format byte. */ - hex[0] = ECC_POINT_UNCOMP; - /* Calculate offset as leading zeros not encoded. */ - i = 1 + 2 * sz - mp_unsigned_bin_size((mp_int*)point->Y->internal); - /* Put in y-ordinate after x-ordinate. */ - if (mp_to_unsigned_bin((mp_int*)point->Y->internal, - (byte*)(hex + i)) < 0) { - err = 1; - } - } - } - if (!err) { - /* Convert binary encoding to hex string. */ - /* Start at end so as not to overwrite. */ - for (i = len-1; i >= 0; i--) { - /* Get byte value and store has hex string. */ - byte b = (byte)hex[i]; - hex[i * 2 + 1] = hexDigit[b & 0xf]; - hex[i * 2 ] = hexDigit[b >> 4]; - } - /* Memset put trailing zero or '\0' on end of string. */ - } - - if (err && (hex != NULL)) { - /* Dispose of allocated data not being returned. */ - XFREE(hex, NULL, DYNAMIC_TYPE_ECC); - hex = NULL; - } - /* Return hex string encoding. */ - return hex; -} - -static size_t hex_to_bytes(const char *hex, unsigned char *output, size_t sz) -{ - word32 i; - for (i = 0; i < sz; i++) { - signed char ch1, ch2; - ch1 = HexCharToByte(hex[i * 2]); - ch2 = HexCharToByte(hex[i * 2 + 1]); - if ((ch1 < 0) || (ch2 < 0)) { - WOLFSSL_MSG("hex_to_bytes: syntax error"); - return 0; - } - output[i] = (unsigned char)((ch1 << 4) + ch2); - } - return sz; -} - -WOLFSSL_EC_POINT* wolfSSL_EC_POINT_hex2point(const WOLFSSL_EC_GROUP *group, - const char *hex, WOLFSSL_EC_POINT*p, WOLFSSL_BN_CTX *ctx) -{ - /* for uncompressed mode */ - size_t str_sz; - WOLFSSL_BIGNUM *Gx = NULL; - WOLFSSL_BIGNUM *Gy = NULL; - char strGx[MAX_ECC_BYTES * 2 + 1]; - - /* for compressed mode */ - int key_sz; - byte *octGx = (byte *)strGx; /* octGx[MAX_ECC_BYTES] */ - - int p_alloc = 0; - int ret; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_hex2point"); - - if (group == NULL || hex == NULL || ctx == NULL) - return NULL; - - if (p == NULL) { - if ((p = wolfSSL_EC_POINT_new(group)) == NULL) { - WOLFSSL_MSG("wolfSSL_EC_POINT_new"); - goto err; - } - p_alloc = 1; - } - - key_sz = (wolfSSL_EC_GROUP_get_degree(group) + 7) / 8; - if (hex[0] == '0' && hex[1] == '4') { /* uncompressed mode */ - str_sz = (size_t)key_sz * 2; - - XMEMSET(strGx, 0x0, str_sz + 1); - XMEMCPY(strGx, hex + 2, str_sz); - - if (wolfSSL_BN_hex2bn(&Gx, strGx) == 0) - goto err; - - if (wolfSSL_BN_hex2bn(&Gy, hex + 2 + str_sz) == 0) - goto err; - - ret = wolfSSL_EC_POINT_set_affine_coordinates_GFp - (group, p, Gx, Gy, ctx); - - if (ret != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp"); - goto err; - } - } - else if (hex[0] == '0' && (hex[1] == '2' || hex[1] == '3')) { - size_t sz = XSTRLEN(hex + 2) / 2; - /* compressed mode */ - octGx[0] = ECC_POINT_COMP_ODD; - if (hex_to_bytes(hex + 2, octGx + 1, sz) != sz) { - goto err; - } - if (wolfSSL_ECPoint_d2i(octGx, (word32)key_sz + 1, group, p) - != WOLFSSL_SUCCESS) { - goto err; - } - } - else - goto err; - - wolfSSL_BN_free(Gx); - wolfSSL_BN_free(Gy); - return p; - -err: - wolfSSL_BN_free(Gx); - wolfSSL_BN_free(Gy); - if (p_alloc) { - wolfSSL_EC_POINT_free(p); - } - return NULL; - -} - -/* Encode the EC point as an uncompressed point in DER. - * - * Return code compliant with OpenSSL. - * Not OpenSSL API. - * - * @param [in] group EC group point belongs to. - * @param [in] point EC point to encode. - * @param [out] out Buffer to encode into. May be NULL. - * @param [in, out] len On in, length of buffer in bytes. - * On out, length of encoding in bytes. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_ECPoint_i2d(const WOLFSSL_EC_GROUP *group, - const WOLFSSL_EC_POINT *point, unsigned char *out, unsigned int *len) -{ - int res = 1; - - WOLFSSL_ENTER("wolfSSL_ECPoint_i2d"); - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL) || (len == NULL)) { - WOLFSSL_MSG("wolfSSL_ECPoint_i2d NULL error"); - res = 0; - } - - /* Ensure points internals are set up. */ - if ((res == 1) && (ec_point_setup(point) != 1)) { - res = 0; - } - - /* Dump the point if encoding. */ - if ((res == 1) && (out != NULL)) { - wolfSSL_EC_POINT_dump("i2d p", point); - } - - if (res == 1) { - /* DER encode point in uncompressed format. */ - int ret = wc_ecc_export_point_der(group->curve_idx, - (ecc_point*)point->internal, out, len); - /* Check return. When out is NULL, return will be length only error. */ - if ((ret != MP_OKAY) && ((out != NULL) || - (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E)))) { - WOLFSSL_MSG("wolfSSL_ECPoint_i2d wc_ecc_export_point_der failed"); - res = 0; - } - } - - return res; -} - -/* Decode the uncompressed point in DER into EC point. - * - * Return code compliant with OpenSSL. - * Not OpenSSL API. - * - * @param [in] in Buffer containing DER encoded point. - * @param [in] len Length of data in bytes. - * @param [in] group EC group associated with point. - * @param [in, out] point EC point to set data into. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_ECPoint_d2i(const unsigned char *in, unsigned int len, - const WOLFSSL_EC_GROUP *group, WOLFSSL_EC_POINT *point) -{ - int ret = 1; - WOLFSSL_BIGNUM* x = NULL; - WOLFSSL_BIGNUM* y = NULL; - - WOLFSSL_ENTER("wolfSSL_ECPoint_d2i"); - - /* Validate parameters. */ - if ((in == NULL) || (group == NULL) || (point == NULL) || - (point->internal == NULL)) { - WOLFSSL_MSG("wolfSSL_ECPoint_d2i NULL error"); - ret = 0; - } - - if (ret == 1) { - #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - /* Import point into internal EC point. */ - if (wc_ecc_import_point_der_ex(in, len, group->curve_idx, - (ecc_point*)point->internal, 0) != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_import_point_der_ex failed"); - ret = 0; - } - #else - /* ECC_POINT_UNCOMP is not defined CAVP self test so use magic number */ - if (in[0] == 0x04) { - /* Import point into internal EC point. */ - if (wc_ecc_import_point_der((unsigned char *)in, len, - group->curve_idx, (ecc_point*)point->internal) != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_import_point_der failed"); - ret = 0; - } - } - else { - WOLFSSL_MSG("Only uncompressed points supported with " - "HAVE_SELFTEST"); - ret = 0; - } - #endif - } - - if (ret == 1) - point->inSet = 1; - - /* Set new external point. */ - if (ret == 1 && ec_point_external_set(point) != 1) { - WOLFSSL_MSG("ec_point_external_set failed"); - ret = 0; - } - - if (ret == 1 && !wolfSSL_BN_is_one(point->Z)) { -#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) - x = wolfSSL_BN_new(); - y = wolfSSL_BN_new(); - if (x == NULL || y == NULL) - ret = 0; - - if (ret == 1 && wolfSSL_EC_POINT_get_affine_coordinates_GFp(group, - point, x, y, NULL) != 1) { - WOLFSSL_MSG("wolfSSL_EC_POINT_get_affine_coordinates_GFp failed"); - ret = 0; - } - - /* wolfSSL_EC_POINT_set_affine_coordinates_GFp check that the point is - * on the curve. */ - if (ret == 1 && wolfSSL_EC_POINT_set_affine_coordinates_GFp(group, - point, x, y, NULL) != 1) { - WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp failed"); - ret = 0; - } -#else - WOLFSSL_MSG("Importing non-affine point. This may cause issues in math " - "operations later on."); -#endif - } - - if (ret == 1) { - /* Dump new point. */ - wolfSSL_EC_POINT_dump("d2i p", point); - } - - wolfSSL_BN_free(x); - wolfSSL_BN_free(y); - - return ret; -} - -/* Encode point as octet string. - * - * HYBRID not supported. - * - * @param [in] group EC group that point belongs to. - * @param [in] point EC point to encode. - * @param [in] form Format of encoding. Valid values: - * POINT_CONVERSION_UNCOMPRESSED,POINT_CONVERSION_COMPRESSED - * @param [out] buf Buffer to write encoding into. - * @param [in] len Length of buffer. - * @param [in] ctx Context to use for BN operations. Unused. - * @return Length of encoded data on success. - * @return 0 on error. - */ -size_t wolfSSL_EC_POINT_point2oct(const WOLFSSL_EC_GROUP *group, - const WOLFSSL_EC_POINT *point, int form, byte *buf, size_t len, - WOLFSSL_BN_CTX *ctx) -{ - int err = 0; - word32 enc_len = (word32)len; -#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - int compressed = ((form == WC_POINT_CONVERSION_COMPRESSED) ? 1 : 0); -#endif /* !HAVE_SELFTEST */ - - WOLFSSL_ENTER("wolfSSL_EC_POINT_point2oct"); - - /* No BN operations performed. */ - (void)ctx; - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL)) { - err = 1; - } - - /* Ensure points internals are set up. */ - if ((!err) && (ec_point_setup(point) != 1)) { - err = 1; - } - - /* Special case when point is infinity. */ - if ((!err) && wolfSSL_EC_POINT_is_at_infinity(group, point)) { - /* Encoding is a single octet: 0x00. */ - enc_len = 1; - if (buf != NULL) { - /* Check whether buffer has space. */ - if (len < 1) { - wolfSSL_ECerr(WOLFSSL_EC_F_EC_GFP_SIMPLE_POINT2OCT, BUFFER_E); - err = 1; - } - else { - /* Put in encoding of infinity. */ - buf[0] = 0x00; - } - } - } - /* Not infinity. */ - else if (!err) { - /* Validate format. */ - if (form != WC_POINT_CONVERSION_UNCOMPRESSED - #ifndef HAVE_SELFTEST - && form != WC_POINT_CONVERSION_COMPRESSED - #endif /* !HAVE_SELFTEST */ - ) { - WOLFSSL_MSG("Unsupported point form"); - err = 1; - } - - if (!err) { - int ret; - - #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - /* Encode as compressed or uncompressed. */ - ret = wc_ecc_export_point_der_ex(group->curve_idx, - (ecc_point*)point->internal, buf, &enc_len, compressed); - #else - /* Encode uncompressed point in DER format. */ - ret = wc_ecc_export_point_der(group->curve_idx, - (ecc_point*)point->internal, buf, &enc_len); - #endif /* !HAVE_SELFTEST */ - /* Check return. When buf is NULL, return will be length only - * error. - */ - if (ret != ((buf != NULL) ? MP_OKAY : WC_NO_ERR_TRACE(LENGTH_ONLY_E))) { - err = 1; - } - } - } - -#if defined(DEBUG_WOLFSSL) - if (!err) { - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_point2oct point", point); - WOLFSSL_MSG("\twolfSSL_EC_POINT_point2oct output:"); - WOLFSSL_BUFFER(buf, enc_len); - } -#endif - - /* On error, return encoding length of 0. */ - if (err) { - enc_len = 0; - } - return (size_t)enc_len; -} - - -/* Convert octet string to EC point. - * - * @param [in] group EC group. - * @param [in, out] point EC point to set data into. - * @param [in] buf Buffer holding octet string. - * @param [in] len Length of data in buffer in bytes. - * @param [in] ctx Context to use for BN operations. Unused. - */ -int wolfSSL_EC_POINT_oct2point(const WOLFSSL_EC_GROUP *group, - WOLFSSL_EC_POINT *point, const unsigned char *buf, size_t len, - WOLFSSL_BN_CTX *ctx) -{ - int ret; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_oct2point"); - - /* No BN operations performed. */ - (void)ctx; - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL)) { - ret = 0; - } - else { - /* Decode DER encoding into EC point. */ - ret = wolfSSL_ECPoint_d2i((unsigned char*)buf, (unsigned int)len, group, - point); - } - - return ret; -} - -/* Convert an EC point to a single BN. - * - * @param [in] group EC group. - * @param [in] point EC point. - * @param [in] form Format of encoding. Valid values: - * WC_POINT_CONVERSION_UNCOMPRESSED, - * WC_POINT_CONVERSION_COMPRESSED. - * @param [in, out] bn BN to hold point value. - * When NULL a new BN is allocated otherwise this is - * returned on success. - * @param [in] ctx Context to use for BN operations. Unused. - * @return BN object with point as a value on success. - * @return NULL on error. - */ -WOLFSSL_BIGNUM *wolfSSL_EC_POINT_point2bn(const WOLFSSL_EC_GROUP* group, - const WOLFSSL_EC_POINT* point, int form, WOLFSSL_BIGNUM* bn, - WOLFSSL_BN_CTX* ctx) -{ - int err = 0; - size_t len = 0; - byte *buf = NULL; - WOLFSSL_BIGNUM *ret = NULL; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_oct2point"); - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL)) { - err = 1; - } - - /* Calculate length of octet encoding. */ - if ((!err) && ((len = wolfSSL_EC_POINT_point2oct(group, point, form, NULL, - 0, ctx)) == 0)) { - err = 1; - } - /* Allocate buffer to hold octet encoding. */ - if ((!err) && ((buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER)) == - NULL)) { - WOLFSSL_MSG("malloc failed"); - err = 1; - } - /* Encode EC point as an octet string. */ - if ((!err) && (wolfSSL_EC_POINT_point2oct(group, point, form, buf, len, - ctx) != len)) { - err = 1; - } - /* Load BN with octet string data. */ - if (!err) { - ret = wolfSSL_BN_bin2bn(buf, (int)len, bn); - } - - /* Dispose of any allocated data. */ - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - - return ret; -} - -#if defined(USE_ECC_B_PARAM) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) -/* Check if EC point is on the the curve defined by the EC group. - * - * @param [in] group EC group defining curve. - * @param [in] point EC point to check. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 1 when point is on curve. - * @return 0 when point is not on curve or error. - */ -int wolfSSL_EC_POINT_is_on_curve(const WOLFSSL_EC_GROUP *group, - const WOLFSSL_EC_POINT *point, WOLFSSL_BN_CTX *ctx) -{ - int err = 0; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_is_on_curve"); - - /* No BN operations performed. */ - (void)ctx; - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL)) { - WOLFSSL_MSG("Invalid arguments"); - err = 1; - } - - /* Ensure internal EC point set. */ - if ((!err) && (!point->inSet) && ec_point_internal_set( - (WOLFSSL_EC_POINT*)point) != 1) { - WOLFSSL_MSG("ec_point_internal_set error"); - err = 1; - } - - /* Check point is on curve from group. */ - if ((!err) && (wc_ecc_point_is_on_curve((ecc_point*)point->internal, - group->curve_idx) != MP_OKAY)) { - err = 1; - } - - /* Return boolean of on curve. No error means on curve. */ - return !err; -} -#endif /* USE_ECC_B_PARAM && !HAVE_SELFTEST && !(FIPS_VERSION <= 2) */ - -#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) -/* Convert Jacobian ordinates to affine. - * - * @param [in] group EC group. - * @param [in] point EC point to get coordinates from. - * @return 1 on success. - * @return 0 on error. - */ -int ec_point_convert_to_affine(const WOLFSSL_EC_GROUP *group, - WOLFSSL_EC_POINT *point) -{ - int err = 0; - mp_digit mp = 0; - WC_DECLARE_VAR(modulus, mp_int, 1, 0); - - /* Allocate memory for curve's prime modulus. */ - WC_ALLOC_VAR_EX(modulus, mp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, err=1); - /* Initialize the MP integer. */ - if ((!err) && (mp_init(modulus) != MP_OKAY)) { - WOLFSSL_MSG("mp_init failed"); - err = 1; - } - - if (!err) { - /* Get the modulus from the hex string in the EC curve set. */ - if (mp_read_radix(modulus, ecc_sets[group->curve_idx].prime, - MP_RADIX_HEX) != MP_OKAY) { - WOLFSSL_MSG("mp_read_radix failed"); - err = 1; - } - /* Get Montgomery multiplier for the modulus as ordinates in - * Montgomery form. - */ - if ((!err) && (mp_montgomery_setup(modulus, &mp) != MP_OKAY)) { - WOLFSSL_MSG("mp_montgomery_setup failed"); - err = 1; - } - /* Map internal EC point from Jacobian to affine. */ - if ((!err) && (ecc_map((ecc_point*)point->internal, modulus, mp) != - MP_OKAY)) { - WOLFSSL_MSG("ecc_map failed"); - err = 1; - } - /* Set new ordinates into external EC point. */ - if ((!err) && (ec_point_external_set((WOLFSSL_EC_POINT *)point) != 1)) { - WOLFSSL_MSG("ec_point_external_set failed"); - err = 1; - } - - point->exSet = !err; - mp_clear(modulus); - } - - WC_FREE_VAR_EX(modulus, NULL, DYNAMIC_TYPE_BIGINT); - - return err; -} - -/* Get the affine coordinates of the EC point on a Prime curve. - * - * When z-ordinate is not one then coordinates are Jacobian and need to be - * converted to affine before storing in BNs. - * - * Return code compliant with OpenSSL. - * - * TODO: OpenSSL doesn't change point when Jacobian. Do the same? - * - * @param [in] group EC group. - * @param [in] point EC point to get coordinates from. - * @param [in, out] x BN to hold x-ordinate. - * @param [in, out] y BN to hold y-ordinate. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_EC_POINT_get_affine_coordinates_GFp(const WOLFSSL_EC_GROUP* group, - const WOLFSSL_EC_POINT* point, WOLFSSL_BIGNUM* x, WOLFSSL_BIGNUM* y, - WOLFSSL_BN_CTX* ctx) -{ - int ret = 1; - - /* BN operations don't need context. */ - (void)ctx; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_get_affine_coordinates_GFp"); - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL) || (point->internal == NULL) || - (x == NULL) || (y == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_POINT_get_affine_coordinates_GFp NULL error"); - ret = 0; - } - /* Don't return point at infinity. */ - if ((ret == 1) && wolfSSL_EC_POINT_is_at_infinity(group, point)) { - ret = 0; - } - - /* Ensure internal EC point has values of external EC point. */ - if ((ret == 1) && (ec_point_setup(point) != 1)) { - ret = 0; - } - - /* Check whether ordinates are in Jacobian form. */ - if ((ret == 1) && (!wolfSSL_BN_is_one(point->Z))) { - /* Convert from Jacobian to affine. */ - if (ec_point_convert_to_affine(group, (WOLFSSL_EC_POINT*)point) == 1) { - ret = 0; - } - } - - /* Copy the externally set x and y ordinates. */ - if ((ret == 1) && (wolfSSL_BN_copy(x, point->X) == NULL)) { - ret = 0; - } - if ((ret == 1) && (wolfSSL_BN_copy(y, point->Y) == NULL)) { - ret = 0; - } - - return ret; -} -#endif /* !WOLFSSL_SP_MATH && !WOLF_CRYPTO_CB_ONLY_ECC */ - -/* Sets the affine coordinates that belong on a prime curve. - * - * @param [in] group EC group. - * @param [in, out] point EC point to set coordinates into. - * @param [in] x BN holding x-ordinate. - * @param [in] y BN holding y-ordinate. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_EC_POINT_set_affine_coordinates_GFp(const WOLFSSL_EC_GROUP* group, - WOLFSSL_EC_POINT* point, const WOLFSSL_BIGNUM* x, const WOLFSSL_BIGNUM* y, - WOLFSSL_BN_CTX* ctx) -{ - int ret = 1; - - /* BN operations don't need context. */ - (void)ctx; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_set_affine_coordinates_GFp"); - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL) || (point->internal == NULL) || - (x == NULL) || (y == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp NULL error"); - ret = 0; - } - - /* Ensure we have a object for x-ordinate. */ - if ((ret == 1) && (point->X == NULL) && - ((point->X = wolfSSL_BN_new()) == NULL)) { - WOLFSSL_MSG("wolfSSL_BN_new failed"); - ret = 0; - } - /* Ensure we have a object for y-ordinate. */ - if ((ret == 1) && (point->Y == NULL) && - ((point->Y = wolfSSL_BN_new()) == NULL)) { - WOLFSSL_MSG("wolfSSL_BN_new failed"); - ret = 0; - } - /* Ensure we have a object for z-ordinate. */ - if ((ret == 1) && (point->Z == NULL) && - ((point->Z = wolfSSL_BN_new()) == NULL)) { - WOLFSSL_MSG("wolfSSL_BN_new failed"); - ret = 0; - } - - /* Copy the x-ordinate. */ - if ((ret == 1) && ((wolfSSL_BN_copy(point->X, x)) == NULL)) { - WOLFSSL_MSG("wolfSSL_BN_copy failed"); - ret = 0; - } - /* Copy the y-ordinate. */ - if ((ret == 1) && ((wolfSSL_BN_copy(point->Y, y)) == NULL)) { - WOLFSSL_MSG("wolfSSL_BN_copy failed"); - ret = 0; - } - /* z-ordinate is one for affine coordinates. */ - if ((ret == 1) && ((wolfSSL_BN_one(point->Z)) == 0)) { - WOLFSSL_MSG("wolfSSL_BN_one failed"); - ret = 0; - } - - /* Copy the new point data to internal object. */ - if ((ret == 1) && (ec_point_internal_set((WOLFSSL_EC_POINT *)point) != 1)) { - WOLFSSL_MSG("ec_point_internal_set failed"); - ret = 0; - } - -#if defined(USE_ECC_B_PARAM) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) - /* Check that the point is valid. */ - if ((ret == 1) && (wolfSSL_EC_POINT_is_on_curve(group, - (WOLFSSL_EC_POINT *)point, ctx) != 1)) { - WOLFSSL_MSG("EC_POINT_is_on_curve failed"); - ret = 0; - } -#endif - - return ret; -} - -#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \ - !defined(HAVE_SELFTEST) && !defined(WOLFSSL_SP_MATH) && \ - !defined(WOLF_CRYPTO_CB_ONLY_ECC) -/* Add two points on the same together. - * - * @param [in] curveIdx Index of curve in ecc_set. - * @param [out] r Result point. - * @param [in] p1 First point to add. - * @param [in] p2 Second point to add. - * @return 1 on success. - * @return 0 on error. - */ -static int wolfssl_ec_point_add(int curveIdx, ecc_point* r, ecc_point* p1, - ecc_point* p2) -{ - int ret = 1; -#ifdef WOLFSSL_SMALL_STACK - mp_int* a = NULL; - mp_int* prime = NULL; - mp_int* mu = NULL; -#else - mp_int a[1]; - mp_int prime[1]; - mp_int mu[1]; -#endif - mp_digit mp = 0; - ecc_point* montP1 = NULL; - ecc_point* montP2 = NULL; - -#ifdef WOLFSSL_SMALL_STACK - if (ret == 1) { - /* Allocate memory for curve parameter: a. */ - a = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); - if (a == NULL) { - WOLFSSL_MSG("Failed to allocate memory for mp_int a"); - ret = 0; - } - } - if (ret == 1) { - /* Allocate memory for curve parameter: prime. */ - prime = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); - if (prime == NULL) { - WOLFSSL_MSG("Failed to allocate memory for mp_int prime"); - ret = 0; - } - } - if (ret == 1) { - /* Allocate memory for mu (Montgomery normalizer). */ - mu = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); - if (mu == NULL) { - WOLFSSL_MSG("Failed to allocate memory for mp_int mu"); - ret = 0; - } - } - if (ret == 1) { - /* Zero out all MP int data in case initialization fails. */ - XMEMSET(a, 0, sizeof(mp_int)); - XMEMSET(prime, 0, sizeof(mp_int)); - XMEMSET(mu, 0, sizeof(mp_int)); - } -#endif - - /* Initialize the MP ints. */ - if ((ret == 1) && (mp_init_multi(prime, a, mu, NULL, NULL, NULL) != - MP_OKAY)) { - WOLFSSL_MSG("mp_init_multi error"); - ret = 0; - } - - /* Read the curve parameter: a. */ - if ((ret == 1) && (mp_read_radix(a, ecc_sets[curveIdx].Af, MP_RADIX_HEX) != - MP_OKAY)) { - WOLFSSL_MSG("mp_read_radix a error"); - ret = 0; - } - - /* Read the curve parameter: prime. */ - if ((ret == 1) && (mp_read_radix(prime, ecc_sets[curveIdx].prime, - MP_RADIX_HEX) != MP_OKAY)) { - WOLFSSL_MSG("mp_read_radix prime error"); - ret = 0; - } - - /* Calculate the Montgomery product. */ - if ((ret == 1) && (mp_montgomery_setup(prime, &mp) != MP_OKAY)) { - WOLFSSL_MSG("mp_montgomery_setup nqm error"); - ret = 0; - } - - /* TODO: use the heap filed of one of the points? */ - /* Allocate new points to hold the Montgomery form values. */ - if ((ret == 1) && (((montP1 = wc_ecc_new_point_h(NULL)) == NULL) || - ((montP2 = wc_ecc_new_point_h(NULL)) == NULL))) { - WOLFSSL_MSG("wc_ecc_new_point_h nqm error"); - ret = 0; - } - - /* Calculate the Montgomery normalizer. */ - if ((ret == 1) && (mp_montgomery_calc_normalization(mu, prime) != - MP_OKAY)) { - WOLFSSL_MSG("mp_montgomery_calc_normalization error"); - ret = 0; - } - - /* Convert to Montgomery form. */ - if ((ret == 1) && (mp_cmp_d(mu, 1) == MP_EQ)) { - /* Copy the points if the normalizer is 1. */ - if ((wc_ecc_copy_point(p1, montP1) != MP_OKAY) || - (wc_ecc_copy_point(p2, montP2) != MP_OKAY)) { - WOLFSSL_MSG("wc_ecc_copy_point error"); - ret = 0; - } - } - else if (ret == 1) { - /* Multiply each ordinate by the Montgomery normalizer. */ - if ((mp_mulmod(p1->x, mu, prime, montP1->x) != MP_OKAY) || - (mp_mulmod(p1->y, mu, prime, montP1->y) != MP_OKAY) || - (mp_mulmod(p1->z, mu, prime, montP1->z) != MP_OKAY)) { - WOLFSSL_MSG("mp_mulmod error"); - ret = 0; - } - /* Multiply each ordinate by the Montgomery normalizer. */ - if ((mp_mulmod(p2->x, mu, prime, montP2->x) != MP_OKAY) || - (mp_mulmod(p2->y, mu, prime, montP2->y) != MP_OKAY) || - (mp_mulmod(p2->z, mu, prime, montP2->z) != MP_OKAY)) { - WOLFSSL_MSG("mp_mulmod error"); - ret = 0; - } - } - - /* Perform point addition with internal EC point objects - Jacobian form - * result. - */ - if ((ret == 1) && (ecc_projective_add_point(montP1, montP2, r, a, prime, - mp) != MP_OKAY)) { - WOLFSSL_MSG("ecc_projective_add_point error"); - ret = 0; - } - - /* Map point back to affine coordinates. Converts from Montogomery form. */ - if ((ret == 1) && (ecc_map(r, prime, mp) != MP_OKAY)) { - WOLFSSL_MSG("ecc_map error"); - ret = 0; - } - - /* Dispose of allocated memory. */ - mp_clear(a); - mp_clear(prime); - mp_clear(mu); - wc_ecc_del_point_h(montP1, NULL); - wc_ecc_del_point_h(montP2, NULL); - WC_FREE_VAR_EX(a, NULL, DYNAMIC_TYPE_BIGINT); - WC_FREE_VAR_EX(prime, NULL, DYNAMIC_TYPE_BIGINT); - WC_FREE_VAR_EX(mu, NULL, DYNAMIC_TYPE_BIGINT); - return ret; -} - -/* Add two points on the same curve together. - * - * @param [in] group EC group. - * @param [out] r EC point that is result of point addition. - * @param [in] p1 First EC point to add. - * @param [in] p2 Second EC point to add. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_EC_POINT_add(const WOLFSSL_EC_GROUP* group, WOLFSSL_EC_POINT* r, - const WOLFSSL_EC_POINT* p1, const WOLFSSL_EC_POINT* p2, WOLFSSL_BN_CTX* ctx) -{ - int ret = 1; - - /* No BN operations performed. */ - (void)ctx; - - /* Validate parameters. */ - if ((group == NULL) || (r == NULL) || (p1 == NULL) || (p2 == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_POINT_add error"); - ret = 0; - } - - /* Ensure the internal objects of the EC points are setup. */ - if ((ret == 1) && ((ec_point_setup(r) != 1) || (ec_point_setup(p1) != 1) || - (ec_point_setup(p2) != 1))) { - WOLFSSL_MSG("ec_point_setup error"); - ret = 0; - } - -#ifdef DEBUG_WOLFSSL - if (ret == 1) { - int nid = wolfSSL_EC_GROUP_get_curve_name(group); - const char* curve = wolfSSL_OBJ_nid2ln(nid); - const char* nistName = wolfSSL_EC_curve_nid2nist(nid); - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_add p1", p1); - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_add p2", p2); - if (curve != NULL) - WOLFSSL_MSG_EX("curve name: %s", curve); - if (nistName != NULL) - WOLFSSL_MSG_EX("nist curve name: %s", nistName); - } -#endif - - if (ret == 1) { - /* Add points using wolfCrypt objects. */ - ret = wolfssl_ec_point_add(group->curve_idx, (ecc_point*)r->internal, - (ecc_point*)p1->internal, (ecc_point*)p2->internal); - } - - /* Copy internal EC point values out to external EC point. */ - if ((ret == 1) && (ec_point_external_set(r) != 1)) { - WOLFSSL_MSG("ec_point_external_set error"); - ret = 0; - } - -#ifdef DEBUG_WOLFSSL - if (ret == 1) { - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_add result", r); - } -#endif - - return ret; -} - -/* Sum the scalar multiplications of the base point and n, and q and m. - * - * r = base point * n + q * m - * - * @param [out] r EC point that is result of operation. - * @param [in] b Base point of curve. - * @param [in] n Scalar to multiply by base point. - * @param [in] q EC point to be scalar multiplied. - * @param [in] m Scalar to multiply q by. - * @param [in] a Parameter A of curve. - * @param [in] prime Prime (modulus) of curve. - * @return 1 on success. - * @return 0 on error. - */ -static int ec_mul2add(ecc_point* r, ecc_point* b, mp_int* n, ecc_point* q, - mp_int* m, mp_int* a, mp_int* prime) -{ - int ret = 1; -#if defined(ECC_SHAMIR) && !defined(WOLFSSL_KCAPI_ECC) - if (ecc_mul2add(b, n, q, m, r, a, prime, NULL) != MP_OKAY) { - WOLFSSL_MSG("ecc_mul2add error"); - ret = 0; - } -#else - ecc_point* tmp = NULL; - mp_digit mp = 0; - - /* Calculate Montgomery product. */ - if (mp_montgomery_setup(prime, &mp) != MP_OKAY) { - WOLFSSL_MSG("mp_montgomery_setup nqm error"); - ret = 0; - } - /* Create temporary point to hold: q * m */ - if ((ret == 1) && ((tmp = wc_ecc_new_point()) == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_POINT_new nqm error"); - ret = 0; - } - /* r = base point * n */ - if ((ret == 1) && (wc_ecc_mulmod(n, b, r, a, prime, 0) != - MP_OKAY)) { - WOLFSSL_MSG("wc_ecc_mulmod nqm error"); - ret = 0; - } - /* tmp = q * m */ - if ((ret == 1) && (wc_ecc_mulmod(m, q, tmp, a, prime, 0) != MP_OKAY)) { - WOLFSSL_MSG("wc_ecc_mulmod nqm error"); - ret = 0; - } - /* r = r + tmp */ - if ((ret == 1) && (ecc_projective_add_point(tmp, r, r, a, prime, mp) != - MP_OKAY)) { - WOLFSSL_MSG("wc_ecc_mulmod nqm error"); - ret = 0; - } - /* Map point back to affine coordinates. Converts from Montogomery - * form. */ - if ((ret == 1) && (ecc_map(r, prime, mp) != MP_OKAY)) { - WOLFSSL_MSG("ecc_map nqm error"); - ret = 0; - } - - /* Dispose of allocated temporary point. */ - wc_ecc_del_point(tmp); -#endif - - return ret; -} - -/* Sum the scalar multiplications of the base point and n, and q and m. - * - * r = base point * n + q * m - * - * @param [in] curveIdx Index of curve in ecc_set. - * @param [out] r EC point that is result of operation. - * @param [in] n Scalar to multiply by base point. May be NULL. - * @param [in] q EC point to be scalar multiplied. May be NULL. - * @param [in] m Scalar to multiply q by. May be NULL. - * @return 1 on success. - * @return 0 on error. - */ -static int wolfssl_ec_point_mul(int curveIdx, ecc_point* r, mp_int* n, - ecc_point* q, mp_int* m) -{ - int ret = 1; -#ifdef WOLFSSL_SMALL_STACK - mp_int* a = NULL; - mp_int* prime = NULL; -#else - mp_int a[1], prime[1]; -#endif - -#ifdef WOLFSSL_SMALL_STACK - /* Allocate MP integer for curve parameter: a. */ - a = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); - if (a == NULL) { - ret = 0; - } - if (ret == 1) { - /* Allocate MP integer for curve parameter: prime. */ - prime = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); - if (prime == NULL) { - ret = 0; - } - } -#endif - - /* Initialize the MP ints. */ - if ((ret == 1) && (mp_init_multi(prime, a, NULL, NULL, NULL, NULL) != - MP_OKAY)) { - WOLFSSL_MSG("mp_init_multi error"); - ret = 0; - } - - /* Read the curve parameter: prime. */ - if ((ret == 1) && (mp_read_radix(prime, ecc_sets[curveIdx].prime, - MP_RADIX_HEX) != MP_OKAY)) { - WOLFSSL_MSG("mp_read_radix prime error"); - ret = 0; - } - - /* Read the curve parameter: a. */ - if ((ret == 1) && (mp_read_radix(a, ecc_sets[curveIdx].Af, - MP_RADIX_HEX) != MP_OKAY)) { - WOLFSSL_MSG("mp_read_radix a error"); - ret = 0; - } - - if ((ret == 1) && (n != NULL)) { - /* Get generator - base point. */ - #if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) - if ((ret == 1) && (wc_ecc_get_generator(r, curveIdx) != MP_OKAY)) { - WOLFSSL_MSG("wc_ecc_get_generator error"); - ret = 0; - } - #else - /* wc_ecc_get_generator is not defined in the FIPS v2 module. */ - /* Read generator (base point) x-ordinate. */ - if ((ret == 1) && (mp_read_radix(r->x, ecc_sets[curveIdx].Gx, - MP_RADIX_HEX) != MP_OKAY)) { - WOLFSSL_MSG("mp_read_radix Gx error"); - ret = 0; - } - /* Read generator (base point) y-ordinate. */ - if ((ret == 1) && (mp_read_radix(r->y, ecc_sets[curveIdx].Gy, - MP_RADIX_HEX) != MP_OKAY)) { - WOLFSSL_MSG("mp_read_radix Gy error"); - ret = 0; - } - /* z-ordinate is one as point is affine. */ - if ((ret == 1) && (mp_set(r->z, 1) != MP_OKAY)) { - WOLFSSL_MSG("mp_set Gz error"); - ret = 0; - } - #endif /* NOPT_FIPS_VERSION == 2 */ - } - - if ((ret == 1) && (n != NULL) && (q != NULL) && (m != NULL)) { - /* r = base point * n + q * m */ - ret = ec_mul2add(r, r, n, q, m, a, prime); - } - /* Not all values present, see if we are only doing base point * n. */ - else if ((ret == 1) && (n != NULL)) { - /* r = base point * n */ - if (wc_ecc_mulmod(n, r, r, a, prime, 1) != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_mulmod gn error"); - ret = 0; - } - } - /* Not all values present, see if we are only doing q * m. */ - else if ((ret == 1) && (q != NULL) && (m != NULL)) { - /* r = q * m */ - if (wc_ecc_mulmod(m, q, r, a, prime, 1) != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_mulmod qm error"); - ret = 0; - } - } - /* No values to use. */ - else if (ret == 1) { - /* Set result to infinity as no values passed in. */ - mp_zero(r->x); - mp_zero(r->y); - mp_zero(r->z); - } - - mp_clear(a); - mp_clear(prime); - WC_FREE_VAR_EX(a, NULL, DYNAMIC_TYPE_BIGINT); - WC_FREE_VAR_EX(prime, NULL, DYNAMIC_TYPE_BIGINT); - return ret; -} - -/* Sum the scalar multiplications of the base point and n, and q and m. - * - * r = base point * n + q * m - * - * Return code compliant with OpenSSL. - * - * @param [in] group EC group. - * @param [out] r EC point that is result of operation. - * @param [in] n Scalar to multiply by base point. May be NULL. - * @param [in] q EC point to be scalar multiplied. May be NULL. - * @param [in] m Scalar to multiply q by. May be NULL. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_EC_POINT_mul(const WOLFSSL_EC_GROUP *group, WOLFSSL_EC_POINT *r, - const WOLFSSL_BIGNUM *n, const WOLFSSL_EC_POINT *q, const WOLFSSL_BIGNUM *m, - WOLFSSL_BN_CTX *ctx) -{ - int ret = 1; - - /* No BN operations performed. */ - (void)ctx; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_mul"); - - /* Validate parameters. */ - if ((group == NULL) || (r == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_POINT_mul NULL error"); - ret = 0; - } - - /* Ensure the internal representation of the EC point q is setup. */ - if ((ret == 1) && (q != NULL) && (ec_point_setup(q) != 1)) { - WOLFSSL_MSG("ec_point_setup error"); - ret = 0; - } - -#ifdef DEBUG_WOLFSSL - if (ret == 1) { - int nid = wolfSSL_EC_GROUP_get_curve_name(group); - const char* curve = wolfSSL_OBJ_nid2ln(nid); - const char* nistName = wolfSSL_EC_curve_nid2nist(nid); - char* num; - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_mul input q", q); - num = wolfSSL_BN_bn2hex(n); - WOLFSSL_MSG_EX("\tn = %s", num); - XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); - num = wolfSSL_BN_bn2hex(m); - WOLFSSL_MSG_EX("\tm = %s", num); - XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); - if (curve != NULL) - WOLFSSL_MSG_EX("curve name: %s", curve); - if (nistName != NULL) - WOLFSSL_MSG_EX("nist curve name: %s", nistName); - } -#endif - - if (ret == 1) { - mp_int* ni = (n != NULL) ? (mp_int*)n->internal : NULL; - ecc_point* qi = (q != NULL) ? (ecc_point*)q->internal : NULL; - mp_int* mi = (m != NULL) ? (mp_int*)m->internal : NULL; - - /* Perform multiplication with wolfCrypt objects. */ - ret = wolfssl_ec_point_mul(group->curve_idx, (ecc_point*)r->internal, - ni, qi, mi); - } - - /* Only on success is the internal point guaranteed to be set. */ - if (r != NULL) { - r->inSet = (ret == 1); - } - /* Copy internal EC point values out to external EC point. */ - if ((ret == 1) && (ec_point_external_set(r) != 1)) { - WOLFSSL_MSG("ec_point_external_set error"); - ret = 0; - } - -#ifdef DEBUG_WOLFSSL - if (ret == 1) { - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_mul result", r); - } -#endif - - return ret; -} -#endif /* !WOLFSSL_ATECC508A && !WOLFSSL_ATECC608A && !HAVE_SELFTEST && - * !WOLFSSL_SP_MATH */ - -/* Invert the point on the curve. - * (x, y) -> (x, -y) = (x, (prime - y) % prime) - * - * @param [in] curveIdx Index of curve in ecc_set. - * @param [in, out] point EC point to invert. - * @return 1 on success. - * @return 0 on error. - */ -static int wolfssl_ec_point_invert(int curveIdx, ecc_point* point) -{ - int ret = 1; - WC_DECLARE_VAR(prime, mp_int, 1, 0); - - /* Allocate memory for an MP int to hold the prime of the curve. */ - WC_ALLOC_VAR_EX(prime, mp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, ret=0); - - /* Initialize MP int. */ - if ((ret == 1) && (mp_init(prime) != MP_OKAY)) { - WOLFSSL_MSG("mp_init_multi error"); - ret = 0; - } - - /* Read the curve parameter: prime. */ - if ((ret == 1) && (mp_read_radix(prime, ecc_sets[curveIdx].prime, - MP_RADIX_HEX) != MP_OKAY)) { - WOLFSSL_MSG("mp_read_radix prime error"); - ret = 0; - } - - /* y = (prime - y) mod prime. */ - if ((ret == 1) && (!mp_iszero(point->y)) && (mp_sub(prime, point->y, - point->y) != MP_OKAY)) { - WOLFSSL_MSG("mp_sub error"); - ret = 0; - } - - /* Dispose of memory associated with MP. */ - mp_free(prime); - WC_FREE_VAR_EX(prime, NULL, DYNAMIC_TYPE_BIGINT); - return ret; -} - -/* Invert the point on the curve. - * (x, y) -> (x, -y) = (x, (prime - y) % prime) - * - * @param [in] group EC group. - * @param [in, out] point EC point to invert. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_EC_POINT_invert(const WOLFSSL_EC_GROUP *group, - WOLFSSL_EC_POINT *point, WOLFSSL_BN_CTX *ctx) -{ - int ret = 1; - - /* No BN operations performed. */ - (void)ctx; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_invert"); - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL) || (point->internal == NULL)) { - ret = 0; - } - - /* Ensure internal representation of point is setup. */ - if ((ret == 1) && (ec_point_setup(point) != 1)) { - ret = 0; - } - -#ifdef DEBUG_WOLFSSL - if (ret == 1) { - int nid = wolfSSL_EC_GROUP_get_curve_name(group); - const char* curve = wolfSSL_OBJ_nid2ln(nid); - const char* nistName = wolfSSL_EC_curve_nid2nist(nid); - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_invert input", point); - if (curve != NULL) - WOLFSSL_MSG_EX("curve name: %s", curve); - if (nistName != NULL) - WOLFSSL_MSG_EX("nist curve name: %s", nistName); - - } -#endif - - if (ret == 1 && !wolfSSL_BN_is_one(point->Z)) { -#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) - if (ec_point_convert_to_affine(group, point) != 0) - ret = 0; -#else - WOLFSSL_MSG("wolfSSL_EC_POINT_invert called on non-affine point"); - ret = 0; -#endif - } - - if (ret == 1) { - /* Perform inversion using wolfCrypt objects. */ - ret = wolfssl_ec_point_invert(group->curve_idx, - (ecc_point*)point->internal); - } - - /* Set the external EC point representation based on internal. */ - if ((ret == 1) && (ec_point_external_set(point) != 1)) { - WOLFSSL_MSG("ec_point_external_set error"); - ret = 0; - } - -#ifdef DEBUG_WOLFSSL - if (ret == 1) { - wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_invert result", point); - } -#endif - - return ret; -} - -#ifdef WOLFSSL_EC_POINT_CMP_JACOBIAN -/* Compare two points on a the same curve. - * - * (Ax, Ay, Az) => (Ax / (Az ^ 2), Ay / (Az ^ 3)) - * (Bx, By, Bz) => (Bx / (Bz ^ 2), By / (Bz ^ 3)) - * When equal: - * (Ax / (Az ^ 2), Ay / (Az ^ 3)) = (Bx / (Bz ^ 2), By / (Bz ^ 3)) - * => (Ax * (Bz ^ 2), Ay * (Bz ^ 3)) = (Bx * (Az ^ 2), By * (Az ^ 3)) - * - * @param [in] group EC group. - * @param [in] a EC point to compare. - * @param [in] b EC point to compare. - * @return 0 when equal. - * @return 1 when different. - * @return -1 on error. - */ -static int ec_point_cmp_jacobian(const WOLFSSL_EC_GROUP* group, - const WOLFSSL_EC_POINT *a, const WOLFSSL_EC_POINT *b, WOLFSSL_BN_CTX *ctx) -{ - int ret = 0; - BIGNUM* at = BN_new(); - BIGNUM* bt = BN_new(); - BIGNUM* az = BN_new(); - BIGNUM* bz = BN_new(); - BIGNUM* mod = BN_new(); - - /* Check that the big numbers were allocated. */ - if ((at == NULL) || (bt == NULL) || (az == NULL) || (bz == NULL) || - (mod == NULL)) { - ret = WOLFSSL_FATAL_ERROR; - } - /* Get the modulus for the curve. */ - if ((ret == 0) && - (BN_hex2bn(&mod, ecc_sets[group->curve_idx].prime) != 1)) { - ret = WOLFSSL_FATAL_ERROR; - } - if (ret == 0) { - /* bt = Bx * (Az ^ 2). When Az is one then just copy. */ - if (BN_is_one(a->Z)) { - if (BN_copy(bt, b->X) == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - } - /* az = Az ^ 2 */ - else if ((BN_mod_mul(az, a->Z, a->Z, mod, ctx) != 1)) { - ret = WOLFSSL_FATAL_ERROR; - } - /* bt = Bx * az = Bx * (Az ^ 2) */ - else if (BN_mod_mul(bt, b->X, az, mod, ctx) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 0) { - /* at = Ax * (Bz ^ 2). When Bz is one then just copy. */ - if (BN_is_one(b->Z)) { - if (BN_copy(at, a->X) == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - } - /* bz = Bz ^ 2 */ - else if (BN_mod_mul(bz, b->Z, b->Z, mod, ctx) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - /* at = Ax * bz = Ax * (Bz ^ 2) */ - else if (BN_mod_mul(at, a->X, bz, mod, ctx) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - } - /* Compare x-ordinates. */ - if ((ret == 0) && (BN_cmp(at, bt) != 0)) { - ret = 1; - } - if (ret == 0) { - /* bt = By * (Az ^ 3). When Az is one then just copy. */ - if (BN_is_one(a->Z)) { - if (BN_copy(bt, b->Y) == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - } - /* az = az * Az = Az ^ 3 */ - else if ((BN_mod_mul(az, az, a->Z, mod, ctx) != 1)) { - ret = WOLFSSL_FATAL_ERROR; - } - /* bt = By * az = By * (Az ^ 3) */ - else if (BN_mod_mul(bt, b->Y, az, mod, ctx) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - } - if (ret == 0) { - /* at = Ay * (Bz ^ 3). When Bz is one then just copy. */ - if (BN_is_one(b->Z)) { - if (BN_copy(at, a->Y) == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - } - /* bz = bz * Bz = Bz ^ 3 */ - else if (BN_mod_mul(bz, bz, b->Z, mod, ctx) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - /* at = Ay * bz = Ay * (Bz ^ 3) */ - else if (BN_mod_mul(at, a->Y, bz, mod, ctx) != 1) { - ret = WOLFSSL_FATAL_ERROR; - } - } - /* Compare y-ordinates. */ - if ((ret == 0) && (BN_cmp(at, bt) != 0)) { - ret = 1; - } - - BN_free(mod); - BN_free(bz); - BN_free(az); - BN_free(bt); - BN_free(at); - return ret; -} -#endif - -/* Compare two points on a the same curve. - * - * Return code compliant with OpenSSL. - * - * @param [in] group EC group. - * @param [in] a EC point to compare. - * @param [in] b EC point to compare. - * @param [in] ctx Context to use for BN operations. Unused. - * @return 0 when equal. - * @return 1 when different. - * @return -1 on error. - */ -int wolfSSL_EC_POINT_cmp(const WOLFSSL_EC_GROUP *group, - const WOLFSSL_EC_POINT *a, const WOLFSSL_EC_POINT *b, WOLFSSL_BN_CTX *ctx) -{ - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_cmp"); - - /* Validate parameters. */ - if ((group == NULL) || (a == NULL) || (a->internal == NULL) || - (b == NULL) || (b->internal == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_POINT_cmp Bad arguments"); - ret = WOLFSSL_FATAL_ERROR; - } - if (ret != -1) { - #ifdef WOLFSSL_EC_POINT_CMP_JACOBIAN - /* If same Z ordinate then no need to convert to affine. */ - if (BN_cmp(a->Z, b->Z) == 0) { - /* Compare */ - ret = ((BN_cmp(a->X, b->X) != 0) || (BN_cmp(a->Y, b->Y) != 0)); - } - else { - ret = ec_point_cmp_jacobian(group, a, b, ctx); - } - #else - /* No BN operations performed. */ - (void)ctx; - - ret = (wc_ecc_cmp_point((ecc_point*)a->internal, - (ecc_point*)b->internal) != MP_EQ); - #endif - } - - return ret; -} - -/* Copy EC point. - * - * @param [out] dest EC point to copy into. - * @param [in] src EC point to copy. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_EC_POINT_copy(WOLFSSL_EC_POINT *dest, const WOLFSSL_EC_POINT *src) -{ - int ret = 1; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_copy"); - - /* Validate parameters. */ - if ((dest == NULL) || (src == NULL)) { - ret = 0; - } - - /* Ensure internal EC point of src is setup. */ - if ((ret == 1) && (ec_point_setup(src) != 1)) { - ret = 0; - } - - /* Copy internal EC points. */ - if ((ret == 1) && (wc_ecc_copy_point((ecc_point*)src->internal, - (ecc_point*)dest->internal) != MP_OKAY)) { - ret = 0; - } - - if (ret == 1) { - /* Destinatation internal point is set. */ - dest->inSet = 1; - - /* Set the external EC point of dest based on internal. */ - if (ec_point_external_set(dest) != 1) { - ret = 0; - } - } - - return ret; -} - -/* Checks whether point is at infinity. - * - * Return code compliant with OpenSSL. - * - * @param [in] group EC group. - * @param [in] point EC point to check. - * @return 1 when at infinity. - * @return 0 when not at infinity. - */ -int wolfSSL_EC_POINT_is_at_infinity(const WOLFSSL_EC_GROUP *group, - const WOLFSSL_EC_POINT *point) -{ - int ret = 1; - - WOLFSSL_ENTER("wolfSSL_EC_POINT_is_at_infinity"); - - /* Validate parameters. */ - if ((group == NULL) || (point == NULL) || (point->internal == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_POINT_is_at_infinity NULL error"); - ret = 0; - } - - /* Ensure internal EC point is setup. */ - if ((ret == 1) && (ec_point_setup(point) != 1)) { - ret = 0; - } - if (ret == 1) { - #ifndef WOLF_CRYPTO_CB_ONLY_ECC - /* Check for infinity. */ - ret = wc_ecc_point_is_at_infinity((ecc_point*)point->internal); - if (ret < 0) { - WOLFSSL_MSG("ecc_point_is_at_infinity failure"); - /* Error return is 0 by OpenSSL. */ - ret = 0; - } - #else - WOLFSSL_MSG("ecc_point_is_at_infinitiy compiled out"); - ret = 0; - #endif - } - - return ret; -} - -#endif /* OPENSSL_EXTRA */ - -/* End EC_POINT */ - -/* Start EC_KEY */ - -#ifdef OPENSSL_EXTRA - -/* - * EC key constructor/deconstructor APIs - */ - -/* Allocate a new EC key. - * - * Not OpenSSL API. - * - * @param [in] heap Heap hint for dynamic memory allocation. - * @param [in] devId Device identifier value. - * @return New, allocated EC key on success. - * @return NULL on error. - */ -WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new_ex(void* heap, int devId) -{ - WOLFSSL_EC_KEY *key = NULL; - int err = 0; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_new"); - - /* Allocate memory for EC key. */ - key = (WOLFSSL_EC_KEY*)XMALLOC(sizeof(WOLFSSL_EC_KEY), heap, - DYNAMIC_TYPE_ECC); - if (key == NULL) { - WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc WOLFSSL_EC_KEY failure"); - err = 1; - } - if (!err) { - /* Reset all fields to 0. */ - XMEMSET(key, 0, sizeof(WOLFSSL_EC_KEY)); - /* Cache heap hint. */ - key->heap = heap; - /* Initialize fields to defaults. */ - key->form = WC_POINT_CONVERSION_UNCOMPRESSED; - - /* Initialize reference count. */ - wolfSSL_RefInit(&key->ref, &err); -#ifdef WOLFSSL_REFCNT_ERROR_RETURN - } - if (!err) { -#endif - /* Allocate memory for internal EC key representation. */ - key->internal = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, - DYNAMIC_TYPE_ECC); - if (key->internal == NULL) { - WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc ecc key failure"); - err = 1; - } - } - if (!err) { - /* Initialize wolfCrypt EC key. */ - if (wc_ecc_init_ex((ecc_key*)key->internal, heap, devId) != 0) { - WOLFSSL_MSG("wolfSSL_EC_KEY_new init ecc key failure"); - err = 1; - } - } - - if (!err) { - /* Group unknown at creation */ - key->group = wolfSSL_EC_GROUP_new_by_curve_name(WC_NID_undef); - if (key->group == NULL) { - WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc WOLFSSL_EC_GROUP failure"); - err = 1; - } - } - - if (!err) { - /* Allocate a point as public key. */ - key->pub_key = wolfSSL_EC_POINT_new(key->group); - if (key->pub_key == NULL) { - WOLFSSL_MSG("wolfSSL_EC_POINT_new failure"); - err = 1; - } - } - - if (!err) { - /* Allocate a BN as private key. */ - key->priv_key = wolfSSL_BN_new(); - if (key->priv_key == NULL) { - WOLFSSL_MSG("wolfSSL_BN_new failure"); - err = 1; - } - } - - if (err) { - /* Dispose of EC key on error. */ - wolfSSL_EC_KEY_free(key); - key = NULL; - } - /* Return new EC key object. */ - return key; -} - -/* Allocate a new EC key. - * - * @return New, allocated EC key on success. - * @return NULL on error. - */ -WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new(void) -{ - return wolfSSL_EC_KEY_new_ex(NULL, INVALID_DEVID); -} - -/* Create new EC key with the group having the specified numeric ID. - * - * @param [in] nid Numeric ID. - * @return New, allocated EC key on success. - * @return NULL on error. - */ -WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new_by_curve_name(int nid) -{ - WOLFSSL_EC_KEY *key; - int err = 0; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_new_by_curve_name"); - - /* Allocate empty, EC key. */ - key = wolfSSL_EC_KEY_new(); - if (key == NULL) { - WOLFSSL_MSG("wolfSSL_EC_KEY_new failure"); - err = 1; - } - - if (!err) { - /* Set group to be nid. */ - ec_group_set_nid(key->group, nid); - if (key->group->curve_idx == -1) { - wolfSSL_EC_KEY_free(key); - key = NULL; - } - } - - /* Return the new EC key object. */ - return key; -} - -/* Dispose of the EC key and allocated data. - * - * Cannot use key after this call. - * - * @param [in] key EC key to free. - */ -void wolfSSL_EC_KEY_free(WOLFSSL_EC_KEY *key) -{ - int doFree = 0; - int err; - - (void)err; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_free"); - - if (key != NULL) { - void* heap = key->heap; - - /* Decrement reference count. */ - wolfSSL_RefDec(&key->ref, &doFree, &err); - if (doFree) { - /* Dispose of allocated reference counting data. */ - wolfSSL_RefFree(&key->ref); - - /* Dispose of private key. */ - wolfSSL_BN_free(key->priv_key); - wolfSSL_EC_POINT_free(key->pub_key); - wolfSSL_EC_GROUP_free(key->group); - if (key->internal != NULL) { - /* Dispose of wolfCrypt representation of EC key. */ - wc_ecc_free((ecc_key*)key->internal); - XFREE(key->internal, heap, DYNAMIC_TYPE_ECC); - } - - /* Set back to NULLs for safety. */ - ForceZero(key, sizeof(*key)); - - /* Dispose of the memory associated with the EC key. */ - XFREE(key, heap, DYNAMIC_TYPE_ECC); - (void)heap; - } - } -} - -/* Increments ref count of EC key. - * - * @param [in, out] key EC key. - * @return 1 on success - * @return 0 on error - */ -int wolfSSL_EC_KEY_up_ref(WOLFSSL_EC_KEY* key) -{ - int err = 1; - - if (key != NULL) { - wolfSSL_RefInc(&key->ref, &err); - } - - return !err; -} - -#ifndef NO_CERTS - -#if defined(OPENSSL_ALL) -/* Copy the internal, wolfCrypt EC key. - * - * @param [in, out] dst Destination wolfCrypt EC key. - * @param [in] src Source wolfCrypt EC key. - * @return 0 on success. - * @return Negative on error. - */ -static int wolfssl_ec_key_int_copy(ecc_key* dst, const ecc_key* src) -{ - int ret; - - /* Copy public key. */ -#if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) - ret = wc_ecc_copy_point(&src->pubkey, &dst->pubkey); -#else - ret = wc_ecc_copy_point((ecc_point*)&src->pubkey, &dst->pubkey); -#endif - if (ret != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_copy_point error"); - } - - if (ret == 0) { - /* Copy private key. */ - ret = mp_copy(wc_ecc_key_get_priv((ecc_key*)src), - wc_ecc_key_get_priv(dst)); - if (ret != MP_OKAY) { - WOLFSSL_MSG("mp_copy error"); - } - } - - if (ret == 0) { - /* Copy domain parameters. */ - if (src->dp) { - ret = wc_ecc_set_curve(dst, 0, src->dp->id); - if (ret != 0) { - WOLFSSL_MSG("wc_ecc_set_curve error"); - } - } - } - - if (ret == 0) { - /* Copy the other components. */ - dst->type = src->type; - dst->idx = src->idx; - dst->state = src->state; - dst->flags = src->flags; - } - - return ret; -} - -/* Copies ecc_key into new WOLFSSL_EC_KEY object - * - * Copies the internal representation as well. - * - * @param [in] src EC key to duplicate. - * - * @return EC key on success. - * @return NULL on error. - */ -WOLFSSL_EC_KEY *wolfSSL_EC_KEY_dup(const WOLFSSL_EC_KEY *src) -{ - int err = 0; - WOLFSSL_EC_KEY* newKey = NULL; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_dup"); - - /* Validate EC key. */ - if ((src == NULL) || (src->internal == NULL) || (src->group == NULL) || - (src->pub_key == NULL) || (src->priv_key == NULL)) { - WOLFSSL_MSG("src NULL error"); - err = 1; - } - - if (!err) { - /* Create a new, empty key. */ - newKey = wolfSSL_EC_KEY_new(); - if (newKey == NULL) { - WOLFSSL_MSG("wolfSSL_EC_KEY_new error"); - err = 1; - } - } - - if (!err) { - /* Copy internal EC key. */ - if (wolfssl_ec_key_int_copy((ecc_key*)newKey->internal, - (ecc_key*)src->internal) != 0) { - WOLFSSL_MSG("Copying internal EC key error"); - err = 1; - } - } - if (!err) { - /* Internal key set. */ - newKey->inSet = 1; - - /* Copy group */ - err = wolfssl_ec_group_copy(newKey->group, src->group); - } - /* Copy public key. */ - if ((!err) && (wolfSSL_EC_POINT_copy(newKey->pub_key, src->pub_key) != 1)) { - WOLFSSL_MSG("Copying EC public key error"); - err = 1; - } - - if (!err) { - /* Set header size of private key in PKCS#8 format.*/ - newKey->pkcs8HeaderSz = src->pkcs8HeaderSz; - - /* Copy private key. */ - if (wolfSSL_BN_copy(newKey->priv_key, src->priv_key) == NULL) { - WOLFSSL_MSG("Copying EC private key error"); - err = 1; - } - } - - if (err) { - /* Dispose of EC key on error. */ - wolfSSL_EC_KEY_free(newKey); - newKey = NULL; - } - /* Return the new EC key. */ - return newKey; -} - -#endif /* OPENSSL_ALL */ - -#endif /* !NO_CERTS */ - -/* - * EC key to/from bin/octet APIs - */ - -/* Create an EC key from the octet encoded public key. - * - * Behaviour checked against OpenSSL. - * - * @param [out] key Reference to EC key. Must pass in a valid object with - * group set. - * @param [in, out] in On in, reference to buffer that contains data. - * On out, reference to buffer after public key data. - * @param [in] len Length of data in the buffer. Must be length of the - * encoded public key. - * @return Allocated EC key on success. - * @return NULL on error. - */ -WOLFSSL_EC_KEY *wolfSSL_o2i_ECPublicKey(WOLFSSL_EC_KEY **key, - const unsigned char **in, long len) -{ - int err = 0; - WOLFSSL_EC_KEY* ret = NULL; - - WOLFSSL_ENTER("wolfSSL_o2i_ECPublicKey"); - - /* Validate parameters: EC group needed to perform import. */ - if ((key == NULL) || (*key == NULL) || ((*key)->group == NULL) || - (in == NULL) || (*in == NULL) || (len <= 0)) { - WOLFSSL_MSG("wolfSSL_o2i_ECPublicKey Bad arguments"); - err = 1; - } - - if (!err) { - /* Return the EC key object passed in. */ - ret = *key; - - /* Import point into public key field. */ - if (wolfSSL_EC_POINT_oct2point(ret->group, ret->pub_key, *in, - (size_t)len, NULL) != 1) { - WOLFSSL_MSG("wolfSSL_EC_POINT_oct2point error"); - ret = NULL; - err = 1; - } - } - if (!err) { - /* Assumed length passed in is all the data. */ - *in += len; - } - - return ret; -} - -/* Puts the encoded public key into out. - * - * Passing in NULL for out returns length only. - * Passing in NULL for *out has buffer allocated, encoded into and passed back. - * Passing non-NULL for *out has it encoded into and pointer moved past. - * - * @param [in] key EC key to encode. - * @param [in, out] out Reference to buffer to encode into. May be NULL or - * point to NULL. - * @return Length of encoding in bytes on success. - * @return 0 on error. - */ -int wolfSSL_i2o_ECPublicKey(const WOLFSSL_EC_KEY *key, unsigned char **out) -{ - int ret = 1; - size_t len = 0; - int form = WC_POINT_CONVERSION_UNCOMPRESSED; - - WOLFSSL_ENTER("wolfSSL_i2o_ECPublicKey"); - - /* Validate parameters. */ - if (key == NULL) { - WOLFSSL_MSG("wolfSSL_i2o_ECPublicKey Bad arguments"); - ret = 0; - } - - /* Ensure the external key data is set from the internal EC key. */ - if ((ret == 1) && (!key->exSet) && (SetECKeyExternal((WOLFSSL_EC_KEY*) - key) != 1)) { - WOLFSSL_MSG("SetECKeyExternal failure"); - ret = 0; - } - - if (ret == 1) { - #ifdef HAVE_COMP_KEY - /* Default to compressed form if not set */ - form = (key->form == WC_POINT_CONVERSION_UNCOMPRESSED) ? - WC_POINT_CONVERSION_UNCOMPRESSED : - WC_POINT_CONVERSION_COMPRESSED; - #endif - - /* Calculate length of point encoding. */ - len = wolfSSL_EC_POINT_point2oct(key->group, key->pub_key, form, NULL, - 0, NULL); - } - /* Encode if length calculated and pointer supplied to update. */ - if ((ret == 1) && (len != 0) && (out != NULL)) { - unsigned char *tmp = NULL; - - /* Allocate buffer for encoding if no buffer supplied. */ - if (*out == NULL) { - tmp = (unsigned char*)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL); - if (tmp == NULL) { - WOLFSSL_MSG("malloc failed"); - ret = 0; - } - } - else { - /* Get buffer to encode into. */ - tmp = *out; - } - - /* Encode public key into buffer. */ - if ((ret == 1) && (wolfSSL_EC_POINT_point2oct(key->group, key->pub_key, - form, tmp, len, NULL) == 0)) { - ret = 0; - } - - if (ret == 1) { - /* Return buffer if allocated. */ - if (*out == NULL) { - *out = tmp; - } - else { - /* Step over encoded data if not allocated. */ - *out += len; - } - } - else if (*out == NULL) { - /* Dispose of allocated buffer. */ - XFREE(tmp, NULL, DYNAMIC_TYPE_OPENSSL); - } - } - - if (ret == 1) { - /* Return length on success. */ - ret = (int)len; - } - return ret; -} - -#ifdef HAVE_ECC_KEY_IMPORT -/* Create a EC key from the DER encoded private key. - * - * @param [out] key Reference to EC key. - * @param [in, out] in On in, reference to buffer that contains DER data. - * On out, reference to buffer after private key data. - * @param [in] long Length of data in the buffer. May be larger than the - * length of the encoded private key. - * @return Allocated EC key on success. - * @return NULL on error. - */ -WOLFSSL_EC_KEY* wolfSSL_d2i_ECPrivateKey(WOLFSSL_EC_KEY** key, - const unsigned char** in, long len) -{ - int err = 0; - word32 idx = 0; - WOLFSSL_EC_KEY* ret = NULL; - - WOLFSSL_ENTER("wolfSSL_d2i_ECPrivateKey"); - - /* Validate parameters. */ - if ((in == NULL) || (*in == NULL) || (len <= 0)) { - WOLFSSL_MSG("wolfSSL_d2i_ECPrivateKey Bad arguments"); - err = 1; - } - - /* Create a new, empty EC key. */ - if ((!err) && ((ret = wolfSSL_EC_KEY_new()) == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_KEY_new error"); - err = 1; - } - - /* Decode the private key DER data into internal EC key. */ - if ((!err) && (wc_EccPrivateKeyDecode(*in, &idx, (ecc_key*)ret->internal, - (word32)len) != 0)) { - WOLFSSL_MSG("wc_EccPrivateKeyDecode error"); - err = 1; - } - - if (!err) { - /* Internal EC key setup. */ - ret->inSet = 1; - - /* Set the EC key from the internal values. */ - if (SetECKeyExternal(ret) != 1) { - WOLFSSL_MSG("SetECKeyExternal error"); - err = 1; - } - } - - if (!err) { - /* Move buffer on to next byte after data used. */ - *in += idx; - if (key) { - /* Return new EC key through reference. */ - *key = ret; - } - } - - if (err && (ret != NULL)) { - /* Dispose of allocated EC key. */ - wolfSSL_EC_KEY_free(ret); - ret = NULL; - } - return ret; -} -#endif /* HAVE_ECC_KEY_IMPORT */ - -/* Enecode the private key of the EC key into the buffer as DER. - * - * @param [in] key EC key to encode. - * @param [in, out] out On in, reference to buffer to place DER encoding into. - * On out, reference to buffer after the encoding. - * May be NULL. - * @return Length of DER encoding on success. - * @return 0 on error. - */ -int wolfSSL_i2d_ECPrivateKey(const WOLFSSL_EC_KEY *key, unsigned char **out) -{ - int err = 0; - word32 len = 0; - - WOLFSSL_ENTER("wolfSSL_i2d_ECPrivateKey"); - - /* Validate parameters. */ - if (key == NULL) { - WOLFSSL_MSG("wolfSSL_i2d_ECPrivateKey Bad arguments"); - err = 1; - } - - /* Update the internal EC key if not set. */ - if ((!err) && (!key->inSet) && (SetECKeyInternal((WOLFSSL_EC_KEY*)key) != - 1)) { - WOLFSSL_MSG("SetECKeyInternal error"); - err = 1; - } - - /* Calculate the length of the private key DER encoding using internal EC - * key. */ - if ((!err) && ((int)(len = (word32)wc_EccKeyDerSize((ecc_key*)key->internal, - 0)) <= 0)) { - WOLFSSL_MSG("wc_EccKeyDerSize error"); - err = 1; - } - - /* Only return length when out is NULL. */ - if ((!err) && (out != NULL)) { - unsigned char* buf = NULL; - - /* Must have a buffer to encode into. */ - if (*out == NULL) { - /* Allocate a new buffer of appropriate length. */ - buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (buf == NULL) { - /* Error and return 0. */ - err = 1; - len = 0; - } - else { - /* Return the allocated buffer. */ - *out = buf; - } - } - /* Encode the internal EC key as a private key in DER format. */ - if ((!err) && wc_EccPrivateKeyToDer((ecc_key*)key->internal, *out, - len) < 0) { - WOLFSSL_MSG("wc_EccPrivateKeyToDer error"); - err = 1; - } - else if (buf != *out) { - /* Move the reference to byte past encoded private key. */ - *out += len; - } - - /* Dispose of any allocated buffer on error. */ - if (err && (*out == buf)) { - XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - *out = NULL; - } - } - - return (int)len; -} - -/* Load private key into EC key from DER encoding. - * - * Not an OpenSSL compatibility API. - * - * @param [in, out] key EC key to put private key values into. - * @param [in] derBuf Buffer holding DER encoding. - * @param [in] derSz Size of DER encoding in bytes. - * @return 1 on success. - * @return -1 on error. - */ -int wolfSSL_EC_KEY_LoadDer(WOLFSSL_EC_KEY* key, const unsigned char* derBuf, - int derSz) -{ - return wolfSSL_EC_KEY_LoadDer_ex(key, derBuf, derSz, - WOLFSSL_EC_KEY_LOAD_PRIVATE); -} - -/* Load private/public key into EC key from DER encoding. - * - * Not an OpenSSL compatibility API. - * - * @param [in, out] key EC key to put private/public key values into. - * @param [in] derBuf Buffer holding DER encoding. - * @param [in] derSz Size of DER encoding in bytes. - * @param [in] opt Key type option. Valid values: - * WOLFSSL_EC_KEY_LOAD_PRIVATE, - * WOLFSSL_EC_KEY_LOAD_PUBLIC. - * @return 1 on success. - * @return -1 on error. - */ -int wolfSSL_EC_KEY_LoadDer_ex(WOLFSSL_EC_KEY* key, const unsigned char* derBuf, - int derSz, int opt) -{ - int res = 1; - int ret; - word32 idx = 0; - word32 algId; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_LoadDer"); - - /* Validate parameters. */ - if ((key == NULL) || (key->internal == NULL) || (derBuf == NULL) || - (derSz <= 0)) { - WOLFSSL_MSG("Bad function arguments"); - res = WOLFSSL_FATAL_ERROR; - } - if ((res == 1) && (opt != WOLFSSL_EC_KEY_LOAD_PRIVATE) && - (opt != WOLFSSL_EC_KEY_LOAD_PUBLIC)) { - res = WOLFSSL_FATAL_ERROR; - } - - if (res == 1) { - /* Assume no PKCS#8 header. */ - key->pkcs8HeaderSz = 0; - - /* Check if input buffer has PKCS8 header. In the case that it does not - * have a PKCS8 header then do not error out. - */ - if ((ret = ToTraditionalInline_ex((const byte*)derBuf, &idx, - (word32)derSz, &algId)) > 0) { - WOLFSSL_MSG("Found PKCS8 header"); - key->pkcs8HeaderSz = (word16)idx; - res = 1; - } - /* Error out on parsing error. */ - else if (ret != WC_NO_ERR_TRACE(ASN_PARSE_E)) { - WOLFSSL_MSG("Unexpected error with trying to remove PKCS8 header"); - res = WOLFSSL_FATAL_ERROR; - } - } - - if (res == 1) { - /* Load into internal EC key based on key type option. */ - if (opt == WOLFSSL_EC_KEY_LOAD_PRIVATE) { - ret = wc_EccPrivateKeyDecode(derBuf, &idx, (ecc_key*)key->internal, - (word32)derSz); - } - else { - ret = wc_EccPublicKeyDecode(derBuf, &idx, (ecc_key*)key->internal, - (word32)derSz); - if (ret < 0) { - ecc_key *tmp = (ecc_key*)XMALLOC(sizeof(ecc_key), - ((ecc_key*)key->internal)->heap, DYNAMIC_TYPE_ECC); - if (tmp == NULL) { - ret = WOLFSSL_FATAL_ERROR; - } - else { - /* We now try again as x.963 [point type][x][opt y]. */ - ret = wc_ecc_init_ex(tmp, ((ecc_key*)key->internal)->heap, - INVALID_DEVID); - if (ret == 0) { - ret = wc_ecc_import_x963(derBuf, (word32)derSz, tmp); - if (ret == 0) { - /* Take ownership of new key - set tmp to the old - * key which will then be freed below. */ - ecc_key *old = (ecc_key *)key->internal; - key->internal = tmp; - tmp = old; - - idx = (word32)derSz; - } - wc_ecc_free(tmp); - } - XFREE(tmp, ((ecc_key*)key->internal)->heap, - DYNAMIC_TYPE_ECC); - } - } - } - if (ret < 0) { - /* Error returned from wolfSSL. */ - if (opt == WOLFSSL_EC_KEY_LOAD_PRIVATE) { - WOLFSSL_MSG("wc_EccPrivateKeyDecode failed"); - } - else { - WOLFSSL_MSG("wc_EccPublicKeyDecode failed"); - } - res = WOLFSSL_FATAL_ERROR; - } - - /* Internal key updated - update whether it is a valid key. */ - key->inSet = (res == 1); - } - - /* Set the external EC key based on value in internal. */ - if ((res == 1) && (SetECKeyExternal(key) != 1)) { - WOLFSSL_MSG("SetECKeyExternal failed"); - res = WOLFSSL_FATAL_ERROR; - } - - return res; -} - - -#ifndef NO_BIO - -WOLFSSL_EC_KEY *wolfSSL_d2i_EC_PUBKEY_bio(WOLFSSL_BIO *bio, - WOLFSSL_EC_KEY **out) -{ - char* data = NULL; - int dataSz = 0; - int memAlloced = 0; - WOLFSSL_EC_KEY* ec = NULL; - int err = 0; - - WOLFSSL_ENTER("wolfSSL_d2i_EC_PUBKEY_bio"); - - if (bio == NULL) - return NULL; - - if (err == 0 && wolfssl_read_bio(bio, &data, &dataSz, &memAlloced) != 0) { - WOLFSSL_ERROR_MSG("wolfssl_read_bio failed"); - err = 1; - } - - if (err == 0 && (ec = wolfSSL_EC_KEY_new()) == NULL) { - WOLFSSL_ERROR_MSG("wolfSSL_EC_KEY_new failed"); - err = 1; - } +#if WOLFSSL_MAX_BN_BITS >= 4096 + static const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF05" + "98DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB" + "9ED529077096966D670C354E4ABC9804" + "F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28F" + "B5C55DF06F4C52C9DE2BCBF695581718" + "3995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33" + "A85521ABDF1CBA64ECFB850458DBEF0A" + "8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619D" + "CEE3D2261AD2EE6BF12FFA06D98A0864" + "D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E2" + "08E24FA074E5AB3143DB5BFCE0FD108E" + "4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C" + "1A946834B6150BDA2583E9CA2AD44CE8" + "DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2" + "233BA186515BE7ED1F612970CEE2D7AF" + "B81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F" + "4DF435C934063199FFFFFFFFFFFFFFFF" + }; - /* Load the EC key with the public key from the DER encoding. */ - if (err == 0 && wolfSSL_EC_KEY_LoadDer_ex(ec, (const unsigned char*)data, - dataSz, WOLFSSL_EC_KEY_LOAD_PUBLIC) != 1) { - WOLFSSL_ERROR_MSG("wolfSSL_EC_KEY_LoadDer_ex failed"); - err = 1; - } + WOLFSSL_ENTER("wolfSSL_DH_4096_prime"); - if (memAlloced) - XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (err) { /* on error */ - wolfSSL_EC_KEY_free(ec); - ec = NULL; - } - else { /* on success */ - if (out != NULL) - *out = ec; + /* Set prime into BN. Creates a new BN when bn is NULL. */ + if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { + WOLFSSL_ERROR_MSG("Error converting DH 4096 prime to big number"); + bn = NULL; } - return ec; + return bn; +#else + (void)bn; + return NULL; +#endif } -#endif /* !NO_BIO */ - -/* - * EC key PEM APIs - */ - -#ifdef HAVE_ECC_KEY_EXPORT -#if defined(WOLFSSL_KEY_GEN) && (!defined(NO_FILESYSTEM) || !defined(NO_BIO)) -/* Encode the EC public key as DER. +/* Returns a big number with the 6144-bit prime from RFC 3526. * - * @param [in] key EC key to encode. - * @param [out] der Pointer through which buffer is returned. - * @param [in] heap Heap hint. - * @return Size of encoding on success. - * @return 0 on error. - */ -static int wolfssl_ec_key_to_pubkey_der(WOLFSSL_EC_KEY* key, - unsigned char** der, void* heap) -{ - int sz; - unsigned char* buf = NULL; - - (void)heap; - - /* Calculate encoded size to allocate. */ - sz = wc_EccPublicKeyDerSize((ecc_key*)key->internal, 1); - if (sz <= 0) { - WOLFSSL_MSG("wc_EccPublicKeyDerSize failed"); - sz = 0; - } - if (sz > 0) { - /* Allocate memory to hold encoding. */ - buf = (byte*)XMALLOC((size_t)sz, heap, DYNAMIC_TYPE_TMP_BUFFER); - if (buf == NULL) { - WOLFSSL_MSG("malloc failed"); - sz = 0; - } - } - if (sz > 0) { - /* Encode public key to DER using wolfSSL. */ - sz = wc_EccPublicKeyToDer((ecc_key*)key->internal, buf, (word32)sz, 1); - if (sz < 0) { - WOLFSSL_MSG("wc_EccPublicKeyToDer failed"); - sz = 0; - } - } - - /* Return buffer on success. */ - if (sz > 0) { - *der = buf; - } - else { - /* Dispose of any dynamically allocated data not returned. */ - XFREE(buf, heap, DYNAMIC_TYPE_TMP_BUFFER); - } - - return sz; -} -#endif - -#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_KEY_GEN) -/* - * Return code compliant with OpenSSL. + * @param [in, out] bn If not NULL then this BN is set and returned. + * If NULL then a new BN is created, set and returned. * - * @param [in] fp File pointer to write PEM encoding to. - * @param [in] key EC key to encode and write. - * @return 1 on success. - * @return 0 on error. + * @return NULL on failure. + * @return WOLFSSL_BIGNUM with value set to 6144-bit prime on success. */ -int wolfSSL_PEM_write_EC_PUBKEY(XFILE fp, WOLFSSL_EC_KEY* key) +WOLFSSL_BIGNUM* wolfSSL_DH_6144_prime(WOLFSSL_BIGNUM* bn) { - int ret = 1; - unsigned char* derBuf = NULL; - int derSz = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_write_EC_PUBKEY"); - - /* Validate parameters. */ - if ((fp == XBADFILE) || (key == NULL)) { - WOLFSSL_MSG("Bad argument."); - return 0; - } +#if WOLFSSL_MAX_BN_BITS >= 6144 + static const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF05" + "98DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB" + "9ED529077096966D670C354E4ABC9804" + "F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28F" + "B5C55DF06F4C52C9DE2BCBF695581718" + "3995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33" + "A85521ABDF1CBA64ECFB850458DBEF0A" + "8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619D" + "CEE3D2261AD2EE6BF12FFA06D98A0864" + "D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E2" + "08E24FA074E5AB3143DB5BFCE0FD108E" + "4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C" + "1A946834B6150BDA2583E9CA2AD44CE8" + "DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2" + "233BA186515BE7ED1F612970CEE2D7AF" + "B81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F" + "4DF435C93402849236C3FAB4D27C7026" + "C1D4DCB2602646DEC9751E763DBA37BD" + "F8FF9406AD9E530EE5DB382F413001AE" + "B06A53ED9027D831179727B0865A8918" + "DA3EDBEBCF9B14ED44CE6CBACED4BB1B" + "DB7F1447E6CC254B332051512BD7AF42" + "6FB8F401378CD2BF5983CA01C64B92EC" + "F032EA15D1721D03F482D7CE6E74FEF6" + "D55E702F46980C82B5A84031900B1C9E" + "59E7C97FBEC7E8F323A97A7E36CC88BE" + "0F1D45B7FF585AC54BD407B22B4154AA" + "CC8F6D7EBF48E1D814CC5ED20F8037E0" + "A79715EEF29BE32806A1D58BB7C5DA76" + "F550AA3D8A1FBFF0EB19CCB1A313D55C" + "DA56C9EC2EF29632387FE8D76E3C0468" + "043E8F663F4860EE12BF2D5B0B7474D6" + "E694F91E6DCC4024FFFFFFFFFFFFFFFF" + }; - /* Encode public key in EC key as DER. */ - derSz = wolfssl_ec_key_to_pubkey_der(key, &derBuf, key->heap); - if (derSz == 0) { - ret = 0; - } + WOLFSSL_ENTER("wolfSSL_DH_6144_prime"); - /* Write out to file the PEM encoding of the DER. */ - if ((ret == 1) && (der_write_to_file_as_pem(derBuf, derSz, fp, - ECC_PUBLICKEY_TYPE, key->heap) != 1)) { - ret = 0; + /* Set prime into BN. Creates a new BN when bn is NULL. */ + if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { + WOLFSSL_ERROR_MSG("Error converting DH 6144 prime to big number"); + bn = NULL; } - /* Dispose of any dynamically allocated data. */ - XFREE(derBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER); - - WOLFSSL_LEAVE("wolfSSL_PEM_write_EC_PUBKEY", ret); - - return ret; -} -#endif + return bn; +#else + (void)bn; + return NULL; #endif +} -#ifndef NO_BIO -/* Read a PEM encoded EC public key from a BIO. + +/* Returns a big number with the 8192-bit prime from RFC 3526. + * + * @param [in, out] bn If not NULL then this BN is set and returned. + * If NULL then a new BN is created, set and returned. * - * @param [in] bio BIO to read EC public key from. - * @param [out] out Pointer to return EC key object through. May be NULL. - * @param [in] cb Password callback when PEM encrypted. - * @param [in] pass NUL terminated string for passphrase when PEM - * encrypted. - * @return New EC key object on success. - * @return NULL on error. + * @return NULL on failure. + * @return WOLFSSL_BIGNUM with value set to 8192-bit prime on success. */ -WOLFSSL_EC_KEY* wolfSSL_PEM_read_bio_EC_PUBKEY(WOLFSSL_BIO* bio, - WOLFSSL_EC_KEY** out, wc_pem_password_cb* cb, void *pass) +WOLFSSL_BIGNUM* wolfSSL_DH_8192_prime(WOLFSSL_BIGNUM* bn) { - int err = 0; - WOLFSSL_EC_KEY* ec = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; +#if WOLFSSL_MAX_BN_BITS >= 8192 + static const char prm[] = { + "FFFFFFFFFFFFFFFFC90FDAA22168C234" + "C4C6628B80DC1CD129024E088A67CC74" + "020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F1437" + "4FE1356D6D51C245E485B576625E7EC6" + "F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF05" + "98DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB" + "9ED529077096966D670C354E4ABC9804" + "F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28F" + "B5C55DF06F4C52C9DE2BCBF695581718" + "3995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33" + "A85521ABDF1CBA64ECFB850458DBEF0A" + "8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619D" + "CEE3D2261AD2EE6BF12FFA06D98A0864" + "D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E2" + "08E24FA074E5AB3143DB5BFCE0FD108E" + "4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C" + "1A946834B6150BDA2583E9CA2AD44CE8" + "DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2" + "233BA186515BE7ED1F612970CEE2D7AF" + "B81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F" + "4DF435C93402849236C3FAB4D27C7026" + "C1D4DCB2602646DEC9751E763DBA37BD" + "F8FF9406AD9E530EE5DB382F413001AE" + "B06A53ED9027D831179727B0865A8918" + "DA3EDBEBCF9B14ED44CE6CBACED4BB1B" + "DB7F1447E6CC254B332051512BD7AF42" + "6FB8F401378CD2BF5983CA01C64B92EC" + "F032EA15D1721D03F482D7CE6E74FEF6" + "D55E702F46980C82B5A84031900B1C9E" + "59E7C97FBEC7E8F323A97A7E36CC88BE" + "0F1D45B7FF585AC54BD407B22B4154AA" + "CC8F6D7EBF48E1D814CC5ED20F8037E0" + "A79715EEF29BE32806A1D58BB7C5DA76" + "F550AA3D8A1FBFF0EB19CCB1A313D55C" + "DA56C9EC2EF29632387FE8D76E3C0468" + "043E8F663F4860EE12BF2D5B0B7474D6" + "E694F91E6DBE115974A3926F12FEE5E4" + "38777CB6A932DF8CD8BEC4D073B931BA" + "3BC832B68D9DD300741FA7BF8AFC47ED" + "2576F6936BA424663AAB639C5AE4F568" + "3423B4742BF1C978238F16CBE39D652D" + "E3FDB8BEFC848AD922222E04A4037C07" + "13EB57A81A23F0C73473FC646CEA306B" + "4BCBC8862F8385DDFA9D4B7FA2C087E8" + "79683303ED5BDD3A062B3CF5B3A278A6" + "6D2A13F83F44F82DDF310EE074AB6A36" + "4597E899A0255DC164F31CC50846851D" + "F9AB48195DED7EA1B1D510BD7EE74D73" + "FAF36BC31ECFA268359046F4EB879F92" + "4009438B481C6CD7889A002ED5EE382B" + "C9190DA6FC026E479558E4475677E9AA" + "9E3050E2765694DFC81F56E880B96E71" + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF" + }; - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_EC_PUBKEY"); + WOLFSSL_ENTER("wolfSSL_DH_8192_prime"); - /* Validate parameters. */ - if (bio == NULL) { - err = 1; + /* Set prime into BN. Creates a new BN when bn is NULL. */ + if (wolfSSL_BN_hex2bn(&bn, prm) != 1) { + WOLFSSL_ERROR_MSG("Error converting DH 8192 prime to big number"); + bn = NULL; } - if (!err) { - /* Create an empty EC key. */ - ec = wolfSSL_EC_KEY_new(); - if (ec == NULL) { - err = 1; - } - } - /* Read a PEM key in to a new DER buffer. */ - if ((!err) && (pem_read_bio_key(bio, cb, pass, ECC_PUBLICKEY_TYPE, - &keyFormat, &der) <= 0)) { - err = 1; - } - /* Load the EC key with the public key from the DER encoding. */ - if ((!err) && (wolfSSL_EC_KEY_LoadDer_ex(ec, der->buffer, (int)der->length, - WOLFSSL_EC_KEY_LOAD_PUBLIC) != 1)) { - WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_EC_KEY"); - err = 1; - } + return bn; +#else + (void)bn; + return NULL; +#endif +} - /* Dispose of dynamically allocated data not needed anymore. */ - FreeDer(&der); - if (err) { - wolfSSL_EC_KEY_free(ec); - ec = NULL; - } +/* + * DH to/from bin APIs + */ - /* Return EC key through out if required. */ - if ((out != NULL) && (ec != NULL)) { - *out = ec; - } - return ec; -} +#ifndef NO_CERTS -/* Read a PEM encoded EC private key from a BIO. +/* Load the DER encoded DH parameters into DH key. + * + * @param [in, out] dh DH key to load parameters into. + * @param [in] der Buffer holding DER encoded parameters data. + * @param [in, out] idx On in, index at which DH key DER data starts. + * On out, index after DH key DER data. + * @param [in] derSz Size of DER buffer in bytes. * - * @param [in] bio BIO to read EC private key from. - * @param [out] out Pointer to return EC key object through. May be NULL. - * @param [in] cb Password callback when PEM encrypted. - * @param [in] pass NUL terminated string for passphrase when PEM - * encrypted. - * @return New EC key object on success. - * @return NULL on error. + * @return 0 on success. + * @return 1 when decoding DER or setting the external key fails. */ -WOLFSSL_EC_KEY* wolfSSL_PEM_read_bio_ECPrivateKey(WOLFSSL_BIO* bio, - WOLFSSL_EC_KEY** out, wc_pem_password_cb* cb, void *pass) +static int wolfssl_dh_load_params(WOLFSSL_DH* dh, const unsigned char* der, + word32* idx, word32 derSz) { - int err = 0; - WOLFSSL_EC_KEY* ec = NULL; - DerBuffer* der = NULL; - int keyFormat = 0; + int err = 0; - WOLFSSL_ENTER("wolfSSL_PEM_read_bio_ECPrivateKey"); +#if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) + int ret; - /* Validate parameters. */ - if (bio == NULL) { + /* Decode DH parameters/key from DER. */ + ret = wc_DhKeyDecode(der, idx, (DhKey*)dh->internal, derSz); + if (ret != 0) { + WOLFSSL_ERROR_MSG("DhKeyDecode() failed"); err = 1; } - if (!err) { - /* Create an empty EC key. */ - ec = wolfSSL_EC_KEY_new(); - if (ec == NULL) { + /* wolfSSL DH key set. */ + dh->inSet = 1; + + /* Set the external DH key based on wolfSSL DH key. */ + if (SetDhExternal(dh) != 1) { + WOLFSSL_ERROR_MSG("SetDhExternal failed"); err = 1; } } - /* Read a PEM key in to a new DER buffer. - * To check ENC EC PRIVATE KEY, it uses PRIVATEKEY_TYPE to call - * pem_read_bio_key(), and then check key format if it is EC. - */ - if ((!err) && (pem_read_bio_key(bio, cb, pass, PRIVATEKEY_TYPE, - &keyFormat, &der) <= 0)) { - err = 1; - } - if (keyFormat != ECDSAk) { - WOLFSSL_ERROR_MSG("Error not EC key format"); +#else + byte* p; + byte* g; + word32 pSz = MAX_DH_SIZE; + word32 gSz = MAX_DH_SIZE; + + /* Only DH parameters supported. */ + /* Load external and set internal. */ + p = (byte*)XMALLOC(pSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + g = (byte*)XMALLOC(gSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + if ((p == NULL) || (g == NULL)) { err = 1; } - /* Load the EC key with the private key from the DER encoding. */ - if ((!err) && (wolfSSL_EC_KEY_LoadDer_ex(ec, der->buffer, (int)der->length, - WOLFSSL_EC_KEY_LOAD_PRIVATE) != 1)) { - WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_EC_KEY"); + /* Extract the p and g as data from the DER encoded DH parameters. */ + if ((!err) && (wc_DhParamsLoad(der + *idx, derSz - *idx, p, &pSz, g, + &gSz) < 0)) { err = 1; } - - /* Dispose of dynamically allocated data not needed anymore. */ - FreeDer(&der); - if (err) { - wolfSSL_EC_KEY_free(ec); - ec = NULL; - } - - /* Return EC key through out if required. */ - if ((out != NULL) && (ec != NULL)) { - *out = ec; - } - return ec; -} -#endif /* !NO_BIO */ - -#if defined(WOLFSSL_KEY_GEN) && defined(HAVE_ECC_KEY_EXPORT) -#ifndef NO_BIO -/* Write out the EC public key as PEM to the BIO. - * - * @param [in] bio BIO to write PEM encoding to. - * @param [in] ec EC public key to encode. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_PEM_write_bio_EC_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_EC_KEY* ec) -{ - int ret = 1; - unsigned char* derBuf = NULL; - int derSz = 0; - - WOLFSSL_ENTER("wolfSSL_PEM_write_bio_EC_PUBKEY"); - - /* Validate parameters. */ - if ((bio == NULL) || (ec == NULL)) { - WOLFSSL_MSG("Bad Function Arguments"); - return 0; - } - - /* Encode public key in EC key as DER. */ - derSz = wolfssl_ec_key_to_pubkey_der(ec, &derBuf, ec->heap); - if (derSz == 0) { - ret = 0; - } - - /* Write out to BIO the PEM encoding of the EC public key. */ - if ((ret == 1) && (der_write_to_bio_as_pem(derBuf, derSz, bio, - ECC_PUBLICKEY_TYPE) != 1)) { - ret = 0; + if (!err) { + /* Put p and g in as big numbers - free existing BNs. */ + if (dh->p != NULL) { + wolfSSL_BN_free(dh->p); + dh->p = NULL; + } + if (dh->g != NULL) { + wolfSSL_BN_free(dh->g); + dh->g = NULL; + } + dh->p = wolfSSL_BN_bin2bn(p, (int)pSz, NULL); + dh->g = wolfSSL_BN_bin2bn(g, (int)gSz, NULL); + if (dh->p == NULL || dh->g == NULL) { + err = 1; + } + else { + /* External DH key parameters were set. */ + dh->exSet = 1; + } } - /* Dispose of any dynamically allocated data. */ - XFREE(derBuf, ec->heap, DYNAMIC_TYPE_TMP_BUFFER); - - return ret; -} - -/* Write out the EC private key as PEM to the BIO. - * - * Return code compliant with OpenSSL. - * - * @param [in] bio BIO to write PEM encoding to. - * @param [in] ec EC private key to encode. - * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. - * @param [in] passwd Password string when PEM encrypted. May be NULL. - * @param [in] passwdSz Length of password string when PEM encrypted. - * @param [in] cb Password callback when PEM encrypted. Unused. - * @param [in] pass NUL terminated string for passphrase when PEM - * encrypted. Unused. - * @return 1 on success. - * @return 0 on error. - */ -int wolfSSL_PEM_write_bio_ECPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EC_KEY* ec, - const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, - wc_pem_password_cb* cb, void* arg) -{ - int ret = 1; - unsigned char* pem = NULL; - int pLen = 0; - - (void)cb; - (void)arg; - - /* Validate parameters. */ - if ((bio == NULL) || (ec == NULL)) { - ret = 0; + /* Set internal as the outside has been updated. */ + if ((!err) && (SetDhInternal(dh) != 1)) { + WOLFSSL_ERROR_MSG("Unable to set internal DH structure"); + err = 1; } - /* Write EC private key to PEM. */ - if ((ret == 1) && (wolfSSL_PEM_write_mem_ECPrivateKey(ec, cipher, passwd, - passwdSz, &pem, &pLen) != 1)) { - ret = 0; - } - /* Write PEM to BIO. */ - if ((ret == 1) && (wolfSSL_BIO_write(bio, pem, pLen) != pLen)) { - WOLFSSL_ERROR_MSG("EC private key BIO write failed"); - ret = 0; + if (!err) { + *idx += wolfssl_der_length(der + *idx, derSz - *idx); } - XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + XFREE(p, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(g, NULL, DYNAMIC_TYPE_PUBLIC_KEY); +#endif - return ret; + return err; } -#endif /* !NO_BIO */ +#ifdef OPENSSL_ALL -/* Encode the EC private key as PEM into buffer. +#if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) +/* Convert DER encoded DH parameters to a WOLFSSL_DH structure. * - * Return code compliant with OpenSSL. - * Not an OpenSSL API. + * @param [out] dh DH key to put parameters into. May be NULL. + * @param [in, out] pp Pointer to DER encoded DH parameters. + * Value updated to end of data when dh is not NULL. + * @param [in] length Length of data available in bytes. * - * @param [in] ec EC private key to encode. - * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. - * @param [in] passwd Password string when PEM encrypted. May be NULL. - * @param [in] passwdSz Length of password string when PEM encrypted. - * @param [out] pem Newly allocated buffer holding PEM encoding. - * @param [out] pLen Length of PEM encoding in bytes. - * @return 1 on success. - * @return 0 on error. + * @return DH key on success. + * @return NULL on failure. */ -int wolfSSL_PEM_write_mem_ECPrivateKey(WOLFSSL_EC_KEY* ec, - const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, - unsigned char **pem, int *pLen) +WOLFSSL_DH *wolfSSL_d2i_DHparams(WOLFSSL_DH** dh, const unsigned char** pp, + long length) { -#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM) - int ret = 1; - byte* derBuf = NULL; - word32 der_max_len = 0; - int derSz = 0; + WOLFSSL_DH *newDh = NULL; + word32 idx = 0; + int err = 0; - WOLFSSL_MSG("wolfSSL_PEM_write_mem_ECPrivateKey"); + WOLFSSL_ENTER("wolfSSL_d2i_DHparams"); /* Validate parameters. */ - if ((pem == NULL) || (pLen == NULL) || (ec == NULL) || - (ec->internal == NULL)) { - WOLFSSL_MSG("Bad function arguments"); - ret = 0; + if ((pp == NULL) || (length <= 0)) { + WOLFSSL_ERROR_MSG("bad argument"); + err = 1; } - /* Ensure internal EC key is set from external. */ - if ((ret == 1) && (ec->inSet == 0)) { - WOLFSSL_MSG("No ECC internal set, do it"); - - if (SetECKeyInternal(ec) != 1) { - WOLFSSL_MSG("SetECKeyInternal failed"); - ret = 0; - } + /* Create new DH key to return. */ + if ((!err) && ((newDh = wolfSSL_DH_new()) == NULL)) { + WOLFSSL_ERROR_MSG("wolfSSL_DH_new() failed"); + err = 1; } - - if (ret == 1) { - /* Calculate maximum size of DER encoding. - * 4 > size of pub, priv + ASN.1 additional information */ - der_max_len = 4 * (word32)wc_ecc_size((ecc_key*)ec->internal) + - WC_AES_BLOCK_SIZE; - - /* Allocate buffer big enough to hold encoding. */ - derBuf = (byte*)XMALLOC((size_t)der_max_len, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (derBuf == NULL) { - WOLFSSL_MSG("malloc failed"); - ret = 0; - } + if ((!err) && (wolfssl_dh_load_params(newDh, *pp, &idx, + (word32)length) != 0)) { + WOLFSSL_ERROR_MSG("Loading DH parameters failed"); + err = 1; } - if (ret == 1) { - /* Encode EC private key as DER. */ - derSz = wc_EccKeyToDer((ecc_key*)ec->internal, derBuf, der_max_len); - if (derSz < 0) { - WOLFSSL_MSG("wc_EccKeyToDer failed"); - XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); - ret = 0; - } + if ((!err) && (dh != NULL)) { + /* Return through parameter too. */ + *dh = newDh; + /* Move buffer on by the used amount. */ + *pp += idx; } - /* Convert DER to PEM - possibly encrypting. */ - if ((ret == 1) && (der_to_enc_pem_alloc(derBuf, derSz, cipher, passwd, - passwdSz, ECC_PRIVATEKEY_TYPE, NULL, pem, pLen) != 1)) { - WOLFSSL_ERROR_MSG("der_to_enc_pem_alloc failed"); - ret = 0; + if (err && (newDh != NULL)) { + /* Dispose of any created DH key. */ + wolfSSL_DH_free(newDh); + newDh = NULL; } - - return ret; -#else - (void)ec; - (void)cipher; - (void)passwd; - (void)passwdSz; - (void)pem; - (void)pLen; - return 0; -#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ + return newDh; } +#endif /* !HAVE_FIPS || FIPS_VERSION_GT(2,0) */ -#ifndef NO_FILESYSTEM -/* Write out the EC private key as PEM to file. - * - * Return code compliant with OpenSSL. +/* Converts internal WOLFSSL_DH structure to DER encoded DH parameters. * - * @param [in] fp File pointer to write PEM encoding to. - * @param [in] ec EC private key to encode. - * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. - * @param [in] passwd Password string when PEM encrypted. May be NULL. - * @param [in] passwdSz Length of password string when PEM encrypted. - * @param [in] cb Password callback when PEM encrypted. Unused. - * @param [in] pass NUL terminated string for passphrase when PEM - * encrypted. Unused. - * @return 1 on success. + * @params [in] dh DH key with parameters to encode. + * @params [in, out] out Pointer to buffer to encode into. + * When NULL or pointer to NULL, only length returned. * @return 0 on error. + * @return Size of DER encoding in bytes on success. */ -int wolfSSL_PEM_write_ECPrivateKey(XFILE fp, WOLFSSL_EC_KEY *ec, - const WOLFSSL_EVP_CIPHER *cipher, unsigned char *passwd, int passwdSz, - wc_pem_password_cb *cb, void *pass) +int wolfSSL_i2d_DHparams(const WOLFSSL_DH *dh, unsigned char **out) { - int ret = 1; - byte *pem = NULL; - int pLen = 0; +#if (!defined(HAVE_FIPS) || FIPS_VERSION_GT(5,0)) && defined(WOLFSSL_DH_EXTRA) + /* Set length to an arbitrarily large value for wc_DhParamsToDer(). */ + word32 len = (word32)-1; + int err = 0; - (void)cb; - (void)pass; + /* Validate parameters. */ + if (dh == NULL) { + WOLFSSL_ERROR_MSG("Bad parameters"); + err = 1; + } - WOLFSSL_MSG("wolfSSL_PEM_write_ECPrivateKey"); + /* Push external DH data into internal DH key if not set. */ + if ((!err) && (!dh->inSet) && (SetDhInternal((WOLFSSL_DH*)dh) != 1)) { + WOLFSSL_ERROR_MSG("Bad DH set internal"); + err = 1; + } + if (!err) { + int ret; + unsigned char* der = NULL; - /* Validate parameters. */ - if ((fp == XBADFILE) || (ec == NULL) || (ec->internal == NULL)) { - WOLFSSL_MSG("Bad function arguments"); - ret = 0; + /* Use *out when available otherwise NULL. */ + if (out != NULL) { + der = *out; + } + /* Get length and/or encode. */ + ret = wc_DhParamsToDer((DhKey*)dh->internal, der, &len); + /* Length of encoded data is returned on success. */ + if (ret > 0) { + *out += len; + } + /* An error occurred unless only length returned. */ + else if (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { + err = 1; + } } - /* Write EC private key to PEM. */ - if ((ret == 1) && (wolfSSL_PEM_write_mem_ECPrivateKey(ec, cipher, passwd, - passwdSz, &pem, &pLen) != 1)) { - WOLFSSL_MSG("wolfSSL_PEM_write_mem_ECPrivateKey failed"); - ret = 0; + /* Set return to 0 on error. */ + if (err) { + len = 0; } + return (int)len; +#else + word32 len; + int ret = 0; + int pSz; + int gSz; - /* Write out to file the PEM encoding of the EC private key. */ - if ((ret == 1) && ((int)XFWRITE(pem, 1, (size_t)pLen, fp) != pLen)) { - WOLFSSL_MSG("ECC private key file write failed"); - ret = 0; + WOLFSSL_ENTER("wolfSSL_i2d_DHparams"); + + /* Validate parameters. */ + if (dh == NULL) { + WOLFSSL_ERROR_MSG("Bad parameters"); + len = 0; } + else { + /* SEQ + * INT [0x00] + * INT [0x00] + * Integers have 0x00 prepended if the top bit of positive number is + * set. + */ + /* Get total length of prime including any prepended zeros. */ + pSz = mp_unsigned_bin_size((mp_int*)dh->p->internal) + + mp_leading_bit((mp_int*)dh->p->internal); + /* Get total length of generator including any prepended zeros. */ + gSz = mp_unsigned_bin_size((mp_int*)dh->g->internal) + + mp_leading_bit((mp_int*)dh->g->internal); + /* Calculate length of data in sequence. */ + len = 1 + ASN_LEN_SIZE(pSz) + pSz + + 1 + ASN_LEN_SIZE(gSz) + gSz; + /* Add in the length of the SEQUENCE. */ + len += 1 + ASN_LEN_SIZE(len); - /* Dispose of any dynamically allocated data. */ - XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + if ((out != NULL) && (*out != NULL)) { + /* Encode parameters. */ + ret = StoreDHparams(*out, &len, (mp_int*)dh->p->internal, + (mp_int*)dh->g->internal); + if (ret != MP_OKAY) { + WOLFSSL_ERROR_MSG("StoreDHparams error"); + len = 0; + } + else { + /* Move pointer on if encoded. */ + *out += len; + } + } + } - return ret; + return (int)len; +#endif } -#endif /* NO_FILESYSTEM */ -#endif /* WOLFSSL_KEY_GEN && HAVE_ECC_KEY_EXPORT */ +#endif /* OPENSSL_ALL */ -/* - * EC key print APIs - */ +#endif /* !NO_CERTS */ -#ifndef NO_CERTS +#endif /* OPENSSL_EXTRA */ -#if defined(XFPRINTF) && !defined(NO_FILESYSTEM) && \ - !defined(NO_STDIO_FILESYSTEM) -/* Print the EC key to a file pointer as text. +#if defined(OPENSSL_EXTRA) || \ + ((!defined(NO_BIO) || !defined(NO_FILESYSTEM)) && \ + defined(HAVE_LIGHTY) || defined(HAVE_STUNNEL) || \ + defined(WOLFSSL_MYSQL_COMPATIBLE)) + +/* Load the DER encoded DH parameters into DH key. + * + * @param [in, out] dh DH key to load parameters into. + * @param [in] derBuf Buffer holding DER encoded parameters data. + * @param [in] derSz Size of DER data in buffer in bytes. * - * @param [in] fp File pointer. - * @param [in] key EC key to print. - * @param [in] indent Number of spaces to place before each line printed. * @return 1 on success. - * @return 0 on failure. + * @return -1 when DH or derBuf is NULL, + * internal DH key in DH is NULL, + * derSz is 0 or less, + * error decoding DER data or + * setting external parameter values fails. */ -int wolfSSL_EC_KEY_print_fp(XFILE fp, WOLFSSL_EC_KEY* key, int indent) +int wolfSSL_DH_LoadDer(WOLFSSL_DH* dh, const unsigned char* derBuf, int derSz) { - int ret = 1; - int bits = 0; - int priv = 0; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_print_fp"); + int ret = 1; + word32 idx = 0; /* Validate parameters. */ - if ((fp == XBADFILE) || (key == NULL) || (key->group == NULL) || - (indent < 0)) { - ret = 0; - } - - if (ret == 1) { - /* Get EC groups order size in bits. */ - bits = wolfSSL_EC_GROUP_order_bits(key->group); - if (bits <= 0) { - WOLFSSL_MSG("Failed to get group order bits."); - ret = 0; - } - } - if (ret == 1) { - const char* keyType; - - /* Determine whether this is a private or public key. */ - if ((key->priv_key != NULL) && (!wolfSSL_BN_is_zero(key->priv_key))) { - keyType = "Private-Key"; - priv = 1; - } - else { - keyType = "Public-Key"; - } - - /* Print key header. */ - if (XFPRINTF(fp, "%*s%s: (%d bit)\n", indent, "", keyType, bits) < 0) { - ret = 0; - } - } - if ((ret == 1) && priv) { - /* Print the private key BN. */ - ret = pk_bn_field_print_fp(fp, indent, "priv", key->priv_key); - } - /* Check for public key data in EC key. */ - if ((ret == 1) && (key->pub_key != NULL) && (key->pub_key->exSet)) { - /* Get the public key point as one BN. */ - WOLFSSL_BIGNUM* pubBn = wolfSSL_EC_POINT_point2bn(key->group, - key->pub_key, WC_POINT_CONVERSION_UNCOMPRESSED, NULL, NULL); - if (pubBn == NULL) { - WOLFSSL_MSG("wolfSSL_EC_POINT_point2bn failed."); - ret = 0; - } - else { - /* Print the public key in a BN. */ - ret = pk_bn_field_print_fp(fp, indent, "pub", pubBn); - wolfSSL_BN_free(pubBn); - } - } - if (ret == 1) { - /* Get the NID of the group. */ - int nid = wolfSSL_EC_GROUP_get_curve_name(key->group); - if (nid > 0) { - /* Convert the NID into a long name and NIST name. */ - const char* curve = wolfSSL_OBJ_nid2ln(nid); - const char* nistName = wolfSSL_EC_curve_nid2nist(nid); - - /* Print OID name if known. */ - if ((curve != NULL) && - (XFPRINTF(fp, "%*sASN1 OID: %s\n", indent, "", curve) < 0)) { - ret = 0; - } - /* Print NIST curve name if known. */ - if ((nistName != NULL) && - (XFPRINTF(fp, "%*sNIST CURVE: %s\n", indent, "", - nistName) < 0)) { - ret = 0; - } - } + if ((dh == NULL) || (dh->internal == NULL) || (derBuf == NULL) || + (derSz <= 0)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = WOLFSSL_FATAL_ERROR; } - - WOLFSSL_LEAVE("wolfSSL_EC_KEY_print_fp", ret); + if ((ret == 1) && (wolfssl_dh_load_params(dh, derBuf, &idx, + (word32)derSz) != 0)) { + WOLFSSL_ERROR_MSG("DH key decode failed"); + ret = WOLFSSL_FATAL_ERROR; + } return ret; } -#endif /* XFPRINTF && !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM */ -#endif /* !NO_CERTS */ +#endif /* - * EC_KEY get/set/test APIs + * DH PEM APIs */ -/* Set data of internal, wolfCrypt EC key object into EC key. - * - * EC_KEY wolfSSL -> OpenSSL +#if defined(HAVE_LIGHTY) || defined(HAVE_STUNNEL) \ + || defined(WOLFSSL_MYSQL_COMPATIBLE) || defined(OPENSSL_EXTRA) + +#if !defined(NO_BIO) || !defined(NO_FILESYSTEM) +/* Create a DH key by reading the PEM encoded data from the BIO. * - * @param [in, out] p EC key to update. - * @return 1 on success. - * @return -1 on failure. + * @param [in] bio BIO object to read from. + * @param [in, out] dh DH key to use. May be NULL. + * @param [in] pem PEM data to decode. + * @param [in] pemSz Size of PEM data in bytes. + * @param [in] memAlloced Indicates that pem was allocated and is to be + * freed after use. + * @return DH key on success. + * @return NULL on failure. */ -int SetECKeyExternal(WOLFSSL_EC_KEY* eckey) +static WOLFSSL_DH *wolfssl_dhparams_read_pem(WOLFSSL_DH **dh, + unsigned char* pem, int pemSz, int memAlloced) { - int ret = 1; - - WOLFSSL_ENTER("SetECKeyExternal"); + WOLFSSL_DH* localDh = NULL; + DerBuffer *der = NULL; + int err = 0; - /* Validate parameter. */ - if ((eckey == NULL) || (eckey->internal == NULL)) { - WOLFSSL_MSG("ec key NULL error"); - ret = WOLFSSL_FATAL_ERROR; + /* Convert PEM to DER assuming DH Parameter format. */ + if ((!err) && (PemToDer(pem, pemSz, DH_PARAM_TYPE, &der, NULL, NULL, + NULL) < 0)) { + /* Convert PEM to DER assuming X9.42 DH Parameter format. */ + if (PemToDer(pem, pemSz, X942_PARAM_TYPE, &der, NULL, NULL, NULL) + != 0) { + err = 1; + } + /* If Success on X9.42 DH format, clear error from failed DH format */ + else { + unsigned long error; + CLEAR_ASN_NO_PEM_HEADER_ERROR(error); + } + } + if (memAlloced) { + /* PEM data no longer needed. */ + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); } - else { - ecc_key* key = (ecc_key*)eckey->internal; - - /* Set group (OID, nid and idx) from wolfCrypt EC key. */ - eckey->group->curve_oid = (int)key->dp->oidSum; - eckey->group->curve_nid = EccEnumToNID(key->dp->id); - eckey->group->curve_idx = key->idx; - - if (eckey->pub_key->internal != NULL) { - /* Copy internal public point from internal key's public point. */ - if (wc_ecc_copy_point(&key->pubkey, - (ecc_point*)eckey->pub_key->internal) != MP_OKAY) { - WOLFSSL_MSG("SetECKeyExternal ecc_copy_point failed"); - ret = WOLFSSL_FATAL_ERROR; - } - /* Set external public key from internal wolfCrypt, public key. */ - if ((ret == 1) && (ec_point_external_set(eckey->pub_key) != 1)) { - WOLFSSL_MSG("SetECKeyExternal ec_point_external_set failed"); - ret = WOLFSSL_FATAL_ERROR; + if (!err) { + /* Use the DH key passed in or allocate a new one. */ + if (dh != NULL) { + localDh = *dh; + } + if (localDh == NULL) { + localDh = wolfSSL_DH_new(); + if (localDh == NULL) { + err = 1; } } - - /* set the external privkey */ - if ((ret == 1) && (key->type == ECC_PRIVATEKEY) && - (wolfssl_bn_set_value(&eckey->priv_key, - wc_ecc_key_get_priv(key)) != 1)) { - WOLFSSL_MSG("ec priv key error"); - ret = WOLFSSL_FATAL_ERROR; + } + /* Load the DER encoded DH parameters from buffer into a DH key. */ + if ((!err) && (wolfSSL_DH_LoadDer(localDh, der->buffer, (int)der->length) + != 1)) { + /* Free an allocated DH key. */ + if ((dh == NULL) || (localDh != *dh)) { + wolfSSL_DH_free(localDh); } - - /* External values set when operations succeeded. */ - eckey->exSet = (ret == 1); + localDh = NULL; + err = 1; + } + /* Return the DH key on success. */ + if ((!err) && (dh != NULL)) { + *dh = localDh; } - return ret; + /* Dispose of DER data. */ + if (der != NULL) { + FreeDer(&der); + } + return localDh; } +#endif /* !NO_BIO || !NO_FILESYSTEM */ -/* Set data of EC key into internal, wolfCrypt EC key object. +#ifndef NO_BIO +/* Create a DH key by reading the PEM encoded data from the BIO. * - * EC_KEY Openssl -> WolfSSL + * DH parameters are public data and are not expected to be encrypted. * - * @param [in, out] p EC key to update. - * @return 1 on success. - * @return -1 on failure. + * @param [in] bio BIO object to read from. + * @param [in, out] dh DH key to When pointer to + * NULL, a new DH key is created. + * @param [in] cb Password callback when PEM encrypted. Not used. + * @param [in] pass NUL terminated string for passphrase when PEM + * encrypted. Not used. + * @return DH key on success. + * @return NULL on failure. */ -int SetECKeyInternal(WOLFSSL_EC_KEY* eckey) +WOLFSSL_DH *wolfSSL_PEM_read_bio_DHparams(WOLFSSL_BIO *bio, WOLFSSL_DH **dh, + wc_pem_password_cb *cb, void *pass) { - int ret = 1; - - WOLFSSL_ENTER("SetECKeyInternal"); - - /* Validate parameter. */ - if ((eckey == NULL) || (eckey->internal == NULL) || - (eckey->group == NULL)) { - WOLFSSL_MSG("ec key NULL error"); - ret = WOLFSSL_FATAL_ERROR; - } - else { - ecc_key* key = (ecc_key*)eckey->internal; - int pubSet = 0; - - /* Validate group. */ - if ((eckey->group->curve_idx < 0) || - (wc_ecc_is_valid_idx(eckey->group->curve_idx) == 0)) { - WOLFSSL_MSG("invalid curve idx"); - ret = WOLFSSL_FATAL_ERROR; - } + WOLFSSL_DH* localDh = NULL; + int err = 0; + unsigned char* mem = NULL; + int size = 0; + int memAlloced = 0; - if (ret == 1) { - /* Set group (idx of curve and corresponding domain parameters). */ - key->idx = eckey->group->curve_idx; - key->dp = &ecc_sets[key->idx]; - pubSet = (eckey->pub_key != NULL); - } - /* Set public key (point). */ - if ((ret == 1) && pubSet) { - if (ec_point_internal_set(eckey->pub_key) != 1) { - WOLFSSL_MSG("ec key pub error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* Copy public point to key. */ - if ((ret == 1) && (wc_ecc_copy_point( - (ecc_point*)eckey->pub_key->internal, &key->pubkey) != - MP_OKAY)) { - WOLFSSL_MSG("wc_ecc_copy_point error"); - ret = WOLFSSL_FATAL_ERROR; - } + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_DHparams"); - if (ret == 1) { - /* Set that the internal key is a public key */ - key->type = ECC_PUBLICKEY; - } - } + (void)cb; + (void)pass; - /* set privkey */ - if ((ret == 1) && (eckey->priv_key != NULL)) { - if (wolfssl_bn_get_value(eckey->priv_key, - wc_ecc_key_get_priv(key)) != 1) { - WOLFSSL_MSG("ec key priv error"); - ret = WOLFSSL_FATAL_ERROR; - } - /* private key */ - if ((ret == 1) && (!mp_iszero(wc_ecc_key_get_priv(key)))) { - if (pubSet) { - key->type = ECC_PRIVATEKEY; - } - else { - key->type = ECC_PRIVATEKEY_ONLY; - } - } - } + /* Validate parameters. */ + if (bio == NULL) { + WOLFSSL_ERROR_MSG("Bad Function Argument bio is NULL"); + err = 1; + } - /* Internal values set when operations succeeded. */ - eckey->inSet = (ret == 1); + /* Get buffer of data from BIO or read data from the BIO into a new buffer. + */ + if ((!err) && (wolfssl_read_bio(bio, (char**)&mem, &size, &memAlloced) + != 0)) { + err = 1; + } + if (!err) { + /* Create a DH key from the PEM - try two different headers. */ + localDh = wolfssl_dhparams_read_pem(dh, mem, size, memAlloced); } - return ret; + return localDh; } -/* Get point conversion format of EC key. - * - * @param [in] key EC key. - * @return Point conversion format on success. - * @return -1 on error. - */ -wc_point_conversion_form_t wolfSSL_EC_KEY_get_conv_form( - const WOLFSSL_EC_KEY* key) -{ - if (key == NULL) - return WOLFSSL_FATAL_ERROR; - return key->form; -} +#endif /* !NO_BIO */ -/* Set point conversion format into EC key. +#ifndef NO_FILESYSTEM +/* Read DH parameters from a file pointer into DH key. + * + * DH parameters are public data and are not expected to be encrypted. + * + * @param [in] fp File pointer to read DH parameter file from. + * @param [in, out] dh DH key with parameters if not NULL. When pointer to + * NULL, a new DH key is created. + * @param [in] cb Password callback when PEM encrypted. Not used. + * @param [in] pass NUL terminated string for passphrase when PEM + * encrypted. Not used. * - * @param [in, out] key EC key to set format into. - * @param [in] form Point conversion format. Valid values: - * WC_POINT_CONVERSION_UNCOMPRESSED, - * WC_POINT_CONVERSION_COMPRESSED (when HAVE_COMP_KEY) + * @return NULL on failure. + * @return DH key with parameters set on success. */ -void wolfSSL_EC_KEY_set_conv_form(WOLFSSL_EC_KEY *key, int form) +WOLFSSL_DH* wolfSSL_PEM_read_DHparams(XFILE fp, WOLFSSL_DH** dh, + wc_pem_password_cb* cb, void* pass) { - if (key == NULL) { - WOLFSSL_MSG("Key passed in NULL"); - } - else if (form == WC_POINT_CONVERSION_UNCOMPRESSED -#ifdef HAVE_COMP_KEY - || form == WC_POINT_CONVERSION_COMPRESSED -#endif - ) { - key->form = (unsigned char)form; + WOLFSSL_DH* localDh = NULL; + int err = 0; + unsigned char* mem = NULL; + int size = 0; + + (void)cb; + (void)pass; + + /* Read data from file pointer. */ + if (wolfssl_read_file(fp, (char**)&mem, &size) != 0) { + err = 1; } - else { - WOLFSSL_MSG("Incorrect form or HAVE_COMP_KEY not compiled in"); + if (!err) { + localDh = wolfssl_dhparams_read_pem(dh, mem, size, 1); } + + return localDh; } +#endif /* !NO_FILESYSTEM */ -/* Get the EC group object that is in EC key. +#if defined(WOLFSSL_DH_EXTRA) && !defined(NO_FILESYSTEM) +/* Encoded parameter data in DH key as DER. * - * @param [in] key EC key. - * @return EC group object on success. - * @return NULL when key is NULL. + * @param [in, out] dh DH key object to encode. + * @param [out] out Buffer containing DER encoding. + * @param [in] heap Heap hint. + * @return <0 on error. + * @return Length of DER encoded DH parameters in bytes. */ -const WOLFSSL_EC_GROUP *wolfSSL_EC_KEY_get0_group(const WOLFSSL_EC_KEY *key) +static int wolfssl_dhparams_to_der(WOLFSSL_DH* dh, unsigned char** out, + void* heap) { - WOLFSSL_EC_GROUP* group = NULL; + int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); + int err = 0; + byte* der = NULL; + word32 derSz = 0; + DhKey* key = NULL; + + (void)heap; + + /* Set internal parameters based on external parameters. */ + if ((dh->inSet == 0) && (SetDhInternal(dh) != 1)) { + WOLFSSL_ERROR_MSG("Unable to set internal DH structure"); + err = 1; + } + if (!err) { + /* Use wolfSSL API to get length of DER encode DH parameters. */ + key = (DhKey*)dh->internal; + ret = wc_DhParamsToDer(key, NULL, &derSz); + if (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { + WOLFSSL_ERROR_MSG("Failed to get size of DH params"); + err = 1; + } + } - WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_group"); + if (!err) { + /* Allocate memory for DER encoding. */ + der = (byte*)XMALLOC(derSz, heap, DYNAMIC_TYPE_TMP_BUFFER); + if (der == NULL) { + WOLFSSL_LEAVE("wolfssl_dhparams_to_der", MEMORY_E); + err = 1; + } + } + if (!err) { + /* Encode DH parameters into DER buffer. */ + ret = wc_DhParamsToDer(key, der, &derSz); + if (ret < 0) { + WOLFSSL_ERROR_MSG("Failed to export DH params"); + err = 1; + } + } - if (key != NULL) { - group = key->group; + if (!err) { + *out = der; + der = NULL; } + XFREE(der, heap, DYNAMIC_TYPE_TMP_BUFFER); - return group; + return ret; } -/* Set the group in WOLFSSL_EC_KEY +/* Writes the DH parameters in PEM format from "dh" out to the file pointer + * passed in. * - * @param [in, out] key EC key to update. - * @param [in] group EC group to copy. - * @return 1 on success + * @param [in] fp File pointer to write to. + * @param [in] dh DH key to write. + * @return 1 on success. * @return 0 on failure. */ -int wolfSSL_EC_KEY_set_group(WOLFSSL_EC_KEY *key, WOLFSSL_EC_GROUP *group) +int wolfSSL_PEM_write_DHparams(XFILE fp, WOLFSSL_DH* dh) { int ret = 1; + int derSz = 0; + byte* derBuf = NULL; + void* heap = NULL; - WOLFSSL_ENTER("wolfSSL_EC_KEY_set_group"); + WOLFSSL_ENTER("wolfSSL_PEM_write_DHparams"); /* Validate parameters. */ - if ((key == NULL) || (group == NULL)) { + if ((fp == XBADFILE) || (dh == NULL)) { + WOLFSSL_ERROR_MSG("Bad Function Arguments"); ret = 0; } if (ret == 1) { - /* Dispose of the current group. */ - if (key->group != NULL) { - wolfSSL_EC_GROUP_free(key->group); + DhKey* key = (DhKey*)dh->internal; + if (key) + heap = key->heap; + if ((derSz = wolfssl_dhparams_to_der(dh, &derBuf, heap)) < 0) { + WOLFSSL_ERROR_MSG("DER encoding failed"); + ret = 0; } - /* Duplicate the passed in group into EC key. */ - key->group = wolfSSL_EC_GROUP_dup(group); - if (key->group == NULL) { + if (derBuf == NULL) { + WOLFSSL_ERROR_MSG("DER encoding failed to get buffer"); ret = 0; } } + if ((ret == 1) && (der_write_to_file_as_pem(derBuf, derSz, fp, + DH_PARAM_TYPE, NULL) != 1)) { + ret = 0; + } + + /* Dispose of DER buffer. */ + XFREE(derBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); + + WOLFSSL_LEAVE("wolfSSL_PEM_write_DHparams", ret); return ret; } +#endif /* WOLFSSL_DH_EXTRA && !NO_FILESYSTEM */ -/* Get the BN object that is the private key in the EC key. - * - * @param [in] key EC key. - * @return BN object on success. - * @return NULL when key is NULL or private key is not set. - */ -WOLFSSL_BIGNUM *wolfSSL_EC_KEY_get0_private_key(const WOLFSSL_EC_KEY *key) -{ - WOLFSSL_BIGNUM* priv_key = NULL; +#endif /* HAVE_LIGHTY || HAVE_STUNNEL || WOLFSSL_MYSQL_COMPATIBLE || + * OPENSSL_EXTRA */ - WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_private_key"); +/* + * DH get/set APIs + */ - /* Validate parameter. */ - if (key == NULL) { - WOLFSSL_MSG("wolfSSL_EC_KEY_get0_private_key Bad arguments"); - } - /* Only return private key if it is not 0. */ - else if (!wolfSSL_BN_is_zero(key->priv_key)) { - priv_key = key->priv_key; - } +#ifdef OPENSSL_EXTRA - return priv_key; -} +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) \ + || defined(WOLFSSL_OPENSSH) || defined(OPENSSL_EXTRA) -/* Sets the private key value into EC key. - * - * Return code compliant with OpenSSL. +/* Set the members of DhKey into WOLFSSL_DH + * Specify elements to set via the 2nd parameter * - * @param [in, out] key EC key to set. - * @param [in] priv_key Private key value in a BN. - * @return 1 on success - * @return 0 on failure. + * @param [in, out] dh DH key to synchronize. + * @param [in] elm Elements to synchronize. + * @return 1 on success. + * @return -1 on failure. */ -int wolfSSL_EC_KEY_set_private_key(WOLFSSL_EC_KEY *key, - const WOLFSSL_BIGNUM *priv_key) +int SetDhExternal_ex(WOLFSSL_DH *dh, int elm) { int ret = 1; + DhKey *key = NULL; - WOLFSSL_ENTER("wolfSSL_EC_KEY_set_private_key"); + WOLFSSL_ENTER("SetDhExternal_ex"); /* Validate parameters. */ - if ((key == NULL) || (priv_key == NULL)) { - WOLFSSL_MSG("Bad arguments"); - ret = 0; + if ((dh == NULL) || (dh->internal == NULL)) { + WOLFSSL_ERROR_MSG("dh key NULL error"); + ret = WOLFSSL_FATAL_ERROR; } - /* Check for obvious invalid values. */ - if (wolfSSL_BN_is_negative(priv_key) || wolfSSL_BN_is_zero(priv_key) || - wolfSSL_BN_is_one(priv_key)) { - WOLFSSL_MSG("Invalid private key value"); - ret = 0; + if (ret == 1) { + /* Get the wolfSSL DH key. */ + key = (DhKey*)dh->internal; } - if (ret == 1) { - /* Free key if previously set. */ - if (key->priv_key != NULL) { - wolfSSL_BN_free(key->priv_key); + if ((ret == 1) && (elm & ELEMENT_P)) { + /* Set the prime. */ + if (wolfssl_bn_set_value(&dh->p, &key->p) != 1) { + WOLFSSL_ERROR_MSG("dh param p error"); + ret = WOLFSSL_FATAL_ERROR; } - - /* Duplicate the BN passed in. */ - key->priv_key = wolfSSL_BN_dup(priv_key); - if (key->priv_key == NULL) { - WOLFSSL_MSG("key ecc priv key NULL"); - ret = 0; + } + if ((ret == 1) && (elm & ELEMENT_G)) { + /* Set the generator. */ + if (wolfssl_bn_set_value(&dh->g, &key->g) != 1) { + WOLFSSL_ERROR_MSG("dh param g error"); + ret = WOLFSSL_FATAL_ERROR; } } - /* Set the external values into internal EC key. */ - if ((ret == 1) && (SetECKeyInternal(key) != 1)) { - WOLFSSL_MSG("SetECKeyInternal failed"); - /* Dispose of new private key on error. */ - wolfSSL_BN_free(key->priv_key); - key->priv_key = NULL; - ret = 0; + if ((ret == 1) && (elm & ELEMENT_Q)) { + /* Set the order. */ + if (wolfssl_bn_set_value(&dh->q, &key->q) != 1) { + WOLFSSL_ERROR_MSG("dh param q error"); + ret = WOLFSSL_FATAL_ERROR; + } + } +#ifdef WOLFSSL_DH_EXTRA + if ((ret == 1) && (elm & ELEMENT_PRV)) { + /* Set the private key. */ + if (wolfssl_bn_set_value(&dh->priv_key, &key->priv) != 1) { + WOLFSSL_ERROR_MSG("No DH Private Key"); + ret = WOLFSSL_FATAL_ERROR; + } + } + if ((ret == 1) && (elm & ELEMENT_PUB)) { + /* Set the public key. */ + if (wolfssl_bn_set_value(&dh->pub_key, &key->pub) != 1) { + WOLFSSL_ERROR_MSG("No DH Public Key"); + ret = WOLFSSL_FATAL_ERROR; + } + } +#endif /* WOLFSSL_DH_EXTRA */ + + if (ret == 1) { + /* On success record that the external values have been set. */ + dh->exSet = 1; } return ret; } - -/* Get the public key EC point object that is in EC key. +/* Set the members of DhKey into WOLFSSL_DH + * DhKey was populated from wc_DhKeyDecode + * p, g, pub_key and priv_key are set. * - * @param [in] key EC key. - * @return EC point object that is the public key on success. - * @return NULL when key is NULL. + * @param [in, out] dh DH key to synchronize. + * @return 1 on success. + * @return -1 on failure. */ -WOLFSSL_EC_POINT* wolfSSL_EC_KEY_get0_public_key(const WOLFSSL_EC_KEY *key) +int SetDhExternal(WOLFSSL_DH *dh) { - WOLFSSL_EC_POINT* pub_key = NULL; - - WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_public_key"); - - if (key != NULL) { - pub_key = key->pub_key; - } - - return pub_key; + /* Assuming Q not required when using this API. */ + int elements = ELEMENT_P | ELEMENT_G | ELEMENT_PUB | ELEMENT_PRV; + WOLFSSL_ENTER("SetDhExternal"); + return SetDhExternal_ex(dh, elements); } +#endif /* WOLFSSL_QT || OPENSSL_ALL || WOLFSSL_OPENSSH || OPENSSL_EXTRA */ -/* - * Return code compliant with OpenSSL. +/* Set the internal/wolfSSL DH key with data from the external parts. * - * @param [in, out] key EC key. - * @param [in] pub Public key as an EC point. - * @return 1 on success - * @return 0 on failure. + * @param [in, out] dh DH key to synchronize. + * @return 1 on success. + * @return -1 on failure. */ -int wolfSSL_EC_KEY_set_public_key(WOLFSSL_EC_KEY *key, - const WOLFSSL_EC_POINT *pub) +int SetDhInternal(WOLFSSL_DH* dh) { int ret = 1; - ecc_point *pub_p = NULL; - ecc_point *key_p = NULL; + DhKey *key = NULL; - WOLFSSL_ENTER("wolfSSL_EC_KEY_set_public_key"); + WOLFSSL_ENTER("SetDhInternal"); /* Validate parameters. */ - if ((key == NULL) || (key->internal == NULL) || (pub == NULL) || - (pub->internal == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_KEY_set_public_key Bad arguments"); - ret = 0; - } - - /* Ensure the internal EC key is set. */ - if ((ret == 1) && (key->inSet == 0) && (SetECKeyInternal(key) != 1)) { - WOLFSSL_MSG("SetECKeyInternal failed"); - ret = 0; + if ((dh == NULL) || (dh->p == NULL) || (dh->g == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = WOLFSSL_FATAL_ERROR; } + if (ret == 1) { + /* Get the wolfSSL DH key. */ + key = (DhKey*)dh->internal; - /* Ensure the internal EC point of pub is setup. */ - if ((ret == 1) && (ec_point_setup(pub) != 1)) { - ret = 0; + /* Clear out key and initialize. */ + wc_FreeDhKey(key); + if (wc_InitDhKey(key) != 0) { + ret = WOLFSSL_FATAL_ERROR; + } } - if (ret == 1) { - /* Get the internal point of pub and the public key in key. */ - pub_p = (ecc_point*)pub->internal; - key_p = (ecc_point*)key->pub_key->internal; - - /* Create new point if required. */ - if (key_p == NULL) { - key_p = wc_ecc_new_point(); - key->pub_key->internal = (void*)key_p; + /* Transfer prime. */ + if (wolfssl_bn_get_value(dh->p, &key->p) != 1) { + ret = WOLFSSL_FATAL_ERROR; } - /* Check point available. */ - if (key_p == NULL) { - WOLFSSL_MSG("key ecc point NULL"); - ret = 0; + } + if (ret == 1) { + /* Transfer generator. */ + if (wolfssl_bn_get_value(dh->g, &key->g) != 1) { + ret = WOLFSSL_FATAL_ERROR; } } - - /* Copy the internal pub point into internal key point. */ - if ((ret == 1) && (wc_ecc_copy_point(pub_p, key_p) != MP_OKAY)) { - WOLFSSL_MSG("ecc_copy_point failure"); - ret = 0; +#ifdef HAVE_FFDHE_Q + /* Transfer order if available. */ + if ((ret == 1) && (dh->q != NULL)) { + if (wolfssl_bn_get_value(dh->q, &key->q) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } } - - /* Copy the internal point data into external. */ - if ((ret == 1) && (ec_point_external_set(key->pub_key) != 1)) { - WOLFSSL_MSG("SetECKeyInternal failed"); - ret = 0; +#endif +#ifdef WOLFSSL_DH_EXTRA + /* Transfer private key if available. */ + if ((ret == 1) && (dh->priv_key != NULL) && + (!wolfSSL_BN_is_zero(dh->priv_key))) { + if (wolfssl_bn_get_value(dh->priv_key, &key->priv) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } } - - /* Copy the internal key into external. */ - if ((ret == 1) && (SetECKeyInternal(key) != 1)) { - WOLFSSL_MSG("SetECKeyInternal failed"); - ret = 0; + /* Transfer public key if available. */ + if ((ret == 1) && (dh->pub_key != NULL) && + (!wolfSSL_BN_is_zero(dh->pub_key))) { + if (wolfssl_bn_get_value(dh->pub_key, &key->pub) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } } +#endif /* WOLFSSL_DH_EXTRA */ if (ret == 1) { - /* Dump out the point and the key's public key for debug. */ - wolfSSL_EC_POINT_dump("pub", pub); - wolfSSL_EC_POINT_dump("key->pub_key", key->pub_key); + /* On success record that the internal values have been set. */ + dh->inSet = 1; } return ret; } -#ifndef NO_WOLFSSL_STUB -/* Set the ASN.1 encoding flag against the EC key. +/* Get the size, in bytes, of the DH key. * - * No implementation as only named curves supported for encoding. + * Return code compliant with OpenSSL. * - * @param [in, out] key EC key. - * @param [in] flag ASN.1 flag to set. Valid values: - * OPENSSL_EC_EXPLICIT_CURVE, OPENSSL_EC_NAMED_CURVE + * @param [in] dh DH key. + * @return -1 on error. + * @return Size of DH key in bytes on success. */ -void wolfSSL_EC_KEY_set_asn1_flag(WOLFSSL_EC_KEY *key, int asn1_flag) +int wolfSSL_DH_size(WOLFSSL_DH* dh) { - (void)key; - (void)asn1_flag; + WOLFSSL_ENTER("wolfSSL_DH_size"); - WOLFSSL_ENTER("wolfSSL_EC_KEY_set_asn1_flag"); - WOLFSSL_STUB("EC_KEY_set_asn1_flag"); -} -#endif + if (dh == NULL) + return WOLFSSL_FATAL_ERROR; -/* - * EC key generate key APIs - */ + /* Validate parameter. */ + /* Size of key is size of prime in bytes. */ + return wolfSSL_BN_num_bytes(dh->p); +} -/* Generate an EC key. - * - * Uses the internal curve index set in the EC key or the default. +/** + * Return parameters p, q and/or g of the DH key. * - * @param [in, out] key EC key. - * @return 1 on success - * @return 0 on failure. + * @param [in] dh DH key to retrieve parameters from. + * @param [out] p Pointer to return prime in. May be NULL. + * @param [out] q Pointer to return order in. May be NULL. + * @param [out] g Pointer to return generator in. May be NULL. */ -int wolfSSL_EC_KEY_generate_key(WOLFSSL_EC_KEY *key) +void wolfSSL_DH_get0_pqg(const WOLFSSL_DH *dh, const WOLFSSL_BIGNUM **p, + const WOLFSSL_BIGNUM **q, const WOLFSSL_BIGNUM **g) { - int res = 1; - int initTmpRng = 0; - WC_RNG* rng = NULL; - WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); - - WOLFSSL_ENTER("wolfSSL_EC_KEY_generate_key"); - - /* Validate parameters. */ - if ((key == NULL) || (key->internal == NULL) || (key->group == NULL)) { - WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key Bad arguments"); - res = 0; - } - if (res == 1) { - /* Check if we know which internal curve index to use. */ - if (key->group->curve_idx < 0) { - /* Generate key using the default curve. */ -#if FIPS_VERSION3_GE(6,0,0) - key->group->curve_idx = ECC_SECP256R1; /* FIPS default to 256 */ -#else - key->group->curve_idx = ECC_CURVE_DEF; -#endif - } + WOLFSSL_ENTER("wolfSSL_DH_get0_pqg"); - /* Create a random number generator. */ - rng = wolfssl_make_rng(tmpRng, &initTmpRng); - if (rng == NULL) { - WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key failed to make RNG"); - res = 0; - } - } - if (res == 1) { - /* NIDToEccEnum returns -1 for invalid NID so if key->group->curve_nid - * is 0 then pass ECC_CURVE_DEF as arg */ - int eccEnum = key->group->curve_nid ? -#if FIPS_VERSION3_GE(6,0,0) - NIDToEccEnum(key->group->curve_nid) : ECC_SECP256R1; -#else - NIDToEccEnum(key->group->curve_nid) : ECC_CURVE_DEF; -#endif - /* Get the internal EC key. */ - ecc_key* ecKey = (ecc_key*)key->internal; - /* Make the key using internal API. */ - int ret = 0; - -#if FIPS_VERSION3_GE(6,0,0) - /* In the case of FIPS only allow key generation with approved curves */ - if (eccEnum != ECC_SECP256R1 && eccEnum != ECC_SECP224R1 && - eccEnum != ECC_SECP384R1 && eccEnum != ECC_SECP521R1) { - WOLFSSL_MSG("Unsupported curve selected in FIPS mode"); - res = 0; - } - if (res == 1) { -#endif - ret = wc_ecc_make_key_ex(rng, 0, ecKey, eccEnum); -#if FIPS_VERSION3_GE(6,0,0) + if (dh != NULL) { + /* Return prime if required. */ + if (p != NULL) { + *p = dh->p; } -#endif - - #if defined(WOLFSSL_ASYNC_CRYPT) - /* Wait on asynchronouse operation. */ - ret = wc_AsyncWait(ret, &ecKey->asyncDev, WC_ASYNC_FLAG_NONE); - #endif - if (ret != 0) { - WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key wc_ecc_make_key failed"); - res = 0; + /* Return order if required. */ + if (q != NULL) { + *q = dh->q; + } + /* Return generator if required. */ + if (g != NULL) { + *g = dh->g; } } - - /* Dispose of local random number generator if initialized. */ - if (initTmpRng) { - wc_FreeRng(rng); - WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG); - } - - /* Set the external key from new internal key values. */ - if ((res == 1) && (SetECKeyExternal(key) != 1)) { - WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key SetECKeyExternal failed"); - res = 0; - } - - return res; } -/* - * EC key check key APIs - */ - -/* Check that the EC key is valid. +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS) && !defined(WOLFSSL_DH_EXTRA)) \ + || (defined(HAVE_FIPS_VERSION) && FIPS_VERSION_GT(2,0)) +#if defined(OPENSSL_ALL) || \ + defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L +/* Sets the parameters p, g and optionally q into the DH key. + * + * Ownership of p, q and g get taken over by "dh" on success and should be + * free'd with a call to wolfSSL_DH_free -- not individually. * - * @param [in] key EC key. - * @return 1 on valid. - * @return 0 on invalid or error. + * @param [in, out] dh DH key to set. + * @param [in] p Prime value to set. May be NULL when value already + * present. + * @param [in] q Order value to set. May be NULL. + * @param [in] g Generator value to set. May be NULL when value already + * present. + * @return 1 on success. + * @return 0 on failure. */ -int wolfSSL_EC_KEY_check_key(const WOLFSSL_EC_KEY *key) +int wolfSSL_DH_set0_pqg(WOLFSSL_DH *dh, WOLFSSL_BIGNUM *p, + WOLFSSL_BIGNUM *q, WOLFSSL_BIGNUM *g) { int ret = 1; - WOLFSSL_ENTER("wolfSSL_EC_KEY_check_key"); + WOLFSSL_ENTER("wolfSSL_DH_set0_pqg"); - /* Validate parameter. */ - if ((key == NULL) || (key->internal == NULL)) { - WOLFSSL_MSG("Bad parameter"); + /* Validate parameters - q is optional. */ + if (dh == NULL) { + WOLFSSL_ERROR_MSG("Bad function arguments"); ret = 0; } - - /* Set the external EC key values into internal if not already. */ - if ((ret == 1) && (key->inSet == 0) && (SetECKeyInternal( - (WOLFSSL_EC_KEY*)key) != 1)) { - WOLFSSL_MSG("SetECKeyInternal failed"); + /* p can be NULL if we already have one set. */ + if ((ret == 1) && (p == NULL) && (dh->p == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); ret = 0; } - - if (ret == 1) { - /* Have internal EC implementation check key. */ - ret = wc_ecc_check_key((ecc_key*)key->internal) == 0; + /* g can be NULL if we already have one set. */ + if ((ret == 1) && (g == NULL) && (dh->g == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = 0; } - return ret; -} - -/* End EC_KEY */ - -#if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) -/* Get the supported, built-in EC curves - * - * @param [in, out] curves Pre-allocated list to put supported curves into. - * @param [in] len Maximum number of items to place in list. - * @return Number of built-in EC curves when curves is NULL or len is 0. - * @return Number of items placed in list otherwise. - */ -size_t wolfSSL_EC_get_builtin_curves(WOLFSSL_EC_BUILTIN_CURVE *curves, - size_t len) -{ - size_t i; - size_t cnt; -#ifdef HAVE_SELFTEST - /* Defined in ecc.h when available. */ - size_t ecc_sets_count; - - /* Count the pre-defined curves since global not available. */ - for (i = 0; ecc_sets[i].size != 0 && ecc_sets[i].name != NULL; i++) { - /* Do nothing. */ - } - ecc_sets_count = i; -#endif + if (ret == 1) { + /* Invalidate internal key. */ + dh->inSet = 0; - /* Assume we are going to return total count. */ - cnt = ecc_sets_count; - /* Check we have a list that can hold data. */ - if ((curves != NULL) && (len != 0)) { - /* Limit count to length of list. */ - if (cnt > len) { - cnt = len; + /* Free external representation of parameters and set with those passed + * in. */ + if (p != NULL) { + wolfSSL_BN_free(dh->p); + dh->p = p; + } + if (q != NULL) { + wolfSSL_BN_free(dh->q); + dh->q = q; + } + if (g != NULL) { + wolfSSL_BN_free(dh->g); + dh->g = g; } + /* External DH key parameters were set. */ + dh->exSet = 1; - /* Put in built-in EC curve nid and short name. */ - for (i = 0; i < cnt; i++) { - curves[i].nid = EccEnumToNID(ecc_sets[i].id); - curves[i].comment = wolfSSL_OBJ_nid2sn(curves[i].nid); + /* Set internal/wolfSSL DH key as well. */ + if (SetDhInternal(dh) != 1) { + WOLFSSL_ERROR_MSG("Unable to set internal DH key"); + /* Don't keep parameters on failure. */ + dh->p = NULL; + dh->q = NULL; + dh->g = NULL; + /* Internal and external DH key not set. */ + dh->inSet = 0; + dh->exSet = 0; + ret = 0; } } - return cnt; + return ret; } -#endif /* !HAVE_FIPS || FIPS_VERSION_GT(2,0) */ -/* Start ECDSA_SIG */ - -/* Allocate a new ECDSA signature object. +/* Set the length of the DH private key in bits. * - * @return New, allocated ECDSA signature object on success. - * @return NULL on error. + * Length field is checked at generation. + * + * @param [in, out] dh DH key to set. + * @param [in] len Length of DH private key in bytes. + * @return 0 on failure. + * @return 1 on success. */ -WOLFSSL_ECDSA_SIG *wolfSSL_ECDSA_SIG_new(void) +int wolfSSL_DH_set_length(WOLFSSL_DH *dh, long len) { - int err = 0; - WOLFSSL_ECDSA_SIG *sig; - - WOLFSSL_ENTER("wolfSSL_ECDSA_SIG_new"); + int ret = 1; - /* Allocate memory for ECDSA signature object. */ - sig = (WOLFSSL_ECDSA_SIG*)XMALLOC(sizeof(WOLFSSL_ECDSA_SIG), NULL, - DYNAMIC_TYPE_ECC); - if (sig == NULL) { - WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA signature failure"); - err = 1; - } + WOLFSSL_ENTER("wolfSSL_DH_set_length"); - if (!err) { - /* Set s to NULL in case of error. */ - sig->s = NULL; - /* Allocate BN into r. */ - sig->r = wolfSSL_BN_new(); - if (sig->r == NULL) { - WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA r failure"); - err = 1; - } + /* Validate parameter. */ + if (dh == NULL) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = 0; } - if (!err) { - /* Allocate BN into s. */ - sig->s = wolfSSL_BN_new(); - if (sig->s == NULL) { - WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA s failure"); - err = 1; - } + else { + /* Store length. */ + dh->length = (int)len; } - if (err && (sig != NULL)) { - /* Dispose of allocated memory. */ - wolfSSL_ECDSA_SIG_free(sig); - sig = NULL; - } - return sig; + return ret; } +#endif /* OPENSSL_ALL || (v1.1.0 or later) */ +#endif -/* Dispose of ECDSA signature object. - * - * Cannot use object after this call. +/* Get the public and private keys requested. * - * @param [in] sig ECDSA signature object to free. + * @param [in] dh DH key to get keys from. + * @param [out] pub_key Pointer to return public key in. May be NULL. + * @param [out] priv_key Pointer to return private key in. May be NULL. */ -void wolfSSL_ECDSA_SIG_free(WOLFSSL_ECDSA_SIG *sig) +void wolfSSL_DH_get0_key(const WOLFSSL_DH *dh, const WOLFSSL_BIGNUM **pub_key, + const WOLFSSL_BIGNUM **priv_key) { - WOLFSSL_ENTER("wolfSSL_ECDSA_SIG_free"); - - if (sig != NULL) { - /* Dispose of BNs allocated for r and s. */ - wolfSSL_BN_free(sig->r); - wolfSSL_BN_free(sig->s); + WOLFSSL_ENTER("wolfSSL_DH_get0_key"); - /* Dispose of memory associated with ECDSA signature object. */ - XFREE(sig, NULL, DYNAMIC_TYPE_ECC); + /* Get only when valid DH passed in. */ + if (dh != NULL) { + /* Return public key if required and available. */ + if ((pub_key != NULL) && (dh->pub_key != NULL)) { + *pub_key = dh->pub_key; + } + /* Return private key if required and available. */ + if ((priv_key != NULL) && (dh->priv_key != NULL)) { + *priv_key = dh->priv_key; + } } } -/* Create an ECDSA signature from the DER encoding. +/* Set the public and/or private key. * - * @param [in, out] sig Reference to ECDSA signature object. May be NULL. - * @param [in, out] pp On in, reference to buffer containing DER encoding. - * On out, reference to buffer after signature data. - * @param [in] len Length of the data in the buffer. May be more than - * the length of the signature. - * @return ECDSA signature object on success. - * @return NULL on error. + * @param [in, out] dh DH key to have keys set into. + * @param [in] pub_key Public key to set. May be NULL. + * @param [in] priv_key Private key to set. May be NULL. + * @return 0 on failure. + * @return 1 on success. */ -WOLFSSL_ECDSA_SIG* wolfSSL_d2i_ECDSA_SIG(WOLFSSL_ECDSA_SIG** sig, - const unsigned char** pp, long len) +int wolfSSL_DH_set0_key(WOLFSSL_DH *dh, WOLFSSL_BIGNUM *pub_key, + WOLFSSL_BIGNUM *priv_key) { - int err = 0; - /* ECDSA signature object to return. */ - WOLFSSL_ECDSA_SIG *s = NULL; + int ret = 1; +#ifdef WOLFSSL_DH_EXTRA + DhKey *key = NULL; +#endif - /* Validate parameter. */ - if (pp == NULL) { - err = 1; + WOLFSSL_ENTER("wolfSSL_DH_set0_key"); + + /* Validate parameters. */ + if (dh == NULL) { + ret = 0; } - if (!err) { - if (sig != NULL) { - /* Use the ECDSA signature object passed in. */ - s = *sig; - } - if (s == NULL) { - /* No ECDSA signature object passed in - create a new one. */ - s = wolfSSL_ECDSA_SIG_new(); - if (s == NULL) { - err = 1; - } - } +#ifdef WOLFSSL_DH_EXTRA + else { + key = (DhKey*)dh->internal; } - if (!err) { - /* DecodeECC_DSA_Sig calls mp_init, so free these. */ - mp_free((mp_int*)s->r->internal); - mp_free((mp_int*)s->s->internal); +#endif - /* Decode the signature into internal r and s fields. */ - if (DecodeECC_DSA_Sig(*pp, (word32)len, (mp_int*)s->r->internal, - (mp_int*)s->s->internal) != MP_OKAY) { - err = 1; + /* Replace public key when one passed in. */ + if ((ret == 1) && (pub_key != NULL)) { + wolfSSL_BN_free(dh->pub_key); + dh->pub_key = pub_key; + #ifdef WOLFSSL_DH_EXTRA + if (wolfssl_bn_get_value(dh->pub_key, &key->pub) != 1) { + ret = 0; } + #endif } - if (!err) { - /* Move pointer passed signature data successfully decoded. */ - *pp += wolfssl_der_length(*pp, (int)len); - if (sig != NULL) { - /* Update reference to ECDSA signature object. */ - *sig = s; + /* Replace private key when one passed in. */ + if ((ret == 1) && (priv_key != NULL)) { + wolfSSL_BN_clear_free(dh->priv_key); + dh->priv_key = priv_key; + #ifdef WOLFSSL_DH_EXTRA + if (wolfssl_bn_get_value(dh->priv_key, &key->priv) != 1) { + ret = 0; } + #endif } - /* Dispose of newly allocated object on error. */ - if (err) { - if ((s != NULL) && ((sig == NULL) || (*sig != s))) { - wolfSSL_ECDSA_SIG_free(s); - } - /* Return NULL for object on error. */ - s = NULL; - } - return s; + return ret; } -/* Encode the ECDSA signature as DER. - * - * @param [in] sig ECDSA signature object. - * @param [in, out] pp On in, reference to buffer in which to place encoding. - * On out, reference to buffer after encoding. - * May be NULL or point to NULL in which case no encoding - * is done. - * @return Length of encoding on success. - * @return 0 on error. - */ -int wolfSSL_i2d_ECDSA_SIG(const WOLFSSL_ECDSA_SIG *sig, unsigned char **pp) -{ - word32 len = 0; - int update_p = 1; +#endif /* OPENSSL_EXTRA */ - /* Validate parameter. */ - if (sig != NULL) { - /* ASN.1: SEQ + INT + INT - * ASN.1 Integer must be a positive value - prepend zero if number has - * top bit set. - */ - /* Get total length of r including any prepended zero. */ - word32 rLen = (word32)(mp_leading_bit((mp_int*)sig->r->internal) + - mp_unsigned_bin_size((mp_int*)sig->r->internal)); - /* Get total length of s including any prepended zero. */ - word32 sLen = (word32)(mp_leading_bit((mp_int*)sig->s->internal) + - mp_unsigned_bin_size((mp_int*)sig->s->internal)); - /* Calculate length of data in sequence. */ - len = (word32)1 + ASN_LEN_SIZE(rLen) + rLen + - (word32)1 + ASN_LEN_SIZE(sLen) + sLen; - /* Add in the length of the SEQUENCE. */ - len += (word32)1 + ASN_LEN_SIZE(len); - - #ifdef WOLFSSL_I2D_ECDSA_SIG_ALLOC - if ((pp != NULL) && (*pp == NULL)) { - *pp = (unsigned char *)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL); - if (*pp != NULL) { - WOLFSSL_MSG("malloc error"); - return 0; - } - update_p = 0; - } - #endif +/* + * DH check APIs + */ - /* Encode only if there is a buffer to encode into. */ - if ((pp != NULL) && (*pp != NULL)) { - /* Encode using the internal representations of r and s. */ - if (StoreECC_DSA_Sig(*pp, &len, (mp_int*)sig->r->internal, - (mp_int*)sig->s->internal) != MP_OKAY) { - /* No bytes encoded. */ - len = 0; - } - else if (update_p) { - /* Update pointer to after encoding. */ - *pp += len; - } - } - } +#ifdef OPENSSL_EXTRA - return (int)len; -} +#ifndef NO_CERTS -/* Get the pointer to the fields of the ECDSA signature. - * - * r and s untouched when sig is NULL. +#ifdef OPENSSL_ALL +/* Check whether BN number is a prime. * - * @param [in] sig ECDSA signature object. - * @param [out] r R field of ECDSA signature as a BN. May be NULL. - * @param [out] s S field of ECDSA signature as a BN. May be NULL. + * @param [in] n Number to check. + * @param [out] isPrime MP_YES when prime and MP_NO when not. + * @return 1 on success. + * @return 0 on error. */ -void wolfSSL_ECDSA_SIG_get0(const WOLFSSL_ECDSA_SIG* sig, - const WOLFSSL_BIGNUM** r, const WOLFSSL_BIGNUM** s) +static int wolfssl_dh_check_prime(WOLFSSL_BIGNUM* n, int* isPrime) { - /* Validate parameter. */ - if (sig != NULL) { - /* Return the r BN when pointer to return through. */ - if (r != NULL) { - *r = sig->r; + int ret = 1; + WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); + WC_RNG* rng; + int localRng; + + /* Make an RNG with tmpRng or get global. */ + rng = wolfssl_make_rng(tmpRng, &localRng); + if (rng == NULL) { + ret = 0; + } + if (ret == 1) { + mp_int* prime = (mp_int*)n->internal; + + if (mp_prime_is_prime_ex(prime, 8, isPrime, rng) != 0) { + ret = 0; } - /* Return the s BN when pointer to return through. */ - if (s != NULL) { - *s = sig->s; + /* Free local random number generator if created. */ + if (localRng) { + wc_FreeRng(rng); + WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_TMP_BUFFER); } } + + return ret; } -/* Set the pointers to the fields of the ECDSA signature. +/* Checks the Diffie-Hellman parameters. * - * @param [in, out] sig ECDSA signature object to update. - * @param [in] r R field of ECDSA signature as a BN. - * @param [in] s S field of ECDSA signature as a BN. + * Checks that the generator and prime are available. + * Checks that the prime is prime. + * OpenSSL expects codes to be non-NULL. + * + * @param [in] dh DH key to check. + * @param [out] codes Codes of checks that failed. * @return 1 on success. - * @return 0 on error. + * @return 0 when DH is NULL, there were errors or failed to create a random + * number generator. */ -int wolfSSL_ECDSA_SIG_set0(WOLFSSL_ECDSA_SIG* sig, WOLFSSL_BIGNUM* r, - WOLFSSL_BIGNUM* s) +int wolfSSL_DH_check(const WOLFSSL_DH *dh, int *codes) { int ret = 1; + int errors = 0; + + WOLFSSL_ENTER("wolfSSL_DH_check"); /* Validate parameters. */ - if ((sig == NULL) || (r == NULL) || (s == NULL)) { + if (dh == NULL) { ret = 0; } + /* Check generator available. */ + if ((ret == 1) && ((dh->g == NULL) || (dh->g->internal == NULL))) { + errors |= DH_NOT_SUITABLE_GENERATOR; + } + if (ret == 1) { - /* Dispose of old BN objects. */ - wolfSSL_BN_free(sig->r); - wolfSSL_BN_free(sig->s); + /* Check prime available. */ + if ((dh->p == NULL) || (dh->p->internal == NULL)) { + errors |= DH_CHECK_P_NOT_PRIME; + } + else { + /* Test if dh->p is prime. */ + int isPrime = MP_NO; + ret = wolfssl_dh_check_prime(dh->p, &isPrime); + /* Set error code if parameter p is not prime. */ + if ((ret == 1) && (isPrime != MP_YES)) { + errors |= DH_CHECK_P_NOT_PRIME; + } + } + } - /* Assign new BN objects. */ - sig->r = r; - sig->s = s; + /* Return errors when user wants exact issues. */ + if (codes != NULL) { + *codes = errors; + } + else if (errors) { + ret = 0; } return ret; } -/* End ECDSA_SIG */ +#endif /* OPENSSL_ALL */ + +#endif /* !NO_CERTS */ + +#endif /* OPENSSL_EXTRA */ + +/* + * DH generate APIs + */ -/* Start ECDSA */ +#if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ + (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ + defined(HAVE_LIGHTY) || defined(WOLFSSL_HAPROXY) || \ + defined(WOLFSSL_OPENSSH) || defined(HAVE_SBLIM_SFCB))) -/* Calculate maximum size of the DER encoded ECDSA signature for the curve. +#if defined(WOLFSSL_KEY_GEN) && !defined(HAVE_SELFTEST) +/* Generate DH parameters. * - * @param [in] key EC key. - * @return Size of DER encoded signature on success. - * @return 0 on error. + * @param [in] prime_len Length of prime in bits. + * @param [in] generator Generator value to use. + * @param [in] callback Called with progress information. Unused. + * @param [in] cb_arg User callback argument. Unused. + * @return NULL on failure. + * @return DH key on success. */ -int wolfSSL_ECDSA_size(const WOLFSSL_EC_KEY *key) +WOLFSSL_DH *wolfSSL_DH_generate_parameters(int prime_len, int generator, + void (*callback) (int, int, void *), void *cb_arg) { - int err = 0; - int len = 0; - const WOLFSSL_EC_GROUP *group = NULL; - int bits = 0; + WOLFSSL_DH* dh = NULL; - /* Validate parameter. */ - if (key == NULL) { - err = 1; - } + WOLFSSL_ENTER("wolfSSL_DH_generate_parameters"); + /* Not supported by wolfSSl APIs. */ + (void)callback; + (void)cb_arg; - /* Get group from key to get order bits. */ - if ((!err) && ((group = wolfSSL_EC_KEY_get0_group(key)) == NULL)) { - err = 1; - } - /* Get order bits of group. */ - if ((!err) && ((bits = wolfSSL_EC_GROUP_order_bits(group)) == 0)) { - /* Group is not set. */ - err = 1; + /* Create an empty DH key. */ + if ((dh = wolfSSL_DH_new()) == NULL) { + WOLFSSL_ERROR_MSG("wolfSSL_DH_new error"); } - - if (!err) { - /* r and s are mod order. */ - int bytes = (bits + 7) / 8; /* Bytes needed to hold bits. */ - len = SIG_HEADER_SZ + /* 2*ASN_TAG + 2*LEN(ENUM) */ - ECC_MAX_PAD_SZ + /* possible leading zeroes in r and s */ - bytes + bytes; /* max r and s in bytes */ + /* Generate parameters into DH key. */ + else if (wolfSSL_DH_generate_parameters_ex(dh, prime_len, generator, NULL) + != 1) { + WOLFSSL_ERROR_MSG("wolfSSL_DH_generate_parameters_ex error"); + wolfSSL_DH_free(dh); + dh = NULL; } - return len; + return dh; } -/* Create ECDSA signature by signing digest with key. +/* Generate DH parameters. * - * @param [in] dgst Digest to sign. - * @param [in] dLen Length of digest in bytes. - * @param [in] key EC key to sign with. - * @return ECDSA signature object on success. - * @return NULL on error. + * @param [in] dh DH key to generate parameters into. + * @param [in] prime_len Length of prime in bits. + * @param [in] generator Generator value to use. + * @param [in] callback Called with progress information. Unused. + * @param [in] cb_arg User callback argument. Unused. + * @return 0 on failure. + * @return 1 on success. */ -WOLFSSL_ECDSA_SIG *wolfSSL_ECDSA_do_sign(const unsigned char *dgst, int dLen, - WOLFSSL_EC_KEY *key) +int wolfSSL_DH_generate_parameters_ex(WOLFSSL_DH* dh, int prime_len, + int generator, void (*callback) (int, int, void *)) { - int err = 0; - WOLFSSL_ECDSA_SIG *sig = NULL; - WC_DECLARE_VAR(out, byte, ECC_BUFSIZE, 0); - unsigned int outLen = ECC_BUFSIZE; + int ret = 1; + DhKey* key = NULL; + WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); + WC_RNG* rng = NULL; + int localRng = 0; - WOLFSSL_ENTER("wolfSSL_ECDSA_do_sign"); + WOLFSSL_ENTER("wolfSSL_DH_generate_parameters_ex"); + /* Not supported by wolfSSL APIs. */ + (void)callback; + (void)generator; /* Validate parameters. */ - if ((dgst == NULL) || (key == NULL) || (key->internal == NULL)) { - WOLFSSL_MSG("wolfSSL_ECDSA_do_sign Bad arguments"); - err = 1; + if (dh == NULL) { + WOLFSSL_ERROR_MSG("Bad parameter"); + ret = 0; } - /* Ensure internal EC key is set from external. */ - if ((!err) && (key->inSet == 0)) { - WOLFSSL_MSG("wolfSSL_ECDSA_do_sign No EC key internal set, do it"); - - if (SetECKeyInternal(key) != 1) { - WOLFSSL_MSG("wolfSSL_ECDSA_do_sign SetECKeyInternal failed"); - err = 1; + if (ret == 1) { + /* Make an RNG with tmpRng or get global. */ + rng = wolfssl_make_rng(tmpRng, &localRng); + if (rng == NULL) { + WOLFSSL_ERROR_MSG("No RNG to use"); + ret = 0; } } -#ifdef WOLFSSL_SMALL_STACK - if (!err) { - /* Allocate buffer to hold encoded signature. */ - out = (byte*)XMALLOC(outLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (out == NULL) { - err = 1; - } - } -#endif + if (ret == 1) { + /* Get internal/wolfSSL DH key. */ + key = (DhKey*)dh->internal; - /* Sign the digest with the key to create encoded ECDSA signature. */ - if ((!err) && (wolfSSL_ECDSA_sign(0, dgst, dLen, out, &outLen, key) != 1)) { - err = 1; + /* Clear out data from internal DH key. */ + wc_FreeDhKey(key); + /* Re-initialize internal DH key. */ + if (wc_InitDhKey(key) != 0) { + ret = 0; + } } - - if (!err) { - const byte* p = out; - /* Decode the ECDSA signature into a new object. */ - sig = wolfSSL_d2i_ECDSA_SIG(NULL, &p, outLen); + if (ret == 1) { + /* Generate parameters into internal DH key. */ + if (wc_DhGenerateParams(rng, prime_len, key) != 0) { + WOLFSSL_ERROR_MSG("wc_DhGenerateParams error"); + ret = 0; + } } - WC_FREE_VAR_EX(out, NULL, DYNAMIC_TYPE_TMP_BUFFER); - - return sig; -} - -/* Verify ECDSA signature in the object using digest and key. - * - * Return code compliant with OpenSSL. - * - * @param [in] dgst Digest to verify. - * @param [in] dLen Length of the digest in bytes. - * @param [in] sig ECDSA signature object. - * @param [in] key EC key containing public key. - * @return 1 when signature is valid. - * @return 0 when signature is invalid. - * @return -1 on error. - */ -int wolfSSL_ECDSA_do_verify(const unsigned char *dgst, int dLen, - const WOLFSSL_ECDSA_SIG *sig, WOLFSSL_EC_KEY *key) -{ - int ret = 1; - int verified = 0; -#ifdef WOLF_CRYPTO_CB_ONLY_ECC - byte signature[ECC_MAX_SIG_SIZE]; - int signatureLen; - byte* p = signature; -#endif - - WOLFSSL_ENTER("wolfSSL_ECDSA_do_verify"); - - /* Validate parameters. */ - if ((dgst == NULL) || (sig == NULL) || (key == NULL) || - (key->internal == NULL)) { - WOLFSSL_MSG("wolfSSL_ECDSA_do_verify Bad arguments"); - ret = WOLFSSL_FATAL_ERROR; + /* Free local random number generator if created. */ + if (localRng) { + wc_FreeRng(rng); + WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_TMP_BUFFER); } - /* Ensure internal EC key is set from external. */ - if ((ret == 1) && (key->inSet == 0)) { - WOLFSSL_MSG("No EC key internal set, do it"); + if (ret == 1) { + /* Internal parameters set by generation. */ + dh->inSet = 1; - if (SetECKeyInternal(key) != 1) { - WOLFSSL_MSG("SetECKeyInternal failed"); - ret = WOLFSSL_FATAL_ERROR; - } - } + WOLFSSL_MSG("wolfSSL does not support using a custom generator."); - if (ret == 1) { -#ifndef WOLF_CRYPTO_CB_ONLY_ECC - /* Verify hash using digest, r and s as MP ints and internal EC key. */ - if (wc_ecc_verify_hash_ex((mp_int*)sig->r->internal, - (mp_int*)sig->s->internal, dgst, (word32)dLen, &verified, - (ecc_key *)key->internal) != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_verify_hash failed"); - ret = WOLFSSL_FATAL_ERROR; - } - else if (verified == 0) { - WOLFSSL_MSG("wc_ecc_verify_hash incorrect signature detected"); + /* Synchronize the external to the internal parameters. */ + if (SetDhExternal(dh) != 1) { + WOLFSSL_ERROR_MSG("SetDhExternal error"); ret = 0; } -#else - signatureLen = i2d_ECDSA_SIG(sig, &p); - if (signatureLen > 0) { - /* verify hash. expects to call wc_CryptoCb_EccVerify internally */ - ret = wc_ecc_verify_hash(signature, signatureLen, dgst, - (word32)dLen, &verified, (ecc_key*)key->internal); - if (ret != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_verify_hash failed"); - ret = WOLFSSL_FATAL_ERROR; - } - else if (verified == 0) { - WOLFSSL_MSG("wc_ecc_verify_hash incorrect signature detected"); - ret = 0; - } - } -#endif /* WOLF_CRYPTO_CB_ONLY_ECC */ } return ret; } +#endif /* WOLFSSL_KEY_GEN && !HAVE_SELFTEST */ + +#endif /* OPENSSL_ALL || (OPENSSL_EXTRA && (HAVE_STUNNEL || WOLFSSL_NGINX || + * HAVE_LIGHTY || WOLFSSL_HAPROXY || WOLFSSL_OPENSSH || + * HAVE_SBLIM_SFCB)) */ + +#ifdef OPENSSL_EXTRA -/* Sign the digest with the key to produce a DER encode signature. +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS) && !defined(WOLFSSL_DH_EXTRA)) \ + || (defined(HAVE_FIPS_VERSION) && FIPS_VERSION_GT(2,0)) +/* Generate a public/private key pair base on parameters. * - * @param [in] type Digest algorithm used to create digest. Unused. - * @param [in] digest Digest of the message to sign. - * @param [in] digestSz Size of the digest in bytes. - * @param [out] sig Buffer to hold signature. - * @param [in, out] sigSz On in, size of buffer in bytes. - * On out, size of signatre in bytes. - * @param [in] key EC key containing private key. + * @param [in, out] dh DH key to generate keys into. * @return 1 on success. * @return 0 on error. */ -int wolfSSL_ECDSA_sign(int type, const unsigned char *digest, int digestSz, - unsigned char *sig, unsigned int *sigSz, WOLFSSL_EC_KEY *key) +int wolfSSL_DH_generate_key(WOLFSSL_DH* dh) { - int ret = 1; - WC_RNG* rng = NULL; + int ret = 1; + word32 pubSz = 0; + word32 privSz = 0; + int localRng = 0; + WC_RNG* rng = NULL; WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); - int initTmpRng = 0; - - WOLFSSL_ENTER("wolfSSL_ECDSA_sign"); + unsigned char* pub = NULL; + unsigned char* priv = NULL; - /* Digest algorithm not used in DER encoding. */ - (void)type; + WOLFSSL_ENTER("wolfSSL_DH_generate_key"); /* Validate parameters. */ - if (key == NULL) { + if ((dh == NULL) || (dh->p == NULL) || (dh->g == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = 0; + } + + /* Synchronize the external and internal parameters. */ + if ((ret == 1) && (dh->inSet == 0) && (SetDhInternal(dh) != 1)) { + WOLFSSL_ERROR_MSG("Bad DH set internal"); ret = 0; } if (ret == 1) { - /* Make an RNG - create local or get global. */ - rng = wolfssl_make_rng(tmpRng, &initTmpRng); + /* Make a new RNG or use global. */ + rng = wolfssl_make_rng(tmpRng, &localRng); + /* Check we have a random number generator. */ if (rng == NULL) { ret = 0; } } - /* Sign the digest with the key using the RNG and put signature into buffer - * update sigSz to be actual length. - */ - if ((ret == 1) && (wc_ecc_sign_hash(digest, (word32)digestSz, sig, sigSz, - rng, (ecc_key*)key->internal) != 0)) { - ret = 0; - } - if (initTmpRng) { - wc_FreeRng(rng); - WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG); + if (ret == 1) { + /* Get the size of the prime in bytes. */ + pubSz = (word32)wolfSSL_BN_num_bytes(dh->p); + if (pubSz == 0) { + WOLFSSL_ERROR_MSG("Prime parameter invalid"); + ret = 0; + } } + if (ret == 1) { + /* Private key size can be as much as the size of the prime. */ + if (dh->length) { + privSz = (word32)(dh->length / 8); /* to bytes */ + /* Special case where priv key is larger than dh->length / 8 + * See GeneratePrivateDh */ + if (dh->length == 128) + privSz = 21; + } + else { + privSz = pubSz; + } + /* Allocate public and private key arrays. */ + pub = (unsigned char*)XMALLOC(pubSz, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + priv = (unsigned char*)XMALLOC(privSz, NULL, DYNAMIC_TYPE_PRIVATE_KEY); + if (pub == NULL || priv == NULL) { + WOLFSSL_ERROR_MSG("Unable to malloc memory"); + ret = 0; + } + } + if (ret == 1) { + /* Dispose of old public and private keys. */ + wolfSSL_BN_free(dh->pub_key); + wolfSSL_BN_free(dh->priv_key); - return ret; -} - -/* Verify the signature with the digest and key. - * - * @param [in] type Digest algorithm used to create digest. Unused. - * @param [in] digest Digest of the message to verify. - * @param [in] digestSz Size of the digest in bytes. - * @param [in] sig Buffer holding signature. - * @param [in] sigSz Size of signature data in bytes. - * @param [in] key EC key containing public key. - * @return 1 when signature is valid. - * @return 0 when signature is invalid or error. - */ -int wolfSSL_ECDSA_verify(int type, const unsigned char *digest, int digestSz, - const unsigned char *sig, int sigSz, WOLFSSL_EC_KEY *key) -{ - int ret = 1; - int verify = 0; - - WOLFSSL_ENTER("wolfSSL_ECDSA_verify"); - - /* Digest algorithm not used in DER encoding. */ - (void)type; + /* Allocate new public and private keys. */ + dh->pub_key = wolfSSL_BN_new(); + dh->priv_key = wolfSSL_BN_new(); + if (dh->pub_key == NULL) { + WOLFSSL_ERROR_MSG("Bad DH new pub"); + ret = 0; + } + if (dh->priv_key == NULL) { + WOLFSSL_ERROR_MSG("Bad DH new priv"); + ret = 0; + } + } - /* Validate parameters. */ - if (key == NULL) { + PRIVATE_KEY_UNLOCK(); + /* Generate public and private keys into arrays. */ + if ((ret == 1) && (wc_DhGenerateKeyPair((DhKey*)dh->internal, rng, priv, + &privSz, pub, &pubSz) < 0)) { + WOLFSSL_ERROR_MSG("Bad wc_DhGenerateKeyPair"); ret = 0; } - - /* Verify signature using digest and key. */ - if ((ret == 1) && (wc_ecc_verify_hash(sig, (word32)sigSz, digest, - (word32)digestSz, &verify, (ecc_key*)key->internal) != 0)) { + /* Set public key from array. */ + if ((ret == 1) && (wolfSSL_BN_bin2bn(pub, (int)pubSz, dh->pub_key) == + NULL)) { + WOLFSSL_ERROR_MSG("Bad DH bn2bin error pub"); ret = 0; } - /* When no error, verification may still have failed - check now. */ - if ((ret == 1) && (verify != 1)) { - WOLFSSL_MSG("wolfSSL_ECDSA_verify failed"); + /* Set private key from array. */ + if ((ret == 1) && (wolfSSL_BN_bin2bn(priv, (int)privSz, dh->priv_key) == + NULL)) { + WOLFSSL_ERROR_MSG("Bad DH bn2bin error priv"); ret = 0; } + PRIVATE_KEY_LOCK(); + + if (localRng) { + /* Free an initialized local random number generator. */ + wc_FreeRng(rng); + WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG); + } + /* Dispose of allocated data. */ + XFREE(pub, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(priv, NULL, DYNAMIC_TYPE_PRIVATE_KEY); return ret; } -/* End ECDSA */ - -/* Start ECDH */ -#ifndef WOLF_CRYPTO_CB_ONLY_ECC -/* Compute the shared secret (key) using ECDH. - * - * KDF not supported. - * - * Return code compliant with OpenSSL. - * - * @param [out] out Buffer to hold key. - * @param [in] outLen Length of buffer in bytes. - * @param [in] pubKey Public key as an EC point. - * @param [in] privKey EC key holding a private key. - * @param [in] kdf Key derivation function to apply to secret. - * @return Length of computed key on success - * @return 0 on error. - */ -int wolfSSL_ECDH_compute_key(void *out, size_t outLen, - const WOLFSSL_EC_POINT *pubKey, WOLFSSL_EC_KEY *privKey, - void *(*kdf) (const void *in, size_t inlen, void *out, size_t *outLen)) +static int _DH_compute_key(unsigned char* key, const WOLFSSL_BIGNUM* otherPub, + WOLFSSL_DH* dh, int ct) { - int err = 0; - word32 len = 0; - ecc_key* key = NULL; -#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,0)) - int setGlobalRNG = 0; + int ret = 0; + word32 keySz = 0; + int pubSz = MAX_DHKEY_SZ; + int privSz = MAX_DHKEY_SZ; + int sz = 0; +#ifdef WOLFSSL_SMALL_STACK + unsigned char* pub = NULL; + unsigned char* priv = NULL; +#else + unsigned char pub [MAX_DHKEY_SZ]; + unsigned char priv[MAX_DHKEY_SZ]; #endif - /* TODO: support using the KDF. */ - (void)kdf; - - WOLFSSL_ENTER("wolfSSL_ECDH_compute_key"); + WOLFSSL_ENTER("wolfSSL_DH_compute_key"); /* Validate parameters. */ - if ((out == NULL) || (pubKey == NULL) || (pubKey->internal == NULL) || - (privKey == NULL) || (privKey->internal == NULL)) { - WOLFSSL_MSG("Bad function arguments"); - err = 1; + if ((dh == NULL) || (dh->priv_key == NULL) || (otherPub == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = WOLFSSL_FATAL_ERROR; } - - /* Ensure internal EC key is set from external. */ - if ((!err) && (privKey->inSet == 0)) { - WOLFSSL_MSG("No EC key internal set, do it"); - - if (SetECKeyInternal(privKey) != 1) { - WOLFSSL_MSG("SetECKeyInternal failed"); - err = 1; + /* Get the maximum size of computed DH key. */ + if ((ret == 0) && ((keySz = (word32)wolfSSL_DH_size(dh)) == 0)) { + WOLFSSL_ERROR_MSG("Bad DH_size"); + ret = WOLFSSL_FATAL_ERROR; + } + if (ret == 0) { + /* Validate the size of the private key. */ + sz = wolfSSL_BN_num_bytes(dh->priv_key); + if (sz > privSz) { + WOLFSSL_ERROR_MSG("Bad priv internal size"); + ret = WOLFSSL_FATAL_ERROR; } } + if (ret == 0) { + #ifdef WOLFSSL_SMALL_STACK + /* Keep real private key size to minimize amount allocated. */ + privSz = sz; + #endif - if (!err) { - int ret; - - /* Get the internal key. */ - key = (ecc_key*)privKey->internal; - /* Set length into variable of type suitable for wolfSSL API. */ - len = (word32)outLen; + /* Validate the size of the public key. */ + sz = wolfSSL_BN_num_bytes(otherPub); + if (sz > pubSz) { + WOLFSSL_ERROR_MSG("Bad otherPub size"); + ret = WOLFSSL_FATAL_ERROR; + } + } - #if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,0)) - /* An RNG is needed. */ - if (key->rng == NULL) { - key->rng = wolfssl_make_global_rng(); - /* RNG set and needs to be unset. */ - setGlobalRNG = 1; + if (ret == 0) { + #ifdef WOLFSSL_SMALL_STACK + /* Allocate memory for the public key array. */ + pub = (unsigned char*)XMALLOC((size_t)sz, NULL, + DYNAMIC_TYPE_PUBLIC_KEY); + if (pub == NULL) + ret = WOLFSSL_FATAL_ERROR; + } + if (ret == 0) { + /* Allocate memory for the private key array. */ + priv = (unsigned char*)XMALLOC((size_t)privSz, NULL, + DYNAMIC_TYPE_PRIVATE_KEY); + if (priv == NULL) { + ret = WOLFSSL_FATAL_ERROR; } + } + if (ret == 0) { #endif - - PRIVATE_KEY_UNLOCK(); - /* Create secret using wolfSSL. */ - ret = wc_ecc_shared_secret_ex(key, (ecc_point*)pubKey->internal, - (byte *)out, &len); - PRIVATE_KEY_LOCK(); - if (ret != MP_OKAY) { - WOLFSSL_MSG("wc_ecc_shared_secret failed"); - err = 1; + /* Get the private key into the array. */ + privSz = wolfSSL_BN_bn2bin(dh->priv_key, priv); + if (privSz <= 0) { + ret = WOLFSSL_FATAL_ERROR; } } - -#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,0)) - /* Remove global from key. */ - if (setGlobalRNG) { - key->rng = NULL; + if (ret == 0) { + /* Get the public key into the array. */ + pubSz = wolfSSL_BN_bn2bin(otherPub, pub); + if (pubSz <= 0) { + ret = WOLFSSL_FATAL_ERROR; + } } -#endif - - if (err) { - /* Make returned value zero. */ - len = 0; + /* Synchronize the external into the internal parameters. */ + if ((ret == 0) && ((dh->inSet == 0) && (SetDhInternal(dh) != 1))) { + WOLFSSL_ERROR_MSG("Bad DH set internal"); + ret = WOLFSSL_FATAL_ERROR; } - return (int)len; -} -#endif /* WOLF_CRYPTO_CB_ONLY_ECC */ - -/* End ECDH */ - -#ifndef NO_WOLFSSL_STUB -const WOLFSSL_EC_KEY_METHOD *wolfSSL_EC_KEY_OpenSSL(void) -{ - WOLFSSL_STUB("wolfSSL_EC_KEY_OpenSSL"); - - return NULL; -} - -WOLFSSL_EC_KEY_METHOD *wolfSSL_EC_KEY_METHOD_new( - const WOLFSSL_EC_KEY_METHOD *meth) -{ - WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_new"); - - (void)meth; - - return NULL; -} -void wolfSSL_EC_KEY_METHOD_free(WOLFSSL_EC_KEY_METHOD *meth) -{ - WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_free"); + PRIVATE_KEY_UNLOCK(); + /* Calculate shared secret from private and public keys. */ + if (ret == 0) { + word32 padded_keySz = keySz; +#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && !defined(HAVE_SELFTEST) + if (ct) { + if (wc_DhAgree_ct((DhKey*)dh->internal, key, &keySz, priv, + (word32)privSz, pub, (word32)pubSz) < 0) { + WOLFSSL_ERROR_MSG("wc_DhAgree_ct failed"); + ret = WOLFSSL_FATAL_ERROR; + } + } + else +#endif /* (!HAVE_FIPS || FIPS_VERSION_GE(7,0)) && !HAVE_SELFTEST */ + { + if (wc_DhAgree((DhKey*)dh->internal, key, &keySz, priv, + (word32)privSz, pub, (word32)pubSz) < 0) { + WOLFSSL_ERROR_MSG("wc_DhAgree failed"); + ret = WOLFSSL_FATAL_ERROR; + } + } - (void)meth; -} + if ((ret == 0) && ct) { + /* Arrange for correct fixed-length, right-justified key, even if + * the crypto back end doesn't support it. With some crypto back + * ends this forgoes formal constant-timeness on the key agreement, + * but assured that wolfSSL_DH_compute_key_padded() functions + * correctly. + */ + if (keySz < padded_keySz) { + XMEMMOVE(key, key + (padded_keySz - keySz), + padded_keySz - keySz); + XMEMSET(key, 0, padded_keySz - keySz); + keySz = padded_keySz; + } + } + } + if (ret == 0) { + /* Return actual length. */ + ret = (int)keySz; + } + PRIVATE_KEY_LOCK(); -void wolfSSL_EC_KEY_METHOD_set_init(WOLFSSL_EC_KEY_METHOD *meth, - void* a1, void* a2, void* a3, void* a4, void* a5, void* a6) -{ - WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_set_init"); - - (void)meth; - (void)a1; - (void)a2; - (void)a3; - (void)a4; - (void)a5; - (void)a6; -} + if (privSz > 0) { +#ifdef WOLFSSL_SMALL_STACK + if (priv != NULL) +#endif + { + /* Zeroize sensitive data. */ + ForceZero(priv, (word32)privSz); + } + } + WC_FREE_VAR_EX(pub, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + WC_FREE_VAR_EX(priv, NULL, DYNAMIC_TYPE_PRIVATE_KEY); -void wolfSSL_EC_KEY_METHOD_set_sign(WOLFSSL_EC_KEY_METHOD *meth, - void* a1, void* a2, void* a3) -{ - WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_set_sign"); + WOLFSSL_LEAVE("wolfSSL_DH_compute_key", ret); - (void)meth; - (void)a1; - (void)a2; - (void)a3; + return ret; } -const WOLFSSL_EC_KEY_METHOD *wolfSSL_EC_KEY_get_method( - const WOLFSSL_EC_KEY *key) +/* Compute the shared key from the private key and peer's public key. + * + * Return code compliant with OpenSSL. + * OpenSSL returns 0 when number of bits in p are smaller than minimum + * supported. + * + * @param [out] key Buffer to place shared key. + * @param [in] otherPub Peer's public key. + * @param [in] dh DH key containing private key. + * @return -1 on error. + * @return Size of shared secret in bytes on success. + */ +int wolfSSL_DH_compute_key(unsigned char* key, const WOLFSSL_BIGNUM* otherPub, + WOLFSSL_DH* dh) { - WOLFSSL_STUB("wolfSSL_EC_KEY_get_method"); - - (void)key; - - return NULL; + return _DH_compute_key(key, otherPub, dh, 0); } -int wolfSSL_EC_KEY_set_method(WOLFSSL_EC_KEY *key, - const WOLFSSL_EC_KEY_METHOD *meth) +/* Compute the shared key from the private key and peer's public key as in + * wolfSSL_DH_compute_key, but using constant time processing, with an output + * key length fixed at the nominal DH key size. Leading zeros are retained. + * + * Return code compliant with OpenSSL. + * OpenSSL returns 0 when number of bits in p are smaller than minimum + * supported. + * + * @param [out] key Buffer to place shared key. + * @param [in] otherPub Peer's public key. + * @param [in] dh DH key containing private key. + * @return -1 on error. + * @return Size of shared secret in bytes on success. + */ +int wolfSSL_DH_compute_key_padded(unsigned char* key, + const WOLFSSL_BIGNUM* otherPub, WOLFSSL_DH* dh) { - WOLFSSL_STUB("wolfSSL_EC_KEY_set_method"); - - (void)key; - (void)meth; - - return 0; + return _DH_compute_key(key, otherPub, dh, 1); } -#endif /* !NO_WOLFSSL_STUB */ +#endif /* !HAVE_FIPS || (HAVE_FIPS && !WOLFSSL_DH_EXTRA) || + * HAVE_FIPS_VERSION > 2 */ #endif /* OPENSSL_EXTRA */ -#endif /* HAVE_ECC */ +#endif /* NO_DH */ /******************************************************************************* - * END OF EC API + * END OF DH API ******************************************************************************/ + +#define WOLFSSL_PK_EC_INCLUDED +#include "src/pk_ec.c" + + /******************************************************************************* * START OF EC25519 API ******************************************************************************/ @@ -16529,7 +7113,8 @@ static int pem_write_mem_pkcs8privatekey(byte** pem, int* pemSz, if (res == 1) { /* Guestimate key size and PEM size. */ - if (pkcs8_encode(pkey, NULL, &keySz) != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { + if (pkcs8_encode(pkey, NULL, &keySz) != + WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { res = 0; } } diff --git a/src/pk_ec.c b/src/pk_ec.c new file mode 100644 index 0000000000..7502030e24 --- /dev/null +++ b/src/pk_ec.c @@ -0,0 +1,5558 @@ +/* pk_ec.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 + +#include +#ifndef WC_NO_RNG + #include +#endif + +#ifdef HAVE_ECC + #include + #ifdef HAVE_SELFTEST + /* point compression types. */ + #define ECC_POINT_COMP_EVEN 0x02 + #define ECC_POINT_COMP_ODD 0x03 + #define ECC_POINT_UNCOMP 0x04 + #endif +#endif +#ifndef WOLFSSL_HAVE_ECC_KEY_GET_PRIV + /* FIPS build has replaced ecc.h. */ + #define wc_ecc_key_get_priv(key) (&((key)->k)) + #define WOLFSSL_HAVE_ECC_KEY_GET_PRIV +#endif + +#if !defined(WOLFSSL_PK_EC_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning pk_ec.c does not need to be compiled separately from ssl.c + #endif +#else + +/******************************************************************************* + * START OF EC API + ******************************************************************************/ + +#ifdef HAVE_ECC + +#if defined(OPENSSL_EXTRA) + +/* Start EC_curve */ + +/* Get the NIST name for the numeric ID. + * + * @param [in] nid Numeric ID of an EC curve. + * @return String representing NIST name of EC curve on success. + * @return NULL on error. + */ +const char* wolfSSL_EC_curve_nid2nist(int nid) +{ + const char* name = NULL; + const WOLF_EC_NIST_NAME* nist_name; + + /* Attempt to find the curve info matching the NID passed in. */ + for (nist_name = kNistCurves; nist_name->name != NULL; nist_name++) { + if (nist_name->nid == nid) { + /* NID found - return name. */ + name = nist_name->name; + break; + } + } + + return name; +} + +/* Get the numeric ID for the NIST name. + * + * @param [in] name NIST name of EC curve. + * @return NID matching NIST name on success. + * @return 0 on error. + */ +int wolfSSL_EC_curve_nist2nid(const char* name) +{ + int nid = 0; + const WOLF_EC_NIST_NAME* nist_name; + + /* Attempt to find the curve info matching the NIST name passed in. */ + for (nist_name = kNistCurves; nist_name->name != NULL; nist_name++) { + if (XSTRCMP(nist_name->name, name) == 0) { + /* Name found - return NID. */ + nid = nist_name->nid; + break; + } + } + + return nid; +} + +#endif /* OPENSSL_EXTRA */ + +/* End EC_curve */ + +/* Start EC_METHOD */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Get the EC method of the EC group object. + * + * wolfSSL doesn't use method tables. Implementation used is dependent upon + * the NID. + * + * @param [in] group EC group object. + * @return EC method. + */ +const WOLFSSL_EC_METHOD* wolfSSL_EC_GROUP_method_of( + const WOLFSSL_EC_GROUP *group) +{ + /* No method table used so just return the same object. */ + return group; +} + +/* Get field type for method. + * + * Only prime fields are supported. + * + * @param [in] meth EC method. + * @return X9.63 prime field NID on success. + * @return 0 on error. + */ +int wolfSSL_EC_METHOD_get_field_type(const WOLFSSL_EC_METHOD *meth) +{ + int nid = 0; + + if (meth != NULL) { + /* Only field type supported by code base. */ + nid = WC_NID_X9_62_prime_field; + } + + return nid; +} +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +/* End EC_METHOD */ + +/* Start EC_GROUP */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Converts ECC curve enum values in ecc_curve_id to the associated OpenSSL NID + * value. + * + * @param [in] n ECC curve id. + * @return ECC curve NID (OpenSSL compatible value). + */ +int EccEnumToNID(int n) +{ + WOLFSSL_ENTER("EccEnumToNID"); + + switch(n) { + case ECC_SECP192R1: + return WC_NID_X9_62_prime192v1; + case ECC_PRIME192V2: + return WC_NID_X9_62_prime192v2; + case ECC_PRIME192V3: + return WC_NID_X9_62_prime192v3; + case ECC_PRIME239V1: + return WC_NID_X9_62_prime239v1; + case ECC_PRIME239V2: + return WC_NID_X9_62_prime239v2; + case ECC_PRIME239V3: + return WC_NID_X9_62_prime239v3; + case ECC_SECP256R1: + return WC_NID_X9_62_prime256v1; + case ECC_SECP112R1: + return WC_NID_secp112r1; + case ECC_SECP112R2: + return WC_NID_secp112r2; + case ECC_SECP128R1: + return WC_NID_secp128r1; + case ECC_SECP128R2: + return WC_NID_secp128r2; + case ECC_SECP160R1: + return WC_NID_secp160r1; + case ECC_SECP160R2: + return WC_NID_secp160r2; + case ECC_SECP224R1: + return WC_NID_secp224r1; + case ECC_SECP384R1: + return WC_NID_secp384r1; + case ECC_SECP521R1: + return WC_NID_secp521r1; + case ECC_SECP160K1: + return WC_NID_secp160k1; + case ECC_SECP192K1: + return WC_NID_secp192k1; + case ECC_SECP224K1: + return WC_NID_secp224k1; + case ECC_SECP256K1: + return WC_NID_secp256k1; + case ECC_BRAINPOOLP160R1: + return WC_NID_brainpoolP160r1; + case ECC_BRAINPOOLP192R1: + return WC_NID_brainpoolP192r1; + case ECC_BRAINPOOLP224R1: + return WC_NID_brainpoolP224r1; + case ECC_BRAINPOOLP256R1: + return WC_NID_brainpoolP256r1; + case ECC_BRAINPOOLP320R1: + return WC_NID_brainpoolP320r1; + case ECC_BRAINPOOLP384R1: + return WC_NID_brainpoolP384r1; + case ECC_BRAINPOOLP512R1: + return WC_NID_brainpoolP512r1; + #ifdef WOLFSSL_SM2 + case ECC_SM2P256V1: + return WC_NID_sm2; + #endif + default: + WOLFSSL_MSG("NID not found"); + return WOLFSSL_FATAL_ERROR; + } +} +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +/* Converts OpenSSL NID of EC curve to the enum value in ecc_curve_id + * + * Used by ecc_sets[]. + * + * @param [in] n OpenSSL NID of EC curve. + * @return wolfCrypt EC curve id. + * @return -1 on error. + */ +int NIDToEccEnum(int nid) +{ + int id; + + WOLFSSL_ENTER("NIDToEccEnum"); + + switch (nid) { + case WC_NID_X9_62_prime192v1: + id = ECC_SECP192R1; + break; + case WC_NID_X9_62_prime192v2: + id = ECC_PRIME192V2; + break; + case WC_NID_X9_62_prime192v3: + id = ECC_PRIME192V3; + break; + case WC_NID_X9_62_prime239v1: + id = ECC_PRIME239V1; + break; + case WC_NID_X9_62_prime239v2: + id = ECC_PRIME239V2; + break; + case WC_NID_X9_62_prime239v3: + id = ECC_PRIME239V3; + break; + case WC_NID_X9_62_prime256v1: + id = ECC_SECP256R1; + break; + case WC_NID_secp112r1: + id = ECC_SECP112R1; + break; + case WC_NID_secp112r2: + id = ECC_SECP112R2; + break; + case WC_NID_secp128r1: + id = ECC_SECP128R1; + break; + case WC_NID_secp128r2: + id = ECC_SECP128R2; + break; + case WC_NID_secp160r1: + id = ECC_SECP160R1; + break; + case WC_NID_secp160r2: + id = ECC_SECP160R2; + break; + case WC_NID_secp224r1: + id = ECC_SECP224R1; + break; + case WC_NID_secp384r1: + id = ECC_SECP384R1; + break; + case WC_NID_secp521r1: + id = ECC_SECP521R1; + break; + case WC_NID_secp160k1: + id = ECC_SECP160K1; + break; + case WC_NID_secp192k1: + id = ECC_SECP192K1; + break; + case WC_NID_secp224k1: + id = ECC_SECP224K1; + break; + case WC_NID_secp256k1: + id = ECC_SECP256K1; + break; + case WC_NID_brainpoolP160r1: + id = ECC_BRAINPOOLP160R1; + break; + case WC_NID_brainpoolP192r1: + id = ECC_BRAINPOOLP192R1; + break; + case WC_NID_brainpoolP224r1: + id = ECC_BRAINPOOLP224R1; + break; + case WC_NID_brainpoolP256r1: + id = ECC_BRAINPOOLP256R1; + break; + case WC_NID_brainpoolP320r1: + id = ECC_BRAINPOOLP320R1; + break; + case WC_NID_brainpoolP384r1: + id = ECC_BRAINPOOLP384R1; + break; + case WC_NID_brainpoolP512r1: + id = ECC_BRAINPOOLP512R1; + break; + default: + WOLFSSL_MSG("NID not found"); + /* -1 on error. */ + id = WOLFSSL_FATAL_ERROR; + } + + return id; +} + +/* Set the fields of the EC group based on numeric ID. + * + * @param [in, out] group EC group. + * @param [in] nid Numeric ID of an EC curve. + */ +static void ec_group_set_nid(WOLFSSL_EC_GROUP* group, int nid) +{ + int eccEnum; + int realNid; + + /* Convert ecc_curve_id enum to NID. */ + if ((realNid = EccEnumToNID(nid)) != -1) { + /* ecc_curve_id enum passed in - have real NID value set. */ + eccEnum = nid; + } + else { + /* NID passed in is OpenSSL type. */ + realNid = nid; + /* Convert NID to ecc_curve_id enum. */ + eccEnum = NIDToEccEnum(nid); + } + + /* Set the numeric ID of the curve */ + group->curve_nid = realNid; + /* Initialize index to -1 (i.e. wolfCrypt doesn't support curve). */ + group->curve_idx = -1; + + /* Find index and OID sum for curve if wolfCrypt supports it. */ + if (eccEnum != -1) { + int i; + + /* Find id and set the internal curve idx and OID sum. */ + for (i = 0; ecc_sets[i].size != 0; i++) { + if (ecc_sets[i].id == eccEnum) { + /* Found id in wolfCrypt supported EC curves. */ + group->curve_idx = i; + group->curve_oid = (int)ecc_sets[i].oidSum; + break; + } + } + } +} + +/* Create a new EC group with the numeric ID for an EC curve. + * + * @param [in] nid Numeric ID of an EC curve. + * @return New, allocated EC group on success. + * @return NULL on error. + */ +WOLFSSL_EC_GROUP* wolfSSL_EC_GROUP_new_by_curve_name(int nid) +{ + int err = 0; + WOLFSSL_EC_GROUP* group; + + WOLFSSL_ENTER("wolfSSL_EC_GROUP_new_by_curve_name"); + + /* Allocate EC group. */ + group = (WOLFSSL_EC_GROUP*)XMALLOC(sizeof(WOLFSSL_EC_GROUP), NULL, + DYNAMIC_TYPE_ECC); + if (group == NULL) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_new_by_curve_name malloc failure"); + err = 1; + } + + if (!err) { + /* Reset all fields. */ + XMEMSET(group, 0, sizeof(WOLFSSL_EC_GROUP)); + + /* Set the fields of group based on the numeric ID. */ + ec_group_set_nid(group, nid); + } + + return group; +} +#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Dispose of the EC group. + * + * Cannot use group after this call. + * + * @param [in] group EC group to free. + */ +void wolfSSL_EC_GROUP_free(WOLFSSL_EC_GROUP *group) +{ + WOLFSSL_ENTER("wolfSSL_EC_GROUP_free"); + + /* Dispose of EC group. */ + XFREE(group, NULL, DYNAMIC_TYPE_ECC); +} +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +#ifdef OPENSSL_EXTRA +#ifndef NO_BIO + +/* Creates an EC group from the DER encoding. + * + * Only named curves supported. + * + * @param [out] group Reference to EC group object. + * @param [in] in Buffer holding DER encoding of curve. + * @param [in] inSz Length of data in buffer. + * @return EC group on success. + * @return NULL on error. + */ +static WOLFSSL_EC_GROUP* wolfssl_ec_group_d2i(WOLFSSL_EC_GROUP** group, + const unsigned char** in_pp, long inSz) +{ + int err = 0; + WOLFSSL_EC_GROUP* ret = NULL; + word32 idx = 0; + word32 oid = 0; + int id = 0; + const unsigned char* in; + + if (in_pp == NULL || *in_pp == NULL) + return NULL; + + in = *in_pp; + + /* Use the group passed in. */ + if ((group != NULL) && (*group != NULL)) { + ret = *group; + } + + /* Only support named curves. */ + if (in[0] != ASN_OBJECT_ID) { + WOLFSSL_ERROR_MSG("Invalid or unsupported encoding"); + err = 1; + } + /* Decode the OBJECT ID - expecting an EC curve OID. */ + if ((!err) && (GetObjectId(in, &idx, &oid, oidCurveType, (word32)inSz) != + 0)) { + err = 1; + } + if (!err) { + /* Get the internal ID for OID. */ + id = wc_ecc_get_oid(oid, NULL, NULL); + if (id < 0) { + err = 1; + } + } + if (!err) { + /* Get the NID for the internal ID. */ + int nid = EccEnumToNID(id); + if (ret == NULL) { + /* Create a new EC group with the numeric ID. */ + ret = wolfSSL_EC_GROUP_new_by_curve_name(nid); + if (ret == NULL) { + err = 1; + } + } + else { + ec_group_set_nid(ret, nid); + } + } + if ((!err) && (group != NULL)) { + /* Return the EC group through reference. */ + *group = ret; + } + + if (err) { + if ((ret != NULL) && (ret != *group)) { + wolfSSL_EC_GROUP_free(ret); + } + ret = NULL; + } + else { + *in_pp += idx; + } + return ret; +} + +/* Creates a new EC group from the PEM encoding in the BIO. + * + * @param [in] bio BIO to read PEM encoding from. + * @param [out] group Reference to EC group object. + * @param [in] cb Password callback when PEM encrypted. + * @param [in] pass NUL terminated string for passphrase when PEM encrypted. + * @return EC group on success. + * @return NULL on error. + */ +WOLFSSL_EC_GROUP* wolfSSL_PEM_read_bio_ECPKParameters(WOLFSSL_BIO* bio, + WOLFSSL_EC_GROUP** group, wc_pem_password_cb* cb, void* pass) +{ + int err = 0; + WOLFSSL_EC_GROUP* ret = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + if (bio == NULL) { + err = 1; + } + + /* Read parameters from BIO and convert PEM to DER. */ + if ((!err) && (pem_read_bio_key(bio, cb, pass, ECC_PARAM_TYPE, + &keyFormat, &der) < 0)) { + err = 1; + } + if (!err) { + /* Create EC group from DER encoding. */ + const byte** p = (const byte**)&der->buffer; + ret = wolfssl_ec_group_d2i(group, p, der->length); + if (ret == NULL) { + WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_EC_GROUP"); + } + } + + /* Dispose of any allocated data. */ + FreeDer(&der); + return ret; +} + +WOLFSSL_EC_GROUP *wolfSSL_d2i_ECPKParameters(WOLFSSL_EC_GROUP **out, + const unsigned char **in, long len) +{ + return wolfssl_ec_group_d2i(out, in, len); +} + +int wolfSSL_i2d_ECPKParameters(const WOLFSSL_EC_GROUP* grp, unsigned char** pp) +{ + unsigned char* out = NULL; + int len = 0; + int idx; + const byte* oid = NULL; + word32 oidSz = 0; + + if (grp == NULL || !wc_ecc_is_valid_idx(grp->curve_idx) || + grp->curve_idx < 0) + return WOLFSSL_FATAL_ERROR; + + /* Get the actual DER encoding of the OID. ecc_sets[grp->curve_idx].oid + * is just the numerical representation. */ + if (wc_ecc_get_oid((word32)grp->curve_oid, &oid, &oidSz) < 0) + return WOLFSSL_FATAL_ERROR; + + len = SetObjectId((int)oidSz, NULL) + (int)oidSz; + + if (pp == NULL) + return len; + + if (*pp == NULL) { + out = (unsigned char*)XMALLOC((size_t)len, NULL, DYNAMIC_TYPE_ASN1); + if (out == NULL) + return WOLFSSL_FATAL_ERROR; + } + else { + out = *pp; + } + + idx = SetObjectId((int)oidSz, out); + XMEMCPY(out + idx, oid, oidSz); + if (*pp == NULL) + *pp = out; + else + *pp += len; + + return len; +} +#endif /* !NO_BIO */ + +#if defined(OPENSSL_ALL) && !defined(NO_CERTS) +/* Copy an EC group. + * + * Only used by wolfSSL_EC_KEY_dup at this time. + * + * @param [in, out] dst Destination EC group. + * @param [in] src Source EC group. + * @return 0 on success. + */ +static int wolfssl_ec_group_copy(WOLFSSL_EC_GROUP* dst, + const WOLFSSL_EC_GROUP* src) +{ + /* Copy the fields. */ + dst->curve_idx = src->curve_idx; + dst->curve_nid = src->curve_nid; + dst->curve_oid = src->curve_oid; + + return 0; +} +#endif /* OPENSSL_ALL && !NO_CERTS */ + +/* Copies ecc_key into new WOLFSSL_EC_GROUP object + * + * @param [in] src EC group to duplicate. + * + * @return EC group on success. + * @return NULL on error. + */ +WOLFSSL_EC_GROUP* wolfSSL_EC_GROUP_dup(const WOLFSSL_EC_GROUP *src) +{ + WOLFSSL_EC_GROUP* newGroup = NULL; + + if (src != NULL) { + /* Create new group base on NID in original EC group. */ + newGroup = wolfSSL_EC_GROUP_new_by_curve_name(src->curve_nid); + } + + return newGroup; +} + +/* Compare two EC groups. + * + * Return code compliant with OpenSSL. + * + * @param [in] a First EC group. + * @param [in] b Second EC group. + * @param [in] ctx Big number context to use when comparing fields. Unused. + * + * @return 0 if equal. + * @return 1 if not equal. + * @return -1 on error. + */ +int wolfSSL_EC_GROUP_cmp(const WOLFSSL_EC_GROUP *a, const WOLFSSL_EC_GROUP *b, + WOLFSSL_BN_CTX *ctx) +{ + int ret; + + /* No BN operations performed. */ + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_EC_GROUP_cmp"); + + /* Validate parameters. */ + if ((a == NULL) || (b == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_cmp Bad arguments"); + /* Return error value. */ + ret = WOLFSSL_FATAL_ERROR; + } + /* Compare NID and wolfSSL curve index. */ + else { + /* 0 when same, 1 when not. */ + ret = ((a->curve_nid == b->curve_nid) && + (a->curve_idx == b->curve_idx)) ? 0 : 1; + } + + return ret; +} + +#ifndef NO_WOLFSSL_STUB +/* Set the ASN.1 flag that indicate encoding of curve. + * + * Stub function - flag not used elsewhere. + * Always encoded as named curve. + * + * @param [in] group EC group to modify. + * @param [in] flag ASN.1 flag to set. Valid values: + * OPENSSL_EC_EXPLICIT_CURVE, OPENSSL_EC_NAMED_CURVE + */ +void wolfSSL_EC_GROUP_set_asn1_flag(WOLFSSL_EC_GROUP *group, int flag) +{ + (void)group; + (void)flag; + + WOLFSSL_ENTER("wolfSSL_EC_GROUP_set_asn1_flag"); + WOLFSSL_STUB("EC_GROUP_set_asn1_flag"); +} +#endif + +/* Get the curve NID of the group. + * + * Return code compliant with OpenSSL. + * + * @param [in] group EC group. + * @return Curve NID on success. + * @return 0 on error. + */ +int wolfSSL_EC_GROUP_get_curve_name(const WOLFSSL_EC_GROUP *group) +{ + int nid = 0; + WOLFSSL_ENTER("wolfSSL_EC_GROUP_get_curve_name"); + + if (group == NULL) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_curve_name Bad arguments"); + } + else { + nid = group->curve_nid; + } + + return nid; +} + +/* Get the degree (curve size in bits) of the EC group. + * + * Return code compliant with OpenSSL. + * + * @return Degree of the curve on success. + * @return 0 on error. + */ +int wolfSSL_EC_GROUP_get_degree(const WOLFSSL_EC_GROUP *group) +{ + int degree = 0; + + WOLFSSL_ENTER("wolfSSL_EC_GROUP_get_degree"); + + if (group == NULL) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_degree Bad arguments"); + } + else { + switch (group->curve_nid) { + case WC_NID_secp112r1: + case WC_NID_secp112r2: + degree = 112; + break; + case WC_NID_secp128r1: + case WC_NID_secp128r2: + degree = 128; + break; + case WC_NID_secp160k1: + case WC_NID_secp160r1: + case WC_NID_secp160r2: + case WC_NID_brainpoolP160r1: + degree = 160; + break; + case WC_NID_secp192k1: + case WC_NID_brainpoolP192r1: + case WC_NID_X9_62_prime192v1: + case WC_NID_X9_62_prime192v2: + case WC_NID_X9_62_prime192v3: + degree = 192; + break; + case WC_NID_secp224k1: + case WC_NID_secp224r1: + case WC_NID_brainpoolP224r1: + degree = 224; + break; + case WC_NID_X9_62_prime239v1: + case WC_NID_X9_62_prime239v2: + case WC_NID_X9_62_prime239v3: + degree = 239; + break; + case WC_NID_secp256k1: + case WC_NID_brainpoolP256r1: + case WC_NID_X9_62_prime256v1: + degree = 256; + break; + case WC_NID_brainpoolP320r1: + degree = 320; + break; + case WC_NID_secp384r1: + case WC_NID_brainpoolP384r1: + degree = 384; + break; + case WC_NID_brainpoolP512r1: + degree = 512; + break; + case WC_NID_secp521r1: + degree = 521; + break; + } + } + + return degree; +} +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +/* Get the length of the order in bits of the EC group. + * + * TODO: consider switch statement or calculating directly from hex string + * array instead of using mp_int. + * + * @param [in] group EC group. + * @return Length of order in bits on success. + * @return 0 on error. + */ +int wolfSSL_EC_GROUP_order_bits(const WOLFSSL_EC_GROUP *group) +{ + int ret = 0; + WC_DECLARE_VAR(order, mp_int, 1, 0); + + /* Validate parameter. */ + if ((group == NULL) || (group->curve_idx < 0)) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_order_bits NULL error"); + ret = WOLFSSL_FATAL_ERROR; + } + +#ifdef WOLFSSL_SMALL_STACK + if (ret == 0) { + /* Allocate memory for mp_int that will hold order value. */ + order = (mp_int *)XMALLOC(sizeof(*order), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (order == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } +#endif + + if (ret == 0) { + /* Initialize mp_int. */ + ret = mp_init(order); + } + + if (ret == 0) { + /* Read hex string of order from wolfCrypt array of curves. */ + ret = mp_read_radix(order, ecc_sets[group->curve_idx].order, + MP_RADIX_HEX); + if (ret == 0) { + /* Get bits of order. */ + ret = mp_count_bits(order); + } + /* Clear and free mp_int. */ + mp_clear(order); + } + + WC_FREE_VAR_EX(order, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + /* Convert error code to length of 0. */ + if (ret < 0) { + ret = 0; + } + + return ret; +} +#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ + +#if defined(OPENSSL_EXTRA) +/* Get the order of the group as a BN. + * + * Return code compliant with OpenSSL. + * + * @param [in] group EC group. + * @param [in, out] order BN to hold order value. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_EC_GROUP_get_order(const WOLFSSL_EC_GROUP *group, + WOLFSSL_BIGNUM *order, WOLFSSL_BN_CTX *ctx) +{ + int ret = 1; + mp_int* mp = NULL; + + /* No BN operations performed - done with mp_int in BN. */ + (void)ctx; + + /* Validate parameters. */ + if ((group == NULL) || (order == NULL) || (order->internal == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order NULL error"); + ret = 0; + } + + if (ret == 1 && + (group->curve_idx < 0 || !wc_ecc_is_valid_idx(group->curve_idx))) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order Bad group idx"); + ret = 0; + } + + if (ret == 1) { + mp = (mp_int*)order->internal; + } + /* Initialize */ + if ((ret == 1) && (mp_init(mp) != MP_OKAY)) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order mp_init failure"); + ret = 0; + } + /* Read hex string of order from wolfCrypt array of curves. */ + if ((ret == 1) && (mp_read_radix(mp, ecc_sets[group->curve_idx].order, + MP_RADIX_HEX) != MP_OKAY)) { + WOLFSSL_MSG("wolfSSL_EC_GROUP_get_order mp_read order failure"); + /* Zero out any partial value but don't free. */ + mp_zero(mp); + ret = 0; + } + + return ret; +} + +#endif /* OPENSSL_EXTRA */ + +/* End EC_GROUP */ + +/* Start EC_POINT */ + +#if defined(OPENSSL_EXTRA) + +/* Set data of EC point into internal, wolfCrypt EC point object. + * + * EC_POINT Openssl -> WolfSSL + * + * @param [in, out] p EC point to update. + * @return 1 on success. + * @return -1 on failure. + */ +static int ec_point_internal_set(WOLFSSL_EC_POINT *p) +{ + int ret = 1; + + WOLFSSL_ENTER("ec_point_internal_set"); + + /* Validate parameter. */ + if ((p == NULL) || (p->internal == NULL)) { + WOLFSSL_MSG("ECPoint NULL error"); + ret = WOLFSSL_FATAL_ERROR; + } + else { + /* Get internal point as a wolfCrypt EC point. */ + ecc_point* point = (ecc_point*)p->internal; + + /* Set X ordinate if available. */ + if ((p->X != NULL) && (wolfssl_bn_get_value(p->X, point->x) != 1)) { + WOLFSSL_MSG("ecc point X error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* Set Y ordinate if available. */ + if ((ret == 1) && (p->Y != NULL) && (wolfssl_bn_get_value(p->Y, + point->y) != 1)) { + WOLFSSL_MSG("ecc point Y error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* Set Z ordinate if available. */ + if ((ret == 1) && (p->Z != NULL) && (wolfssl_bn_get_value(p->Z, + point->z) != 1)) { + WOLFSSL_MSG("ecc point Z error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* Internal values set when operations succeeded. */ + p->inSet = (ret == 1); + } + + return ret; +} + +/* Set data of internal, wolfCrypt EC point object into EC point. + * + * EC_POINT WolfSSL -> OpenSSL + * + * @param [in, out] p EC point to update. + * @return 1 on success. + * @return -1 on failure. + */ +static int ec_point_external_set(WOLFSSL_EC_POINT *p) +{ + int ret = 1; + + WOLFSSL_ENTER("ec_point_external_set"); + + /* Validate parameter. */ + if ((p == NULL) || (p->internal == NULL)) { + WOLFSSL_MSG("ECPoint NULL error"); + ret = WOLFSSL_FATAL_ERROR; + } + else { + /* Get internal point as a wolfCrypt EC point. */ + ecc_point* point = (ecc_point*)p->internal; + + /* Set X ordinate. */ + if (wolfssl_bn_set_value(&p->X, point->x) != 1) { + WOLFSSL_MSG("ecc point X error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* Set Y ordinate. */ + if ((ret == 1) && (wolfssl_bn_set_value(&p->Y, point->y) != 1)) { + WOLFSSL_MSG("ecc point Y error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* Set Z ordinate. */ + if ((ret == 1) && (wolfssl_bn_set_value(&p->Z, point->z) != 1)) { + WOLFSSL_MSG("ecc point Z error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* External values set when operations succeeded. */ + p->exSet = (ret == 1); + } + + return ret; +} + +/* Setup internals of EC point. + * + * Assumes point is not NULL. + * + * @param [in, out] point EC point to update. + * @return 1 on success. + * @return 0 on failure. + */ +static int ec_point_setup(const WOLFSSL_EC_POINT *point) { + int ret = 1; + + /* Check if internal values need setting. */ + if (!point->inSet) { + WOLFSSL_MSG("No ECPoint internal set, do it"); + + /* Forcing to non-constant type to update internals. */ + if (ec_point_internal_set((WOLFSSL_EC_POINT *)point) != 1) { + WOLFSSL_MSG("ec_point_internal_set failed"); + ret = 0; + } + } + + return ret; +} + +/* Create a new EC point from the group. + * + * @param [in] group EC group. + * @return EC point on success. + * @return NULL on error. + */ +WOLFSSL_EC_POINT* wolfSSL_EC_POINT_new(const WOLFSSL_EC_GROUP* group) +{ + int err = 0; + WOLFSSL_EC_POINT* point = NULL; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_new"); + + /* Validate parameter. */ + if (group == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_new NULL error"); + err = 1; + } + + if (!err) { + /* Allocate memory for new EC point. */ + point = (WOLFSSL_EC_POINT*)XMALLOC(sizeof(WOLFSSL_EC_POINT), NULL, + DYNAMIC_TYPE_ECC); + if (point == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_new malloc ecc point failure"); + err = 1; + } + } + if (!err) { + /* Clear fields of EC point. */ + XMEMSET(point, 0, sizeof(WOLFSSL_EC_POINT)); + + /* Allocate internal EC point. */ + point->internal = wc_ecc_new_point(); + if (point->internal == NULL) { + WOLFSSL_MSG("ecc_new_point failure"); + err = 1; + } + } + + if (err) { + XFREE(point, NULL, DYNAMIC_TYPE_ECC); + point = NULL; + } + return point; +} + +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Dispose of the EC point. + * + * Cannot use point after this call. + * + * @param [in, out] point EC point to free. + */ +void wolfSSL_EC_POINT_free(WOLFSSL_EC_POINT *point) +{ + WOLFSSL_ENTER("wolfSSL_EC_POINT_free"); + + if (point != NULL) { + if (point->internal != NULL) { + wc_ecc_del_point((ecc_point*)point->internal); + point->internal = NULL; + } + + /* Free ordinates. */ + wolfSSL_BN_free(point->X); + wolfSSL_BN_free(point->Y); + wolfSSL_BN_free(point->Z); + /* Clear fields. */ + point->X = NULL; + point->Y = NULL; + point->Z = NULL; + point->inSet = 0; + point->exSet = 0; + + /* Dispose of EC point. */ + XFREE(point, NULL, DYNAMIC_TYPE_ECC); + } +} +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +#ifdef OPENSSL_EXTRA + +/* Clear and dispose of the EC point. + * + * Cannot use point after this call. + * + * @param [in, out] point EC point to free. + */ +void wolfSSL_EC_POINT_clear_free(WOLFSSL_EC_POINT *point) +{ + WOLFSSL_ENTER("wolfSSL_EC_POINT_clear_free"); + + if (point != NULL) { + if (point->internal != NULL) { + /* Force internal point to be zeros. */ + #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + wc_ecc_forcezero_point((ecc_point*)point->internal); + #else + ecc_point* p = (ecc_point*)point->internal; + mp_forcezero(p->x); + mp_forcezero(p->y); + mp_forcezero(p->z); + #endif + wc_ecc_del_point((ecc_point*)point->internal); + point->internal = NULL; + } + + /* Clear the ordinates before freeing. */ + wolfSSL_BN_clear_free(point->X); + wolfSSL_BN_clear_free(point->Y); + wolfSSL_BN_clear_free(point->Z); + /* Clear fields. */ + point->X = NULL; + point->Y = NULL; + point->Z = NULL; + point->inSet = 0; + point->exSet = 0; + + /* Dispose of EC point. */ + XFREE(point, NULL, DYNAMIC_TYPE_ECC); + } +} + +/* Print out the internals of EC point in debug and when logging callback set. + * + * Not an OpenSSL API. + * + * TODO: Use WOLFSSL_MSG_EX()? + * + * @param [in] msg Message to prepend. + * @param [in] point EC point to print. + */ +void wolfSSL_EC_POINT_dump(const char *msg, const WOLFSSL_EC_POINT *point) +{ +#if defined(DEBUG_WOLFSSL) + char *num; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_dump"); + + /* Only print when debugging on. */ + if (WOLFSSL_IS_DEBUG_ON()) { + if (point == NULL) { + /* No point passed in so just put out "NULL". */ + WOLFSSL_MSG_EX("%s = NULL\n", msg); + } + else { + /* Put out message and status of internal/external data set. */ + WOLFSSL_MSG_EX("%s:\n\tinSet=%d, exSet=%d\n", msg, point->inSet, + point->exSet); + /* Get x-ordinate as a hex string and print. */ + num = wolfSSL_BN_bn2hex(point->X); + WOLFSSL_MSG_EX("\tX = %s\n", num); + XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); + /* Get x-ordinate as a hex string and print. */ + num = wolfSSL_BN_bn2hex(point->Y); + WOLFSSL_MSG_EX("\tY = %s\n", num); + XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); + /* Get z-ordinate as a hex string and print. */ + num = wolfSSL_BN_bn2hex(point->Z); + WOLFSSL_MSG_EX("\tZ = %s\n", num); + XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); + } + } +#else + (void)msg; + (void)point; +#endif +} + +/* Convert EC point to hex string that as either uncompressed or compressed. + * + * ECC point compression types were not included in selftest ecc.h + * + * @param [in] group EC group for point. + * @param [in] point EC point to encode. + * @param [in] form Format of encoding. Valid values: + * POINT_CONVERSION_UNCOMPRESSED, POINT_CONVERSION_COMPRESSED + * @param [in] ctx Context to use for BN operations. Unused. + * @return Allocated hex string on success. + * @return NULL on error. + */ +char* wolfSSL_EC_POINT_point2hex(const WOLFSSL_EC_GROUP* group, + const WOLFSSL_EC_POINT* point, int form, WOLFSSL_BN_CTX* ctx) +{ + static const char* hexDigit = "0123456789ABCDEF"; + char* hex = NULL; + int i; + int sz = 0; + int len = 0; + int err = 0; + + /* No BN operations performed. */ + (void)ctx; + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL)) { + err = 1; + } + /* Get curve id expects a positive index. */ + if ((!err) && (group->curve_idx < 0)) { + err = 1; + } + + if (!err) { + /* Get curve id to look up ordinate size. */ + int id = wc_ecc_get_curve_id(group->curve_idx); + /* Get size of ordinate. */ + if ((sz = wc_ecc_get_curve_size_from_id(id)) < 0) { + err = 1; + } + } + if (!err) { + /* [] */ + len = sz + 1; + if (form == WC_POINT_CONVERSION_UNCOMPRESSED) { + /* Include y ordinate when uncompressed. */ + len += sz; + } + + /* Hex string: allocate 2 bytes to represent each byte plus 1 for '\0'. + */ + hex = (char*)XMALLOC((size_t)(2 * len + 1), NULL, DYNAMIC_TYPE_ECC); + if (hex == NULL) { + err = 1; + } + } + if (!err) { + /* Make bytes all zeros to allow for ordinate values less than max size. + */ + XMEMSET(hex, 0, (size_t)(2 * len + 1)); + + /* Calculate offset as leading zeros not encoded. */ + i = sz - mp_unsigned_bin_size((mp_int*)point->X->internal) + 1; + /* Put in x-ordinate after format byte. */ + if (mp_to_unsigned_bin((mp_int*)point->X->internal, (byte*)(hex + i)) < + 0) { + err = 1; + } + } + if (!err) { + if (form == WC_POINT_CONVERSION_COMPRESSED) { + /* Compressed format byte value dependent on whether y-ordinate is + * odd. + */ + hex[0] = mp_isodd((mp_int*)point->Y->internal) ? + ECC_POINT_COMP_ODD : ECC_POINT_COMP_EVEN; + /* No y-ordinate. */ + } + else { + /* Put in uncompressed format byte. */ + hex[0] = ECC_POINT_UNCOMP; + /* Calculate offset as leading zeros not encoded. */ + i = 1 + 2 * sz - mp_unsigned_bin_size((mp_int*)point->Y->internal); + /* Put in y-ordinate after x-ordinate. */ + if (mp_to_unsigned_bin((mp_int*)point->Y->internal, + (byte*)(hex + i)) < 0) { + err = 1; + } + } + } + if (!err) { + /* Convert binary encoding to hex string. */ + /* Start at end so as not to overwrite. */ + for (i = len-1; i >= 0; i--) { + /* Get byte value and store has hex string. */ + byte b = (byte)hex[i]; + hex[i * 2 + 1] = hexDigit[b & 0xf]; + hex[i * 2 ] = hexDigit[b >> 4]; + } + /* Memset put trailing zero or '\0' on end of string. */ + } + + if (err && (hex != NULL)) { + /* Dispose of allocated data not being returned. */ + XFREE(hex, NULL, DYNAMIC_TYPE_ECC); + hex = NULL; + } + /* Return hex string encoding. */ + return hex; +} + +static size_t hex_to_bytes(const char *hex, unsigned char *output, size_t sz) +{ + word32 i; + for (i = 0; i < sz; i++) { + signed char ch1, ch2; + ch1 = HexCharToByte(hex[i * 2]); + ch2 = HexCharToByte(hex[i * 2 + 1]); + if ((ch1 < 0) || (ch2 < 0)) { + WOLFSSL_MSG("hex_to_bytes: syntax error"); + return 0; + } + output[i] = (unsigned char)((ch1 << 4) + ch2); + } + return sz; +} + +WOLFSSL_EC_POINT* wolfSSL_EC_POINT_hex2point(const WOLFSSL_EC_GROUP *group, + const char *hex, WOLFSSL_EC_POINT*p, WOLFSSL_BN_CTX *ctx) +{ + /* for uncompressed mode */ + size_t str_sz; + WOLFSSL_BIGNUM *Gx = NULL; + WOLFSSL_BIGNUM *Gy = NULL; + char strGx[MAX_ECC_BYTES * 2 + 1]; + + /* for compressed mode */ + int key_sz; + byte *octGx = (byte *)strGx; /* octGx[MAX_ECC_BYTES] */ + + int p_alloc = 0; + int ret; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_hex2point"); + + if (group == NULL || hex == NULL || ctx == NULL) + return NULL; + + if (p == NULL) { + if ((p = wolfSSL_EC_POINT_new(group)) == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_new"); + goto err; + } + p_alloc = 1; + } + + key_sz = (wolfSSL_EC_GROUP_get_degree(group) + 7) / 8; + if (hex[0] == '0' && hex[1] == '4') { /* uncompressed mode */ + str_sz = (size_t)key_sz * 2; + + XMEMSET(strGx, 0x0, str_sz + 1); + XMEMCPY(strGx, hex + 2, str_sz); + + if (wolfSSL_BN_hex2bn(&Gx, strGx) == 0) + goto err; + + if (wolfSSL_BN_hex2bn(&Gy, hex + 2 + str_sz) == 0) + goto err; + + ret = wolfSSL_EC_POINT_set_affine_coordinates_GFp + (group, p, Gx, Gy, ctx); + + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp"); + goto err; + } + } + else if (hex[0] == '0' && (hex[1] == '2' || hex[1] == '3')) { + size_t sz = XSTRLEN(hex + 2) / 2; + /* compressed mode */ + octGx[0] = ECC_POINT_COMP_ODD; + if (hex_to_bytes(hex + 2, octGx + 1, sz) != sz) { + goto err; + } + if (wolfSSL_ECPoint_d2i(octGx, (word32)key_sz + 1, group, p) + != WOLFSSL_SUCCESS) { + goto err; + } + } + else + goto err; + + wolfSSL_BN_free(Gx); + wolfSSL_BN_free(Gy); + return p; + +err: + wolfSSL_BN_free(Gx); + wolfSSL_BN_free(Gy); + if (p_alloc) { + wolfSSL_EC_POINT_free(p); + } + return NULL; + +} + +/* Encode the EC point as an uncompressed point in DER. + * + * Return code compliant with OpenSSL. + * Not OpenSSL API. + * + * @param [in] group EC group point belongs to. + * @param [in] point EC point to encode. + * @param [out] out Buffer to encode into. May be NULL. + * @param [in, out] len On in, length of buffer in bytes. + * On out, length of encoding in bytes. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_ECPoint_i2d(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *point, unsigned char *out, unsigned int *len) +{ + int res = 1; + + WOLFSSL_ENTER("wolfSSL_ECPoint_i2d"); + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL) || (len == NULL)) { + WOLFSSL_MSG("wolfSSL_ECPoint_i2d NULL error"); + res = 0; + } + + /* Ensure points internals are set up. */ + if ((res == 1) && (ec_point_setup(point) != 1)) { + res = 0; + } + + /* Dump the point if encoding. */ + if ((res == 1) && (out != NULL)) { + wolfSSL_EC_POINT_dump("i2d p", point); + } + + if (res == 1) { + /* DER encode point in uncompressed format. */ + int ret = wc_ecc_export_point_der(group->curve_idx, + (ecc_point*)point->internal, out, len); + /* Check return. When out is NULL, return will be length only error. */ + if ((ret != MP_OKAY) && ((out != NULL) || + (ret != WC_NO_ERR_TRACE(LENGTH_ONLY_E)))) { + WOLFSSL_MSG("wolfSSL_ECPoint_i2d wc_ecc_export_point_der failed"); + res = 0; + } + } + + return res; +} + +/* Decode the uncompressed point in DER into EC point. + * + * Return code compliant with OpenSSL. + * Not OpenSSL API. + * + * @param [in] in Buffer containing DER encoded point. + * @param [in] len Length of data in bytes. + * @param [in] group EC group associated with point. + * @param [in, out] point EC point to set data into. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_ECPoint_d2i(const unsigned char *in, unsigned int len, + const WOLFSSL_EC_GROUP *group, WOLFSSL_EC_POINT *point) +{ + int ret = 1; + WOLFSSL_BIGNUM* x = NULL; + WOLFSSL_BIGNUM* y = NULL; + + WOLFSSL_ENTER("wolfSSL_ECPoint_d2i"); + + /* Validate parameters. */ + if ((in == NULL) || (group == NULL) || (point == NULL) || + (point->internal == NULL)) { + WOLFSSL_MSG("wolfSSL_ECPoint_d2i NULL error"); + ret = 0; + } + + if (ret == 1) { + #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + /* Import point into internal EC point. */ + if (wc_ecc_import_point_der_ex(in, len, group->curve_idx, + (ecc_point*)point->internal, 0) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_import_point_der_ex failed"); + ret = 0; + } + #else + /* ECC_POINT_UNCOMP is not defined CAVP self test so use magic number */ + if (in[0] == 0x04) { + /* Import point into internal EC point. */ + if (wc_ecc_import_point_der((unsigned char *)in, len, + group->curve_idx, (ecc_point*)point->internal) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_import_point_der failed"); + ret = 0; + } + } + else { + WOLFSSL_MSG("Only uncompressed points supported with " + "HAVE_SELFTEST"); + ret = 0; + } + #endif + } + + if (ret == 1) + point->inSet = 1; + + /* Set new external point. */ + if (ret == 1 && ec_point_external_set(point) != 1) { + WOLFSSL_MSG("ec_point_external_set failed"); + ret = 0; + } + + if (ret == 1 && !wolfSSL_BN_is_one(point->Z)) { +#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) + x = wolfSSL_BN_new(); + y = wolfSSL_BN_new(); + if (x == NULL || y == NULL) + ret = 0; + + if (ret == 1 && wolfSSL_EC_POINT_get_affine_coordinates_GFp(group, + point, x, y, NULL) != 1) { + WOLFSSL_MSG("wolfSSL_EC_POINT_get_affine_coordinates_GFp failed"); + ret = 0; + } + + /* wolfSSL_EC_POINT_set_affine_coordinates_GFp check that the point is + * on the curve. */ + if (ret == 1 && wolfSSL_EC_POINT_set_affine_coordinates_GFp(group, + point, x, y, NULL) != 1) { + WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp failed"); + ret = 0; + } +#else + WOLFSSL_MSG("Importing non-affine point. This may cause issues in math " + "operations later on."); +#endif + } + + if (ret == 1) { + /* Dump new point. */ + wolfSSL_EC_POINT_dump("d2i p", point); + } + + wolfSSL_BN_free(x); + wolfSSL_BN_free(y); + + return ret; +} + +/* Encode point as octet string. + * + * HYBRID not supported. + * + * @param [in] group EC group that point belongs to. + * @param [in] point EC point to encode. + * @param [in] form Format of encoding. Valid values: + * POINT_CONVERSION_UNCOMPRESSED,POINT_CONVERSION_COMPRESSED + * @param [out] buf Buffer to write encoding into. + * @param [in] len Length of buffer. + * @param [in] ctx Context to use for BN operations. Unused. + * @return Length of encoded data on success. + * @return 0 on error. + */ +size_t wolfSSL_EC_POINT_point2oct(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *point, int form, byte *buf, size_t len, + WOLFSSL_BN_CTX *ctx) +{ + int err = 0; + word32 enc_len = (word32)len; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + int compressed = ((form == WC_POINT_CONVERSION_COMPRESSED) ? 1 : 0); +#endif /* !HAVE_SELFTEST */ + + WOLFSSL_ENTER("wolfSSL_EC_POINT_point2oct"); + + /* No BN operations performed. */ + (void)ctx; + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL)) { + err = 1; + } + + /* Ensure points internals are set up. */ + if ((!err) && (ec_point_setup(point) != 1)) { + err = 1; + } + + /* Special case when point is infinity. */ + if ((!err) && wolfSSL_EC_POINT_is_at_infinity(group, point)) { + /* Encoding is a single octet: 0x00. */ + enc_len = 1; + if (buf != NULL) { + /* Check whether buffer has space. */ + if (len < 1) { + wolfSSL_ECerr(WOLFSSL_EC_F_EC_GFP_SIMPLE_POINT2OCT, BUFFER_E); + err = 1; + } + else { + /* Put in encoding of infinity. */ + buf[0] = 0x00; + } + } + } + /* Not infinity. */ + else if (!err) { + /* Validate format. */ + if (form != WC_POINT_CONVERSION_UNCOMPRESSED + #ifndef HAVE_SELFTEST + && form != WC_POINT_CONVERSION_COMPRESSED + #endif /* !HAVE_SELFTEST */ + ) { + WOLFSSL_MSG("Unsupported point form"); + err = 1; + } + + if (!err) { + int ret; + + #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + /* Encode as compressed or uncompressed. */ + ret = wc_ecc_export_point_der_ex(group->curve_idx, + (ecc_point*)point->internal, buf, &enc_len, compressed); + #else + /* Encode uncompressed point in DER format. */ + ret = wc_ecc_export_point_der(group->curve_idx, + (ecc_point*)point->internal, buf, &enc_len); + #endif /* !HAVE_SELFTEST */ + /* Check return. When buf is NULL, return will be length only + * error. + */ + if (ret != ((buf != NULL) ? MP_OKAY : + WC_NO_ERR_TRACE(LENGTH_ONLY_E))) { + err = 1; + } + } + } + +#if defined(DEBUG_WOLFSSL) + if (!err) { + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_point2oct point", point); + WOLFSSL_MSG("\twolfSSL_EC_POINT_point2oct output:"); + WOLFSSL_BUFFER(buf, enc_len); + } +#endif + + /* On error, return encoding length of 0. */ + if (err) { + enc_len = 0; + } + return (size_t)enc_len; +} + + +/* Convert octet string to EC point. + * + * @param [in] group EC group. + * @param [in, out] point EC point to set data into. + * @param [in] buf Buffer holding octet string. + * @param [in] len Length of data in buffer in bytes. + * @param [in] ctx Context to use for BN operations. Unused. + */ +int wolfSSL_EC_POINT_oct2point(const WOLFSSL_EC_GROUP *group, + WOLFSSL_EC_POINT *point, const unsigned char *buf, size_t len, + WOLFSSL_BN_CTX *ctx) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_oct2point"); + + /* No BN operations performed. */ + (void)ctx; + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL)) { + ret = 0; + } + else { + /* Decode DER encoding into EC point. */ + ret = wolfSSL_ECPoint_d2i((unsigned char*)buf, (unsigned int)len, group, + point); + } + + return ret; +} + +/* Convert an EC point to a single BN. + * + * @param [in] group EC group. + * @param [in] point EC point. + * @param [in] form Format of encoding. Valid values: + * WC_POINT_CONVERSION_UNCOMPRESSED, + * WC_POINT_CONVERSION_COMPRESSED. + * @param [in, out] bn BN to hold point value. + * When NULL a new BN is allocated otherwise this is + * returned on success. + * @param [in] ctx Context to use for BN operations. Unused. + * @return BN object with point as a value on success. + * @return NULL on error. + */ +WOLFSSL_BIGNUM *wolfSSL_EC_POINT_point2bn(const WOLFSSL_EC_GROUP* group, + const WOLFSSL_EC_POINT* point, int form, WOLFSSL_BIGNUM* bn, + WOLFSSL_BN_CTX* ctx) +{ + int err = 0; + size_t len = 0; + byte *buf = NULL; + WOLFSSL_BIGNUM *ret = NULL; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_oct2point"); + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL)) { + err = 1; + } + + /* Calculate length of octet encoding. */ + if ((!err) && ((len = wolfSSL_EC_POINT_point2oct(group, point, form, NULL, + 0, ctx)) == 0)) { + err = 1; + } + /* Allocate buffer to hold octet encoding. */ + if ((!err) && ((buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER)) == + NULL)) { + WOLFSSL_MSG("malloc failed"); + err = 1; + } + /* Encode EC point as an octet string. */ + if ((!err) && (wolfSSL_EC_POINT_point2oct(group, point, form, buf, len, + ctx) != len)) { + err = 1; + } + /* Load BN with octet string data. */ + if (!err) { + ret = wolfSSL_BN_bin2bn(buf, (int)len, bn); + } + + /* Dispose of any allocated data. */ + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +#if defined(USE_ECC_B_PARAM) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) +/* Check if EC point is on the the curve defined by the EC group. + * + * @param [in] group EC group defining curve. + * @param [in] point EC point to check. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 1 when point is on curve. + * @return 0 when point is not on curve or error. + */ +int wolfSSL_EC_POINT_is_on_curve(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *point, WOLFSSL_BN_CTX *ctx) +{ + int err = 0; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_is_on_curve"); + + /* No BN operations performed. */ + (void)ctx; + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL)) { + WOLFSSL_MSG("Invalid arguments"); + err = 1; + } + + /* Ensure internal EC point set. */ + if ((!err) && (!point->inSet) && ec_point_internal_set( + (WOLFSSL_EC_POINT*)point) != 1) { + WOLFSSL_MSG("ec_point_internal_set error"); + err = 1; + } + + /* Check point is on curve from group. */ + if ((!err) && (wc_ecc_point_is_on_curve((ecc_point*)point->internal, + group->curve_idx) != MP_OKAY)) { + err = 1; + } + + /* Return boolean of on curve. No error means on curve. */ + return !err; +} +#endif /* USE_ECC_B_PARAM && !HAVE_SELFTEST && !(FIPS_VERSION <= 2) */ + +#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) +/* Convert Jacobian ordinates to affine. + * + * @param [in] group EC group. + * @param [in] point EC point to get coordinates from. + * @return 1 on success. + * @return 0 on error. + */ +int ec_point_convert_to_affine(const WOLFSSL_EC_GROUP *group, + WOLFSSL_EC_POINT *point) +{ + int err = 0; + mp_digit mp = 0; + WC_DECLARE_VAR(modulus, mp_int, 1, 0); + + /* Allocate memory for curve's prime modulus. */ + WC_ALLOC_VAR_EX(modulus, mp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, err=1); + /* Initialize the MP integer. */ + if ((!err) && (mp_init(modulus) != MP_OKAY)) { + WOLFSSL_MSG("mp_init failed"); + err = 1; + } + + if (!err) { + /* Get the modulus from the hex string in the EC curve set. */ + if (mp_read_radix(modulus, ecc_sets[group->curve_idx].prime, + MP_RADIX_HEX) != MP_OKAY) { + WOLFSSL_MSG("mp_read_radix failed"); + err = 1; + } + /* Get Montgomery multiplier for the modulus as ordinates in + * Montgomery form. + */ + if ((!err) && (mp_montgomery_setup(modulus, &mp) != MP_OKAY)) { + WOLFSSL_MSG("mp_montgomery_setup failed"); + err = 1; + } + /* Map internal EC point from Jacobian to affine. */ + if ((!err) && (ecc_map((ecc_point*)point->internal, modulus, mp) != + MP_OKAY)) { + WOLFSSL_MSG("ecc_map failed"); + err = 1; + } + /* Set new ordinates into external EC point. */ + if ((!err) && (ec_point_external_set((WOLFSSL_EC_POINT *)point) != 1)) { + WOLFSSL_MSG("ec_point_external_set failed"); + err = 1; + } + + point->exSet = !err; + mp_clear(modulus); + } + + WC_FREE_VAR_EX(modulus, NULL, DYNAMIC_TYPE_BIGINT); + + return err; +} + +/* Get the affine coordinates of the EC point on a Prime curve. + * + * When z-ordinate is not one then coordinates are Jacobian and need to be + * converted to affine before storing in BNs. + * + * Return code compliant with OpenSSL. + * + * TODO: OpenSSL doesn't change point when Jacobian. Do the same? + * + * @param [in] group EC group. + * @param [in] point EC point to get coordinates from. + * @param [in, out] x BN to hold x-ordinate. + * @param [in, out] y BN to hold y-ordinate. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_EC_POINT_get_affine_coordinates_GFp(const WOLFSSL_EC_GROUP* group, + const WOLFSSL_EC_POINT* point, WOLFSSL_BIGNUM* x, WOLFSSL_BIGNUM* y, + WOLFSSL_BN_CTX* ctx) +{ + int ret = 1; + + /* BN operations don't need context. */ + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_get_affine_coordinates_GFp"); + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL) || (point->internal == NULL) || + (x == NULL) || (y == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_POINT_get_affine_coordinates_GFp NULL error"); + ret = 0; + } + /* Don't return point at infinity. */ + if ((ret == 1) && wolfSSL_EC_POINT_is_at_infinity(group, point)) { + ret = 0; + } + + /* Ensure internal EC point has values of external EC point. */ + if ((ret == 1) && (ec_point_setup(point) != 1)) { + ret = 0; + } + + /* Check whether ordinates are in Jacobian form. */ + if ((ret == 1) && (!wolfSSL_BN_is_one(point->Z))) { + /* Convert from Jacobian to affine. */ + if (ec_point_convert_to_affine(group, (WOLFSSL_EC_POINT*)point) == 1) { + ret = 0; + } + } + + /* Copy the externally set x and y ordinates. */ + if ((ret == 1) && (wolfSSL_BN_copy(x, point->X) == NULL)) { + ret = 0; + } + if ((ret == 1) && (wolfSSL_BN_copy(y, point->Y) == NULL)) { + ret = 0; + } + + return ret; +} +#endif /* !WOLFSSL_SP_MATH && !WOLF_CRYPTO_CB_ONLY_ECC */ + +/* Sets the affine coordinates that belong on a prime curve. + * + * @param [in] group EC group. + * @param [in, out] point EC point to set coordinates into. + * @param [in] x BN holding x-ordinate. + * @param [in] y BN holding y-ordinate. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_EC_POINT_set_affine_coordinates_GFp(const WOLFSSL_EC_GROUP* group, + WOLFSSL_EC_POINT* point, const WOLFSSL_BIGNUM* x, const WOLFSSL_BIGNUM* y, + WOLFSSL_BN_CTX* ctx) +{ + int ret = 1; + + /* BN operations don't need context. */ + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_set_affine_coordinates_GFp"); + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL) || (point->internal == NULL) || + (x == NULL) || (y == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_POINT_set_affine_coordinates_GFp NULL error"); + ret = 0; + } + + /* Ensure we have a object for x-ordinate. */ + if ((ret == 1) && (point->X == NULL) && + ((point->X = wolfSSL_BN_new()) == NULL)) { + WOLFSSL_MSG("wolfSSL_BN_new failed"); + ret = 0; + } + /* Ensure we have a object for y-ordinate. */ + if ((ret == 1) && (point->Y == NULL) && + ((point->Y = wolfSSL_BN_new()) == NULL)) { + WOLFSSL_MSG("wolfSSL_BN_new failed"); + ret = 0; + } + /* Ensure we have a object for z-ordinate. */ + if ((ret == 1) && (point->Z == NULL) && + ((point->Z = wolfSSL_BN_new()) == NULL)) { + WOLFSSL_MSG("wolfSSL_BN_new failed"); + ret = 0; + } + + /* Copy the x-ordinate. */ + if ((ret == 1) && ((wolfSSL_BN_copy(point->X, x)) == NULL)) { + WOLFSSL_MSG("wolfSSL_BN_copy failed"); + ret = 0; + } + /* Copy the y-ordinate. */ + if ((ret == 1) && ((wolfSSL_BN_copy(point->Y, y)) == NULL)) { + WOLFSSL_MSG("wolfSSL_BN_copy failed"); + ret = 0; + } + /* z-ordinate is one for affine coordinates. */ + if ((ret == 1) && ((wolfSSL_BN_one(point->Z)) == 0)) { + WOLFSSL_MSG("wolfSSL_BN_one failed"); + ret = 0; + } + + /* Copy the new point data to internal object. */ + if ((ret == 1) && (ec_point_internal_set((WOLFSSL_EC_POINT *)point) != 1)) { + WOLFSSL_MSG("ec_point_internal_set failed"); + ret = 0; + } + +#if defined(USE_ECC_B_PARAM) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + /* Check that the point is valid. */ + if ((ret == 1) && (wolfSSL_EC_POINT_is_on_curve(group, + (WOLFSSL_EC_POINT *)point, ctx) != 1)) { + WOLFSSL_MSG("EC_POINT_is_on_curve failed"); + ret = 0; + } +#endif + + return ret; +} + +#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \ + !defined(HAVE_SELFTEST) && !defined(WOLFSSL_SP_MATH) && \ + !defined(WOLF_CRYPTO_CB_ONLY_ECC) +/* Add two points on the same together. + * + * @param [in] curveIdx Index of curve in ecc_set. + * @param [out] r Result point. + * @param [in] p1 First point to add. + * @param [in] p2 Second point to add. + * @return 1 on success. + * @return 0 on error. + */ +static int wolfssl_ec_point_add(int curveIdx, ecc_point* r, ecc_point* p1, + ecc_point* p2) +{ + int ret = 1; +#ifdef WOLFSSL_SMALL_STACK + mp_int* a = NULL; + mp_int* prime = NULL; + mp_int* mu = NULL; +#else + mp_int a[1]; + mp_int prime[1]; + mp_int mu[1]; +#endif + mp_digit mp = 0; + ecc_point* montP1 = NULL; + ecc_point* montP2 = NULL; + +#ifdef WOLFSSL_SMALL_STACK + if (ret == 1) { + /* Allocate memory for curve parameter: a. */ + a = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); + if (a == NULL) { + WOLFSSL_MSG("Failed to allocate memory for mp_int a"); + ret = 0; + } + } + if (ret == 1) { + /* Allocate memory for curve parameter: prime. */ + prime = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); + if (prime == NULL) { + WOLFSSL_MSG("Failed to allocate memory for mp_int prime"); + ret = 0; + } + } + if (ret == 1) { + /* Allocate memory for mu (Montgomery normalizer). */ + mu = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); + if (mu == NULL) { + WOLFSSL_MSG("Failed to allocate memory for mp_int mu"); + ret = 0; + } + } + if (ret == 1) { + /* Zero out all MP int data in case initialization fails. */ + XMEMSET(a, 0, sizeof(mp_int)); + XMEMSET(prime, 0, sizeof(mp_int)); + XMEMSET(mu, 0, sizeof(mp_int)); + } +#endif + + /* Initialize the MP ints. */ + if ((ret == 1) && (mp_init_multi(prime, a, mu, NULL, NULL, NULL) != + MP_OKAY)) { + WOLFSSL_MSG("mp_init_multi error"); + ret = 0; + } + + /* Read the curve parameter: a. */ + if ((ret == 1) && (mp_read_radix(a, ecc_sets[curveIdx].Af, MP_RADIX_HEX) != + MP_OKAY)) { + WOLFSSL_MSG("mp_read_radix a error"); + ret = 0; + } + + /* Read the curve parameter: prime. */ + if ((ret == 1) && (mp_read_radix(prime, ecc_sets[curveIdx].prime, + MP_RADIX_HEX) != MP_OKAY)) { + WOLFSSL_MSG("mp_read_radix prime error"); + ret = 0; + } + + /* Calculate the Montgomery product. */ + if ((ret == 1) && (mp_montgomery_setup(prime, &mp) != MP_OKAY)) { + WOLFSSL_MSG("mp_montgomery_setup nqm error"); + ret = 0; + } + + /* TODO: use the heap filed of one of the points? */ + /* Allocate new points to hold the Montgomery form values. */ + if ((ret == 1) && (((montP1 = wc_ecc_new_point_h(NULL)) == NULL) || + ((montP2 = wc_ecc_new_point_h(NULL)) == NULL))) { + WOLFSSL_MSG("wc_ecc_new_point_h nqm error"); + ret = 0; + } + + /* Calculate the Montgomery normalizer. */ + if ((ret == 1) && (mp_montgomery_calc_normalization(mu, prime) != + MP_OKAY)) { + WOLFSSL_MSG("mp_montgomery_calc_normalization error"); + ret = 0; + } + + /* Convert to Montgomery form. */ + if ((ret == 1) && (mp_cmp_d(mu, 1) == MP_EQ)) { + /* Copy the points if the normalizer is 1. */ + if ((wc_ecc_copy_point(p1, montP1) != MP_OKAY) || + (wc_ecc_copy_point(p2, montP2) != MP_OKAY)) { + WOLFSSL_MSG("wc_ecc_copy_point error"); + ret = 0; + } + } + else if (ret == 1) { + /* Multiply each ordinate by the Montgomery normalizer. */ + if ((mp_mulmod(p1->x, mu, prime, montP1->x) != MP_OKAY) || + (mp_mulmod(p1->y, mu, prime, montP1->y) != MP_OKAY) || + (mp_mulmod(p1->z, mu, prime, montP1->z) != MP_OKAY)) { + WOLFSSL_MSG("mp_mulmod error"); + ret = 0; + } + /* Multiply each ordinate by the Montgomery normalizer. */ + if ((mp_mulmod(p2->x, mu, prime, montP2->x) != MP_OKAY) || + (mp_mulmod(p2->y, mu, prime, montP2->y) != MP_OKAY) || + (mp_mulmod(p2->z, mu, prime, montP2->z) != MP_OKAY)) { + WOLFSSL_MSG("mp_mulmod error"); + ret = 0; + } + } + + /* Perform point addition with internal EC point objects - Jacobian form + * result. + */ + if ((ret == 1) && (ecc_projective_add_point(montP1, montP2, r, a, prime, + mp) != MP_OKAY)) { + WOLFSSL_MSG("ecc_projective_add_point error"); + ret = 0; + } + + /* Map point back to affine coordinates. Converts from Montogomery form. */ + if ((ret == 1) && (ecc_map(r, prime, mp) != MP_OKAY)) { + WOLFSSL_MSG("ecc_map error"); + ret = 0; + } + + /* Dispose of allocated memory. */ + mp_clear(a); + mp_clear(prime); + mp_clear(mu); + wc_ecc_del_point_h(montP1, NULL); + wc_ecc_del_point_h(montP2, NULL); + WC_FREE_VAR_EX(a, NULL, DYNAMIC_TYPE_BIGINT); + WC_FREE_VAR_EX(prime, NULL, DYNAMIC_TYPE_BIGINT); + WC_FREE_VAR_EX(mu, NULL, DYNAMIC_TYPE_BIGINT); + return ret; +} + +/* Add two points on the same curve together. + * + * @param [in] group EC group. + * @param [out] r EC point that is result of point addition. + * @param [in] p1 First EC point to add. + * @param [in] p2 Second EC point to add. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_EC_POINT_add(const WOLFSSL_EC_GROUP* group, WOLFSSL_EC_POINT* r, + const WOLFSSL_EC_POINT* p1, const WOLFSSL_EC_POINT* p2, WOLFSSL_BN_CTX* ctx) +{ + int ret = 1; + + /* No BN operations performed. */ + (void)ctx; + + /* Validate parameters. */ + if ((group == NULL) || (r == NULL) || (p1 == NULL) || (p2 == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_POINT_add error"); + ret = 0; + } + + /* Ensure the internal objects of the EC points are setup. */ + if ((ret == 1) && ((ec_point_setup(r) != 1) || (ec_point_setup(p1) != 1) || + (ec_point_setup(p2) != 1))) { + WOLFSSL_MSG("ec_point_setup error"); + ret = 0; + } + +#ifdef DEBUG_WOLFSSL + if (ret == 1) { + int nid = wolfSSL_EC_GROUP_get_curve_name(group); + const char* curve = wolfSSL_OBJ_nid2ln(nid); + const char* nistName = wolfSSL_EC_curve_nid2nist(nid); + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_add p1", p1); + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_add p2", p2); + if (curve != NULL) + WOLFSSL_MSG_EX("curve name: %s", curve); + if (nistName != NULL) + WOLFSSL_MSG_EX("nist curve name: %s", nistName); + } +#endif + + if (ret == 1) { + /* Add points using wolfCrypt objects. */ + ret = wolfssl_ec_point_add(group->curve_idx, (ecc_point*)r->internal, + (ecc_point*)p1->internal, (ecc_point*)p2->internal); + } + + /* Copy internal EC point values out to external EC point. */ + if ((ret == 1) && (ec_point_external_set(r) != 1)) { + WOLFSSL_MSG("ec_point_external_set error"); + ret = 0; + } + +#ifdef DEBUG_WOLFSSL + if (ret == 1) { + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_add result", r); + } +#endif + + return ret; +} + +/* Sum the scalar multiplications of the base point and n, and q and m. + * + * r = base point * n + q * m + * + * @param [out] r EC point that is result of operation. + * @param [in] b Base point of curve. + * @param [in] n Scalar to multiply by base point. + * @param [in] q EC point to be scalar multiplied. + * @param [in] m Scalar to multiply q by. + * @param [in] a Parameter A of curve. + * @param [in] prime Prime (modulus) of curve. + * @return 1 on success. + * @return 0 on error. + */ +static int ec_mul2add(ecc_point* r, ecc_point* b, mp_int* n, ecc_point* q, + mp_int* m, mp_int* a, mp_int* prime) +{ + int ret = 1; +#if defined(ECC_SHAMIR) && !defined(WOLFSSL_KCAPI_ECC) + if (ecc_mul2add(b, n, q, m, r, a, prime, NULL) != MP_OKAY) { + WOLFSSL_MSG("ecc_mul2add error"); + ret = 0; + } +#else + ecc_point* tmp = NULL; + mp_digit mp = 0; + + /* Calculate Montgomery product. */ + if (mp_montgomery_setup(prime, &mp) != MP_OKAY) { + WOLFSSL_MSG("mp_montgomery_setup nqm error"); + ret = 0; + } + /* Create temporary point to hold: q * m */ + if ((ret == 1) && ((tmp = wc_ecc_new_point()) == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_POINT_new nqm error"); + ret = 0; + } + /* r = base point * n */ + if ((ret == 1) && (wc_ecc_mulmod(n, b, r, a, prime, 0) != + MP_OKAY)) { + WOLFSSL_MSG("wc_ecc_mulmod nqm error"); + ret = 0; + } + /* tmp = q * m */ + if ((ret == 1) && (wc_ecc_mulmod(m, q, tmp, a, prime, 0) != MP_OKAY)) { + WOLFSSL_MSG("wc_ecc_mulmod nqm error"); + ret = 0; + } + /* r = r + tmp */ + if ((ret == 1) && (ecc_projective_add_point(tmp, r, r, a, prime, mp) != + MP_OKAY)) { + WOLFSSL_MSG("wc_ecc_mulmod nqm error"); + ret = 0; + } + /* Map point back to affine coordinates. Converts from Montogomery + * form. */ + if ((ret == 1) && (ecc_map(r, prime, mp) != MP_OKAY)) { + WOLFSSL_MSG("ecc_map nqm error"); + ret = 0; + } + + /* Dispose of allocated temporary point. */ + wc_ecc_del_point(tmp); +#endif + + return ret; +} + +/* Sum the scalar multiplications of the base point and n, and q and m. + * + * r = base point * n + q * m + * + * @param [in] curveIdx Index of curve in ecc_set. + * @param [out] r EC point that is result of operation. + * @param [in] n Scalar to multiply by base point. May be NULL. + * @param [in] q EC point to be scalar multiplied. May be NULL. + * @param [in] m Scalar to multiply q by. May be NULL. + * @return 1 on success. + * @return 0 on error. + */ +static int wolfssl_ec_point_mul(int curveIdx, ecc_point* r, mp_int* n, + ecc_point* q, mp_int* m) +{ + int ret = 1; +#ifdef WOLFSSL_SMALL_STACK + mp_int* a = NULL; + mp_int* prime = NULL; +#else + mp_int a[1], prime[1]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + /* Allocate MP integer for curve parameter: a. */ + a = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); + if (a == NULL) { + ret = 0; + } + if (ret == 1) { + /* Allocate MP integer for curve parameter: prime. */ + prime = (mp_int*)XMALLOC(sizeof(mp_int), NULL, DYNAMIC_TYPE_BIGINT); + if (prime == NULL) { + ret = 0; + } + } +#endif + + /* Initialize the MP ints. */ + if ((ret == 1) && (mp_init_multi(prime, a, NULL, NULL, NULL, NULL) != + MP_OKAY)) { + WOLFSSL_MSG("mp_init_multi error"); + ret = 0; + } + + /* Read the curve parameter: prime. */ + if ((ret == 1) && (mp_read_radix(prime, ecc_sets[curveIdx].prime, + MP_RADIX_HEX) != MP_OKAY)) { + WOLFSSL_MSG("mp_read_radix prime error"); + ret = 0; + } + + /* Read the curve parameter: a. */ + if ((ret == 1) && (mp_read_radix(a, ecc_sets[curveIdx].Af, + MP_RADIX_HEX) != MP_OKAY)) { + WOLFSSL_MSG("mp_read_radix a error"); + ret = 0; + } + + if ((ret == 1) && (n != NULL)) { + /* Get generator - base point. */ + #if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) + if ((ret == 1) && (wc_ecc_get_generator(r, curveIdx) != MP_OKAY)) { + WOLFSSL_MSG("wc_ecc_get_generator error"); + ret = 0; + } + #else + /* wc_ecc_get_generator is not defined in the FIPS v2 module. */ + /* Read generator (base point) x-ordinate. */ + if ((ret == 1) && (mp_read_radix(r->x, ecc_sets[curveIdx].Gx, + MP_RADIX_HEX) != MP_OKAY)) { + WOLFSSL_MSG("mp_read_radix Gx error"); + ret = 0; + } + /* Read generator (base point) y-ordinate. */ + if ((ret == 1) && (mp_read_radix(r->y, ecc_sets[curveIdx].Gy, + MP_RADIX_HEX) != MP_OKAY)) { + WOLFSSL_MSG("mp_read_radix Gy error"); + ret = 0; + } + /* z-ordinate is one as point is affine. */ + if ((ret == 1) && (mp_set(r->z, 1) != MP_OKAY)) { + WOLFSSL_MSG("mp_set Gz error"); + ret = 0; + } + #endif /* NOPT_FIPS_VERSION == 2 */ + } + + if ((ret == 1) && (n != NULL) && (q != NULL) && (m != NULL)) { + /* r = base point * n + q * m */ + ret = ec_mul2add(r, r, n, q, m, a, prime); + } + /* Not all values present, see if we are only doing base point * n. */ + else if ((ret == 1) && (n != NULL)) { + /* r = base point * n */ + if (wc_ecc_mulmod(n, r, r, a, prime, 1) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_mulmod gn error"); + ret = 0; + } + } + /* Not all values present, see if we are only doing q * m. */ + else if ((ret == 1) && (q != NULL) && (m != NULL)) { + /* r = q * m */ + if (wc_ecc_mulmod(m, q, r, a, prime, 1) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_mulmod qm error"); + ret = 0; + } + } + /* No values to use. */ + else if (ret == 1) { + /* Set result to infinity as no values passed in. */ + mp_zero(r->x); + mp_zero(r->y); + mp_zero(r->z); + } + + mp_clear(a); + mp_clear(prime); + WC_FREE_VAR_EX(a, NULL, DYNAMIC_TYPE_BIGINT); + WC_FREE_VAR_EX(prime, NULL, DYNAMIC_TYPE_BIGINT); + return ret; +} + +/* Sum the scalar multiplications of the base point and n, and q and m. + * + * r = base point * n + q * m + * + * Return code compliant with OpenSSL. + * + * @param [in] group EC group. + * @param [out] r EC point that is result of operation. + * @param [in] n Scalar to multiply by base point. May be NULL. + * @param [in] q EC point to be scalar multiplied. May be NULL. + * @param [in] m Scalar to multiply q by. May be NULL. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_EC_POINT_mul(const WOLFSSL_EC_GROUP *group, WOLFSSL_EC_POINT *r, + const WOLFSSL_BIGNUM *n, const WOLFSSL_EC_POINT *q, const WOLFSSL_BIGNUM *m, + WOLFSSL_BN_CTX *ctx) +{ + int ret = 1; + + /* No BN operations performed. */ + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_mul"); + + /* Validate parameters. */ + if ((group == NULL) || (r == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_POINT_mul NULL error"); + ret = 0; + } + + /* Ensure the internal representation of the EC point q is setup. */ + if ((ret == 1) && (q != NULL) && (ec_point_setup(q) != 1)) { + WOLFSSL_MSG("ec_point_setup error"); + ret = 0; + } + +#ifdef DEBUG_WOLFSSL + if (ret == 1) { + int nid = wolfSSL_EC_GROUP_get_curve_name(group); + const char* curve = wolfSSL_OBJ_nid2ln(nid); + const char* nistName = wolfSSL_EC_curve_nid2nist(nid); + char* num; + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_mul input q", q); + num = wolfSSL_BN_bn2hex(n); + WOLFSSL_MSG_EX("\tn = %s", num); + XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); + num = wolfSSL_BN_bn2hex(m); + WOLFSSL_MSG_EX("\tm = %s", num); + XFREE(num, NULL, DYNAMIC_TYPE_OPENSSL); + if (curve != NULL) + WOLFSSL_MSG_EX("curve name: %s", curve); + if (nistName != NULL) + WOLFSSL_MSG_EX("nist curve name: %s", nistName); + } +#endif + + if (ret == 1) { + mp_int* ni = (n != NULL) ? (mp_int*)n->internal : NULL; + ecc_point* qi = (q != NULL) ? (ecc_point*)q->internal : NULL; + mp_int* mi = (m != NULL) ? (mp_int*)m->internal : NULL; + + /* Perform multiplication with wolfCrypt objects. */ + ret = wolfssl_ec_point_mul(group->curve_idx, (ecc_point*)r->internal, + ni, qi, mi); + } + + /* Only on success is the internal point guaranteed to be set. */ + if (r != NULL) { + r->inSet = (ret == 1); + } + /* Copy internal EC point values out to external EC point. */ + if ((ret == 1) && (ec_point_external_set(r) != 1)) { + WOLFSSL_MSG("ec_point_external_set error"); + ret = 0; + } + +#ifdef DEBUG_WOLFSSL + if (ret == 1) { + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_mul result", r); + } +#endif + + return ret; +} +#endif /* !WOLFSSL_ATECC508A && !WOLFSSL_ATECC608A && !HAVE_SELFTEST && + * !WOLFSSL_SP_MATH */ + +/* Invert the point on the curve. + * (x, y) -> (x, -y) = (x, (prime - y) % prime) + * + * @param [in] curveIdx Index of curve in ecc_set. + * @param [in, out] point EC point to invert. + * @return 1 on success. + * @return 0 on error. + */ +static int wolfssl_ec_point_invert(int curveIdx, ecc_point* point) +{ + int ret = 1; + WC_DECLARE_VAR(prime, mp_int, 1, 0); + + /* Allocate memory for an MP int to hold the prime of the curve. */ + WC_ALLOC_VAR_EX(prime, mp_int, 1, NULL, DYNAMIC_TYPE_BIGINT, ret=0); + + /* Initialize MP int. */ + if ((ret == 1) && (mp_init(prime) != MP_OKAY)) { + WOLFSSL_MSG("mp_init_multi error"); + ret = 0; + } + + /* Read the curve parameter: prime. */ + if ((ret == 1) && (mp_read_radix(prime, ecc_sets[curveIdx].prime, + MP_RADIX_HEX) != MP_OKAY)) { + WOLFSSL_MSG("mp_read_radix prime error"); + ret = 0; + } + + /* y = (prime - y) mod prime. */ + if ((ret == 1) && (!mp_iszero(point->y)) && (mp_sub(prime, point->y, + point->y) != MP_OKAY)) { + WOLFSSL_MSG("mp_sub error"); + ret = 0; + } + + /* Dispose of memory associated with MP. */ + mp_free(prime); + WC_FREE_VAR_EX(prime, NULL, DYNAMIC_TYPE_BIGINT); + return ret; +} + +/* Invert the point on the curve. + * (x, y) -> (x, -y) = (x, (prime - y) % prime) + * + * @param [in] group EC group. + * @param [in, out] point EC point to invert. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_EC_POINT_invert(const WOLFSSL_EC_GROUP *group, + WOLFSSL_EC_POINT *point, WOLFSSL_BN_CTX *ctx) +{ + int ret = 1; + + /* No BN operations performed. */ + (void)ctx; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_invert"); + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL) || (point->internal == NULL)) { + ret = 0; + } + + /* Ensure internal representation of point is setup. */ + if ((ret == 1) && (ec_point_setup(point) != 1)) { + ret = 0; + } + +#ifdef DEBUG_WOLFSSL + if (ret == 1) { + int nid = wolfSSL_EC_GROUP_get_curve_name(group); + const char* curve = wolfSSL_OBJ_nid2ln(nid); + const char* nistName = wolfSSL_EC_curve_nid2nist(nid); + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_invert input", point); + if (curve != NULL) + WOLFSSL_MSG_EX("curve name: %s", curve); + if (nistName != NULL) + WOLFSSL_MSG_EX("nist curve name: %s", nistName); + + } +#endif + + if (ret == 1 && !wolfSSL_BN_is_one(point->Z)) { +#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) + if (ec_point_convert_to_affine(group, point) != 0) + ret = 0; +#else + WOLFSSL_MSG("wolfSSL_EC_POINT_invert called on non-affine point"); + ret = 0; +#endif + } + + if (ret == 1) { + /* Perform inversion using wolfCrypt objects. */ + ret = wolfssl_ec_point_invert(group->curve_idx, + (ecc_point*)point->internal); + } + + /* Set the external EC point representation based on internal. */ + if ((ret == 1) && (ec_point_external_set(point) != 1)) { + WOLFSSL_MSG("ec_point_external_set error"); + ret = 0; + } + +#ifdef DEBUG_WOLFSSL + if (ret == 1) { + wolfSSL_EC_POINT_dump("wolfSSL_EC_POINT_invert result", point); + } +#endif + + return ret; +} + +#ifdef WOLFSSL_EC_POINT_CMP_JACOBIAN +/* Compare two points on a the same curve. + * + * (Ax, Ay, Az) => (Ax / (Az ^ 2), Ay / (Az ^ 3)) + * (Bx, By, Bz) => (Bx / (Bz ^ 2), By / (Bz ^ 3)) + * When equal: + * (Ax / (Az ^ 2), Ay / (Az ^ 3)) = (Bx / (Bz ^ 2), By / (Bz ^ 3)) + * => (Ax * (Bz ^ 2), Ay * (Bz ^ 3)) = (Bx * (Az ^ 2), By * (Az ^ 3)) + * + * @param [in] group EC group. + * @param [in] a EC point to compare. + * @param [in] b EC point to compare. + * @return 0 when equal. + * @return 1 when different. + * @return -1 on error. + */ +static int ec_point_cmp_jacobian(const WOLFSSL_EC_GROUP* group, + const WOLFSSL_EC_POINT *a, const WOLFSSL_EC_POINT *b, WOLFSSL_BN_CTX *ctx) +{ + int ret = 0; + BIGNUM* at = BN_new(); + BIGNUM* bt = BN_new(); + BIGNUM* az = BN_new(); + BIGNUM* bz = BN_new(); + BIGNUM* mod = BN_new(); + + /* Check that the big numbers were allocated. */ + if ((at == NULL) || (bt == NULL) || (az == NULL) || (bz == NULL) || + (mod == NULL)) { + ret = WOLFSSL_FATAL_ERROR; + } + /* Get the modulus for the curve. */ + if ((ret == 0) && + (BN_hex2bn(&mod, ecc_sets[group->curve_idx].prime) != 1)) { + ret = WOLFSSL_FATAL_ERROR; + } + if (ret == 0) { + /* bt = Bx * (Az ^ 2). When Az is one then just copy. */ + if (BN_is_one(a->Z)) { + if (BN_copy(bt, b->X) == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } + /* az = Az ^ 2 */ + else if ((BN_mod_mul(az, a->Z, a->Z, mod, ctx) != 1)) { + ret = WOLFSSL_FATAL_ERROR; + } + /* bt = Bx * az = Bx * (Az ^ 2) */ + else if (BN_mod_mul(bt, b->X, az, mod, ctx) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 0) { + /* at = Ax * (Bz ^ 2). When Bz is one then just copy. */ + if (BN_is_one(b->Z)) { + if (BN_copy(at, a->X) == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } + /* bz = Bz ^ 2 */ + else if (BN_mod_mul(bz, b->Z, b->Z, mod, ctx) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } + /* at = Ax * bz = Ax * (Bz ^ 2) */ + else if (BN_mod_mul(at, a->X, bz, mod, ctx) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } + } + /* Compare x-ordinates. */ + if ((ret == 0) && (BN_cmp(at, bt) != 0)) { + ret = 1; + } + if (ret == 0) { + /* bt = By * (Az ^ 3). When Az is one then just copy. */ + if (BN_is_one(a->Z)) { + if (BN_copy(bt, b->Y) == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } + /* az = az * Az = Az ^ 3 */ + else if ((BN_mod_mul(az, az, a->Z, mod, ctx) != 1)) { + ret = WOLFSSL_FATAL_ERROR; + } + /* bt = By * az = By * (Az ^ 3) */ + else if (BN_mod_mul(bt, b->Y, az, mod, ctx) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 0) { + /* at = Ay * (Bz ^ 3). When Bz is one then just copy. */ + if (BN_is_one(b->Z)) { + if (BN_copy(at, a->Y) == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } + /* bz = bz * Bz = Bz ^ 3 */ + else if (BN_mod_mul(bz, bz, b->Z, mod, ctx) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } + /* at = Ay * bz = Ay * (Bz ^ 3) */ + else if (BN_mod_mul(at, a->Y, bz, mod, ctx) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } + } + /* Compare y-ordinates. */ + if ((ret == 0) && (BN_cmp(at, bt) != 0)) { + ret = 1; + } + + BN_free(mod); + BN_free(bz); + BN_free(az); + BN_free(bt); + BN_free(at); + return ret; +} +#endif + +/* Compare two points on a the same curve. + * + * Return code compliant with OpenSSL. + * + * @param [in] group EC group. + * @param [in] a EC point to compare. + * @param [in] b EC point to compare. + * @param [in] ctx Context to use for BN operations. Unused. + * @return 0 when equal. + * @return 1 when different. + * @return -1 on error. + */ +int wolfSSL_EC_POINT_cmp(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *a, const WOLFSSL_EC_POINT *b, WOLFSSL_BN_CTX *ctx) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_cmp"); + + /* Validate parameters. */ + if ((group == NULL) || (a == NULL) || (a->internal == NULL) || + (b == NULL) || (b->internal == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_POINT_cmp Bad arguments"); + ret = WOLFSSL_FATAL_ERROR; + } + if (ret != -1) { + #ifdef WOLFSSL_EC_POINT_CMP_JACOBIAN + /* If same Z ordinate then no need to convert to affine. */ + if (BN_cmp(a->Z, b->Z) == 0) { + /* Compare */ + ret = ((BN_cmp(a->X, b->X) != 0) || (BN_cmp(a->Y, b->Y) != 0)); + } + else { + ret = ec_point_cmp_jacobian(group, a, b, ctx); + } + #else + /* No BN operations performed. */ + (void)ctx; + + ret = (wc_ecc_cmp_point((ecc_point*)a->internal, + (ecc_point*)b->internal) != MP_EQ); + #endif + } + + return ret; +} + +/* Copy EC point. + * + * @param [out] dest EC point to copy into. + * @param [in] src EC point to copy. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_EC_POINT_copy(WOLFSSL_EC_POINT *dest, const WOLFSSL_EC_POINT *src) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_copy"); + + /* Validate parameters. */ + if ((dest == NULL) || (src == NULL)) { + ret = 0; + } + + /* Ensure internal EC point of src is setup. */ + if ((ret == 1) && (ec_point_setup(src) != 1)) { + ret = 0; + } + + /* Copy internal EC points. */ + if ((ret == 1) && (wc_ecc_copy_point((ecc_point*)src->internal, + (ecc_point*)dest->internal) != MP_OKAY)) { + ret = 0; + } + + if (ret == 1) { + /* Destinatation internal point is set. */ + dest->inSet = 1; + + /* Set the external EC point of dest based on internal. */ + if (ec_point_external_set(dest) != 1) { + ret = 0; + } + } + + return ret; +} + +/* Checks whether point is at infinity. + * + * Return code compliant with OpenSSL. + * + * @param [in] group EC group. + * @param [in] point EC point to check. + * @return 1 when at infinity. + * @return 0 when not at infinity. + */ +int wolfSSL_EC_POINT_is_at_infinity(const WOLFSSL_EC_GROUP *group, + const WOLFSSL_EC_POINT *point) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_EC_POINT_is_at_infinity"); + + /* Validate parameters. */ + if ((group == NULL) || (point == NULL) || (point->internal == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_POINT_is_at_infinity NULL error"); + ret = 0; + } + + /* Ensure internal EC point is setup. */ + if ((ret == 1) && (ec_point_setup(point) != 1)) { + ret = 0; + } + if (ret == 1) { + #ifndef WOLF_CRYPTO_CB_ONLY_ECC + /* Check for infinity. */ + ret = wc_ecc_point_is_at_infinity((ecc_point*)point->internal); + if (ret < 0) { + WOLFSSL_MSG("ecc_point_is_at_infinity failure"); + /* Error return is 0 by OpenSSL. */ + ret = 0; + } + #else + WOLFSSL_MSG("ecc_point_is_at_infinitiy compiled out"); + ret = 0; + #endif + } + + return ret; +} + +#endif /* OPENSSL_EXTRA */ + +/* End EC_POINT */ + +/* Start EC_KEY */ + +#ifdef OPENSSL_EXTRA + +/* + * EC key constructor/deconstructor APIs + */ + +/* Allocate a new EC key. + * + * Not OpenSSL API. + * + * @param [in] heap Heap hint for dynamic memory allocation. + * @param [in] devId Device identifier value. + * @return New, allocated EC key on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new_ex(void* heap, int devId) +{ + WOLFSSL_EC_KEY *key = NULL; + int err = 0; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_new"); + + /* Allocate memory for EC key. */ + key = (WOLFSSL_EC_KEY*)XMALLOC(sizeof(WOLFSSL_EC_KEY), heap, + DYNAMIC_TYPE_ECC); + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc WOLFSSL_EC_KEY failure"); + err = 1; + } + if (!err) { + /* Reset all fields to 0. */ + XMEMSET(key, 0, sizeof(WOLFSSL_EC_KEY)); + /* Cache heap hint. */ + key->heap = heap; + /* Initialize fields to defaults. */ + key->form = WC_POINT_CONVERSION_UNCOMPRESSED; + + /* Initialize reference count. */ + wolfSSL_RefInit(&key->ref, &err); +#ifdef WOLFSSL_REFCNT_ERROR_RETURN + } + if (!err) { +#endif + /* Allocate memory for internal EC key representation. */ + key->internal = (ecc_key*)XMALLOC(sizeof(ecc_key), heap, + DYNAMIC_TYPE_ECC); + if (key->internal == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc ecc key failure"); + err = 1; + } + } + if (!err) { + /* Initialize wolfCrypt EC key. */ + if (wc_ecc_init_ex((ecc_key*)key->internal, heap, devId) != 0) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new init ecc key failure"); + err = 1; + } + } + + if (!err) { + /* Group unknown at creation */ + key->group = wolfSSL_EC_GROUP_new_by_curve_name(WC_NID_undef); + if (key->group == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new malloc WOLFSSL_EC_GROUP failure"); + err = 1; + } + } + + if (!err) { + /* Allocate a point as public key. */ + key->pub_key = wolfSSL_EC_POINT_new(key->group); + if (key->pub_key == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_new failure"); + err = 1; + } + } + + if (!err) { + /* Allocate a BN as private key. */ + key->priv_key = wolfSSL_BN_new(); + if (key->priv_key == NULL) { + WOLFSSL_MSG("wolfSSL_BN_new failure"); + err = 1; + } + } + + if (err) { + /* Dispose of EC key on error. */ + wolfSSL_EC_KEY_free(key); + key = NULL; + } + /* Return new EC key object. */ + return key; +} + +/* Allocate a new EC key. + * + * @return New, allocated EC key on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new(void) +{ + return wolfSSL_EC_KEY_new_ex(NULL, INVALID_DEVID); +} + +/* Create new EC key with the group having the specified numeric ID. + * + * @param [in] nid Numeric ID. + * @return New, allocated EC key on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY *wolfSSL_EC_KEY_new_by_curve_name(int nid) +{ + WOLFSSL_EC_KEY *key; + int err = 0; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_new_by_curve_name"); + + /* Allocate empty, EC key. */ + key = wolfSSL_EC_KEY_new(); + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new failure"); + err = 1; + } + + if (!err) { + /* Set group to be nid. */ + ec_group_set_nid(key->group, nid); + if (key->group->curve_idx == -1) { + wolfSSL_EC_KEY_free(key); + key = NULL; + } + } + + /* Return the new EC key object. */ + return key; +} + +/* Dispose of the EC key and allocated data. + * + * Cannot use key after this call. + * + * @param [in] key EC key to free. + */ +void wolfSSL_EC_KEY_free(WOLFSSL_EC_KEY *key) +{ + int doFree = 0; + int err; + + (void)err; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_free"); + + if (key != NULL) { + void* heap = key->heap; + + /* Decrement reference count. */ + wolfSSL_RefDec(&key->ref, &doFree, &err); + if (doFree) { + /* Dispose of allocated reference counting data. */ + wolfSSL_RefFree(&key->ref); + + /* Dispose of private key. */ + wolfSSL_BN_free(key->priv_key); + wolfSSL_EC_POINT_free(key->pub_key); + wolfSSL_EC_GROUP_free(key->group); + if (key->internal != NULL) { + /* Dispose of wolfCrypt representation of EC key. */ + wc_ecc_free((ecc_key*)key->internal); + XFREE(key->internal, heap, DYNAMIC_TYPE_ECC); + } + + /* Set back to NULLs for safety. */ + ForceZero(key, sizeof(*key)); + + /* Dispose of the memory associated with the EC key. */ + XFREE(key, heap, DYNAMIC_TYPE_ECC); + (void)heap; + } + } +} + +/* Increments ref count of EC key. + * + * @param [in, out] key EC key. + * @return 1 on success + * @return 0 on error + */ +int wolfSSL_EC_KEY_up_ref(WOLFSSL_EC_KEY* key) +{ + int err = 1; + + if (key != NULL) { + wolfSSL_RefInc(&key->ref, &err); + } + + return !err; +} + +#ifndef NO_CERTS + +#if defined(OPENSSL_ALL) +/* Copy the internal, wolfCrypt EC key. + * + * @param [in, out] dst Destination wolfCrypt EC key. + * @param [in] src Source wolfCrypt EC key. + * @return 0 on success. + * @return Negative on error. + */ +static int wolfssl_ec_key_int_copy(ecc_key* dst, const ecc_key* src) +{ + int ret; + + /* Copy public key. */ +#if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) + ret = wc_ecc_copy_point(&src->pubkey, &dst->pubkey); +#else + ret = wc_ecc_copy_point((ecc_point*)&src->pubkey, &dst->pubkey); +#endif + if (ret != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_copy_point error"); + } + + if (ret == 0) { + /* Copy private key. */ + ret = mp_copy(wc_ecc_key_get_priv((ecc_key*)src), + wc_ecc_key_get_priv(dst)); + if (ret != MP_OKAY) { + WOLFSSL_MSG("mp_copy error"); + } + } + + if (ret == 0) { + /* Copy domain parameters. */ + if (src->dp) { + ret = wc_ecc_set_curve(dst, 0, src->dp->id); + if (ret != 0) { + WOLFSSL_MSG("wc_ecc_set_curve error"); + } + } + } + + if (ret == 0) { + /* Copy the other components. */ + dst->type = src->type; + dst->idx = src->idx; + dst->state = src->state; + dst->flags = src->flags; + } + + return ret; +} + +/* Copies ecc_key into new WOLFSSL_EC_KEY object + * + * Copies the internal representation as well. + * + * @param [in] src EC key to duplicate. + * + * @return EC key on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY *wolfSSL_EC_KEY_dup(const WOLFSSL_EC_KEY *src) +{ + int err = 0; + WOLFSSL_EC_KEY* newKey = NULL; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_dup"); + + /* Validate EC key. */ + if ((src == NULL) || (src->internal == NULL) || (src->group == NULL) || + (src->pub_key == NULL) || (src->priv_key == NULL)) { + WOLFSSL_MSG("src NULL error"); + err = 1; + } + + if (!err) { + /* Create a new, empty key. */ + newKey = wolfSSL_EC_KEY_new(); + if (newKey == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new error"); + err = 1; + } + } + + if (!err) { + /* Copy internal EC key. */ + if (wolfssl_ec_key_int_copy((ecc_key*)newKey->internal, + (ecc_key*)src->internal) != 0) { + WOLFSSL_MSG("Copying internal EC key error"); + err = 1; + } + } + if (!err) { + /* Internal key set. */ + newKey->inSet = 1; + + /* Copy group */ + err = wolfssl_ec_group_copy(newKey->group, src->group); + } + /* Copy public key. */ + if ((!err) && (wolfSSL_EC_POINT_copy(newKey->pub_key, src->pub_key) != 1)) { + WOLFSSL_MSG("Copying EC public key error"); + err = 1; + } + + if (!err) { + /* Set header size of private key in PKCS#8 format.*/ + newKey->pkcs8HeaderSz = src->pkcs8HeaderSz; + + /* Copy private key. */ + if (wolfSSL_BN_copy(newKey->priv_key, src->priv_key) == NULL) { + WOLFSSL_MSG("Copying EC private key error"); + err = 1; + } + } + + if (err) { + /* Dispose of EC key on error. */ + wolfSSL_EC_KEY_free(newKey); + newKey = NULL; + } + /* Return the new EC key. */ + return newKey; +} + +#endif /* OPENSSL_ALL */ + +#endif /* !NO_CERTS */ + +/* + * EC key to/from bin/octet APIs + */ + +/* Create an EC key from the octet encoded public key. + * + * Behaviour checked against OpenSSL. + * + * @param [out] key Reference to EC key. Must pass in a valid object with + * group set. + * @param [in, out] in On in, reference to buffer that contains data. + * On out, reference to buffer after public key data. + * @param [in] len Length of data in the buffer. Must be length of the + * encoded public key. + * @return Allocated EC key on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY *wolfSSL_o2i_ECPublicKey(WOLFSSL_EC_KEY **key, + const unsigned char **in, long len) +{ + int err = 0; + WOLFSSL_EC_KEY* ret = NULL; + + WOLFSSL_ENTER("wolfSSL_o2i_ECPublicKey"); + + /* Validate parameters: EC group needed to perform import. */ + if ((key == NULL) || (*key == NULL) || ((*key)->group == NULL) || + (in == NULL) || (*in == NULL) || (len <= 0)) { + WOLFSSL_MSG("wolfSSL_o2i_ECPublicKey Bad arguments"); + err = 1; + } + + if (!err) { + /* Return the EC key object passed in. */ + ret = *key; + + /* Import point into public key field. */ + if (wolfSSL_EC_POINT_oct2point(ret->group, ret->pub_key, *in, + (size_t)len, NULL) != 1) { + WOLFSSL_MSG("wolfSSL_EC_POINT_oct2point error"); + ret = NULL; + err = 1; + } + } + if (!err) { + /* Assumed length passed in is all the data. */ + *in += len; + } + + return ret; +} + +/* Puts the encoded public key into out. + * + * Passing in NULL for out returns length only. + * Passing in NULL for *out has buffer allocated, encoded into and passed back. + * Passing non-NULL for *out has it encoded into and pointer moved past. + * + * @param [in] key EC key to encode. + * @param [in, out] out Reference to buffer to encode into. May be NULL or + * point to NULL. + * @return Length of encoding in bytes on success. + * @return 0 on error. + */ +int wolfSSL_i2o_ECPublicKey(const WOLFSSL_EC_KEY *key, unsigned char **out) +{ + int ret = 1; + size_t len = 0; + int form = WC_POINT_CONVERSION_UNCOMPRESSED; + + WOLFSSL_ENTER("wolfSSL_i2o_ECPublicKey"); + + /* Validate parameters. */ + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_i2o_ECPublicKey Bad arguments"); + ret = 0; + } + + /* Ensure the external key data is set from the internal EC key. */ + if ((ret == 1) && (!key->exSet) && (SetECKeyExternal((WOLFSSL_EC_KEY*) + key) != 1)) { + WOLFSSL_MSG("SetECKeyExternal failure"); + ret = 0; + } + + if (ret == 1) { + #ifdef HAVE_COMP_KEY + /* Default to compressed form if not set */ + form = (key->form == WC_POINT_CONVERSION_UNCOMPRESSED) ? + WC_POINT_CONVERSION_UNCOMPRESSED : + WC_POINT_CONVERSION_COMPRESSED; + #endif + + /* Calculate length of point encoding. */ + len = wolfSSL_EC_POINT_point2oct(key->group, key->pub_key, form, NULL, + 0, NULL); + } + /* Encode if length calculated and pointer supplied to update. */ + if ((ret == 1) && (len != 0) && (out != NULL)) { + unsigned char *tmp = NULL; + + /* Allocate buffer for encoding if no buffer supplied. */ + if (*out == NULL) { + tmp = (unsigned char*)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL); + if (tmp == NULL) { + WOLFSSL_MSG("malloc failed"); + ret = 0; + } + } + else { + /* Get buffer to encode into. */ + tmp = *out; + } + + /* Encode public key into buffer. */ + if ((ret == 1) && (wolfSSL_EC_POINT_point2oct(key->group, key->pub_key, + form, tmp, len, NULL) == 0)) { + ret = 0; + } + + if (ret == 1) { + /* Return buffer if allocated. */ + if (*out == NULL) { + *out = tmp; + } + else { + /* Step over encoded data if not allocated. */ + *out += len; + } + } + else if (*out == NULL) { + /* Dispose of allocated buffer. */ + XFREE(tmp, NULL, DYNAMIC_TYPE_OPENSSL); + } + } + + if (ret == 1) { + /* Return length on success. */ + ret = (int)len; + } + return ret; +} + +#ifdef HAVE_ECC_KEY_IMPORT +/* Create a EC key from the DER encoded private key. + * + * @param [out] key Reference to EC key. + * @param [in, out] in On in, reference to buffer that contains DER data. + * On out, reference to buffer after private key data. + * @param [in] long Length of data in the buffer. May be larger than the + * length of the encoded private key. + * @return Allocated EC key on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY* wolfSSL_d2i_ECPrivateKey(WOLFSSL_EC_KEY** key, + const unsigned char** in, long len) +{ + int err = 0; + word32 idx = 0; + WOLFSSL_EC_KEY* ret = NULL; + + WOLFSSL_ENTER("wolfSSL_d2i_ECPrivateKey"); + + /* Validate parameters. */ + if ((in == NULL) || (*in == NULL) || (len <= 0)) { + WOLFSSL_MSG("wolfSSL_d2i_ECPrivateKey Bad arguments"); + err = 1; + } + + /* Create a new, empty EC key. */ + if ((!err) && ((ret = wolfSSL_EC_KEY_new()) == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_KEY_new error"); + err = 1; + } + + /* Decode the private key DER data into internal EC key. */ + if ((!err) && (wc_EccPrivateKeyDecode(*in, &idx, (ecc_key*)ret->internal, + (word32)len) != 0)) { + WOLFSSL_MSG("wc_EccPrivateKeyDecode error"); + err = 1; + } + + if (!err) { + /* Internal EC key setup. */ + ret->inSet = 1; + + /* Set the EC key from the internal values. */ + if (SetECKeyExternal(ret) != 1) { + WOLFSSL_MSG("SetECKeyExternal error"); + err = 1; + } + } + + if (!err) { + /* Move buffer on to next byte after data used. */ + *in += idx; + if (key) { + /* Return new EC key through reference. */ + *key = ret; + } + } + + if (err && (ret != NULL)) { + /* Dispose of allocated EC key. */ + wolfSSL_EC_KEY_free(ret); + ret = NULL; + } + return ret; +} +#endif /* HAVE_ECC_KEY_IMPORT */ + +/* Enecode the private key of the EC key into the buffer as DER. + * + * @param [in] key EC key to encode. + * @param [in, out] out On in, reference to buffer to place DER encoding into. + * On out, reference to buffer after the encoding. + * May be NULL. + * @return Length of DER encoding on success. + * @return 0 on error. + */ +int wolfSSL_i2d_ECPrivateKey(const WOLFSSL_EC_KEY *key, unsigned char **out) +{ + int err = 0; + word32 len = 0; + + WOLFSSL_ENTER("wolfSSL_i2d_ECPrivateKey"); + + /* Validate parameters. */ + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_i2d_ECPrivateKey Bad arguments"); + err = 1; + } + + /* Update the internal EC key if not set. */ + if ((!err) && (!key->inSet) && (SetECKeyInternal((WOLFSSL_EC_KEY*)key) != + 1)) { + WOLFSSL_MSG("SetECKeyInternal error"); + err = 1; + } + + /* Calculate the length of the private key DER encoding using internal EC + * key. */ + if ((!err) && ((int)(len = (word32)wc_EccKeyDerSize((ecc_key*)key->internal, + 0)) <= 0)) { + WOLFSSL_MSG("wc_EccKeyDerSize error"); + err = 1; + } + + /* Only return length when out is NULL. */ + if ((!err) && (out != NULL)) { + unsigned char* buf = NULL; + + /* Must have a buffer to encode into. */ + if (*out == NULL) { + /* Allocate a new buffer of appropriate length. */ + buf = (byte*)XMALLOC(len, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + /* Error and return 0. */ + err = 1; + len = 0; + } + else { + /* Return the allocated buffer. */ + *out = buf; + } + } + /* Encode the internal EC key as a private key in DER format. */ + if ((!err) && wc_EccPrivateKeyToDer((ecc_key*)key->internal, *out, + len) < 0) { + WOLFSSL_MSG("wc_EccPrivateKeyToDer error"); + err = 1; + } + else if (buf != *out) { + /* Move the reference to byte past encoded private key. */ + *out += len; + } + + /* Dispose of any allocated buffer on error. */ + if (err && (*out == buf)) { + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + *out = NULL; + } + } + + return (int)len; +} + +/* Load private key into EC key from DER encoding. + * + * Not an OpenSSL compatibility API. + * + * @param [in, out] key EC key to put private key values into. + * @param [in] derBuf Buffer holding DER encoding. + * @param [in] derSz Size of DER encoding in bytes. + * @return 1 on success. + * @return -1 on error. + */ +int wolfSSL_EC_KEY_LoadDer(WOLFSSL_EC_KEY* key, const unsigned char* derBuf, + int derSz) +{ + return wolfSSL_EC_KEY_LoadDer_ex(key, derBuf, derSz, + WOLFSSL_EC_KEY_LOAD_PRIVATE); +} + +/* Load private/public key into EC key from DER encoding. + * + * Not an OpenSSL compatibility API. + * + * @param [in, out] key EC key to put private/public key values into. + * @param [in] derBuf Buffer holding DER encoding. + * @param [in] derSz Size of DER encoding in bytes. + * @param [in] opt Key type option. Valid values: + * WOLFSSL_EC_KEY_LOAD_PRIVATE, + * WOLFSSL_EC_KEY_LOAD_PUBLIC. + * @return 1 on success. + * @return -1 on error. + */ +int wolfSSL_EC_KEY_LoadDer_ex(WOLFSSL_EC_KEY* key, const unsigned char* derBuf, + int derSz, int opt) +{ + int res = 1; + int ret; + word32 idx = 0; + word32 algId; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_LoadDer"); + + /* Validate parameters. */ + if ((key == NULL) || (key->internal == NULL) || (derBuf == NULL) || + (derSz <= 0)) { + WOLFSSL_MSG("Bad function arguments"); + res = WOLFSSL_FATAL_ERROR; + } + if ((res == 1) && (opt != WOLFSSL_EC_KEY_LOAD_PRIVATE) && + (opt != WOLFSSL_EC_KEY_LOAD_PUBLIC)) { + res = WOLFSSL_FATAL_ERROR; + } + + if (res == 1) { + /* Assume no PKCS#8 header. */ + key->pkcs8HeaderSz = 0; + + /* Check if input buffer has PKCS8 header. In the case that it does not + * have a PKCS8 header then do not error out. + */ + if ((ret = ToTraditionalInline_ex((const byte*)derBuf, &idx, + (word32)derSz, &algId)) > 0) { + WOLFSSL_MSG("Found PKCS8 header"); + key->pkcs8HeaderSz = (word16)idx; + res = 1; + } + /* Error out on parsing error. */ + else if (ret != WC_NO_ERR_TRACE(ASN_PARSE_E)) { + WOLFSSL_MSG("Unexpected error with trying to remove PKCS8 header"); + res = WOLFSSL_FATAL_ERROR; + } + } + + if (res == 1) { + /* Load into internal EC key based on key type option. */ + if (opt == WOLFSSL_EC_KEY_LOAD_PRIVATE) { + ret = wc_EccPrivateKeyDecode(derBuf, &idx, (ecc_key*)key->internal, + (word32)derSz); + } + else { + ret = wc_EccPublicKeyDecode(derBuf, &idx, (ecc_key*)key->internal, + (word32)derSz); + if (ret < 0) { + ecc_key *tmp = (ecc_key*)XMALLOC(sizeof(ecc_key), + ((ecc_key*)key->internal)->heap, DYNAMIC_TYPE_ECC); + if (tmp == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + else { + /* We now try again as x.963 [point type][x][opt y]. */ + ret = wc_ecc_init_ex(tmp, ((ecc_key*)key->internal)->heap, + INVALID_DEVID); + if (ret == 0) { + ret = wc_ecc_import_x963(derBuf, (word32)derSz, tmp); + if (ret == 0) { + /* Take ownership of new key - set tmp to the old + * key which will then be freed below. */ + ecc_key *old = (ecc_key *)key->internal; + key->internal = tmp; + tmp = old; + + idx = (word32)derSz; + } + wc_ecc_free(tmp); + } + XFREE(tmp, ((ecc_key*)key->internal)->heap, + DYNAMIC_TYPE_ECC); + } + } + } + if (ret < 0) { + /* Error returned from wolfSSL. */ + if (opt == WOLFSSL_EC_KEY_LOAD_PRIVATE) { + WOLFSSL_MSG("wc_EccPrivateKeyDecode failed"); + } + else { + WOLFSSL_MSG("wc_EccPublicKeyDecode failed"); + } + res = WOLFSSL_FATAL_ERROR; + } + + /* Internal key updated - update whether it is a valid key. */ + key->inSet = (res == 1); + } + + /* Set the external EC key based on value in internal. */ + if ((res == 1) && (SetECKeyExternal(key) != 1)) { + WOLFSSL_MSG("SetECKeyExternal failed"); + res = WOLFSSL_FATAL_ERROR; + } + + return res; +} + + +#ifndef NO_BIO + +WOLFSSL_EC_KEY *wolfSSL_d2i_EC_PUBKEY_bio(WOLFSSL_BIO *bio, + WOLFSSL_EC_KEY **out) +{ + char* data = NULL; + int dataSz = 0; + int memAlloced = 0; + WOLFSSL_EC_KEY* ec = NULL; + int err = 0; + + WOLFSSL_ENTER("wolfSSL_d2i_EC_PUBKEY_bio"); + + if (bio == NULL) + return NULL; + + if (err == 0 && wolfssl_read_bio(bio, &data, &dataSz, &memAlloced) != 0) { + WOLFSSL_ERROR_MSG("wolfssl_read_bio failed"); + err = 1; + } + + if (err == 0 && (ec = wolfSSL_EC_KEY_new()) == NULL) { + WOLFSSL_ERROR_MSG("wolfSSL_EC_KEY_new failed"); + err = 1; + } + + /* Load the EC key with the public key from the DER encoding. */ + if (err == 0 && wolfSSL_EC_KEY_LoadDer_ex(ec, (const unsigned char*)data, + dataSz, WOLFSSL_EC_KEY_LOAD_PUBLIC) != 1) { + WOLFSSL_ERROR_MSG("wolfSSL_EC_KEY_LoadDer_ex failed"); + err = 1; + } + + if (memAlloced) + XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (err) { /* on error */ + wolfSSL_EC_KEY_free(ec); + ec = NULL; + } + else { /* on success */ + if (out != NULL) + *out = ec; + } + + return ec; +} + +#endif /* !NO_BIO */ + +/* + * EC key PEM APIs + */ + +#ifdef HAVE_ECC_KEY_EXPORT +#if defined(WOLFSSL_KEY_GEN) && (!defined(NO_FILESYSTEM) || !defined(NO_BIO)) +/* Encode the EC public key as DER. + * + * @param [in] key EC key to encode. + * @param [out] der Pointer through which buffer is returned. + * @param [in] heap Heap hint. + * @return Size of encoding on success. + * @return 0 on error. + */ +static int wolfssl_ec_key_to_pubkey_der(WOLFSSL_EC_KEY* key, + unsigned char** der, void* heap) +{ + int sz; + unsigned char* buf = NULL; + + (void)heap; + + /* Calculate encoded size to allocate. */ + sz = wc_EccPublicKeyDerSize((ecc_key*)key->internal, 1); + if (sz <= 0) { + WOLFSSL_MSG("wc_EccPublicKeyDerSize failed"); + sz = 0; + } + if (sz > 0) { + /* Allocate memory to hold encoding. */ + buf = (byte*)XMALLOC((size_t)sz, heap, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + WOLFSSL_MSG("malloc failed"); + sz = 0; + } + } + if (sz > 0) { + /* Encode public key to DER using wolfSSL. */ + sz = wc_EccPublicKeyToDer((ecc_key*)key->internal, buf, (word32)sz, 1); + if (sz < 0) { + WOLFSSL_MSG("wc_EccPublicKeyToDer failed"); + sz = 0; + } + } + + /* Return buffer on success. */ + if (sz > 0) { + *der = buf; + } + else { + /* Dispose of any dynamically allocated data not returned. */ + XFREE(buf, heap, DYNAMIC_TYPE_TMP_BUFFER); + } + + return sz; +} +#endif + +#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_KEY_GEN) +/* + * Return code compliant with OpenSSL. + * + * @param [in] fp File pointer to write PEM encoding to. + * @param [in] key EC key to encode and write. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_PEM_write_EC_PUBKEY(XFILE fp, WOLFSSL_EC_KEY* key) +{ + int ret = 1; + unsigned char* derBuf = NULL; + int derSz = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_write_EC_PUBKEY"); + + /* Validate parameters. */ + if ((fp == XBADFILE) || (key == NULL)) { + WOLFSSL_MSG("Bad argument."); + return 0; + } + + /* Encode public key in EC key as DER. */ + derSz = wolfssl_ec_key_to_pubkey_der(key, &derBuf, key->heap); + if (derSz == 0) { + ret = 0; + } + + /* Write out to file the PEM encoding of the DER. */ + if ((ret == 1) && (der_write_to_file_as_pem(derBuf, derSz, fp, + ECC_PUBLICKEY_TYPE, key->heap) != 1)) { + ret = 0; + } + + /* Dispose of any dynamically allocated data. */ + XFREE(derBuf, key->heap, DYNAMIC_TYPE_TMP_BUFFER); + + WOLFSSL_LEAVE("wolfSSL_PEM_write_EC_PUBKEY", ret); + + return ret; +} +#endif +#endif + +#ifndef NO_BIO +/* Read a PEM encoded EC public key from a BIO. + * + * @param [in] bio BIO to read EC public key from. + * @param [out] out Pointer to return EC key object through. May be NULL. + * @param [in] cb Password callback when PEM encrypted. + * @param [in] pass NUL terminated string for passphrase when PEM + * encrypted. + * @return New EC key object on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY* wolfSSL_PEM_read_bio_EC_PUBKEY(WOLFSSL_BIO* bio, + WOLFSSL_EC_KEY** out, wc_pem_password_cb* cb, void *pass) +{ + int err = 0; + WOLFSSL_EC_KEY* ec = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_EC_PUBKEY"); + + /* Validate parameters. */ + if (bio == NULL) { + err = 1; + } + + if (!err) { + /* Create an empty EC key. */ + ec = wolfSSL_EC_KEY_new(); + if (ec == NULL) { + err = 1; + } + } + /* Read a PEM key in to a new DER buffer. */ + if ((!err) && (pem_read_bio_key(bio, cb, pass, ECC_PUBLICKEY_TYPE, + &keyFormat, &der) <= 0)) { + err = 1; + } + /* Load the EC key with the public key from the DER encoding. */ + if ((!err) && (wolfSSL_EC_KEY_LoadDer_ex(ec, der->buffer, (int)der->length, + WOLFSSL_EC_KEY_LOAD_PUBLIC) != 1)) { + WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_EC_KEY"); + err = 1; + } + + /* Dispose of dynamically allocated data not needed anymore. */ + FreeDer(&der); + if (err) { + wolfSSL_EC_KEY_free(ec); + ec = NULL; + } + + /* Return EC key through out if required. */ + if ((out != NULL) && (ec != NULL)) { + *out = ec; + } + return ec; +} + +/* Read a PEM encoded EC private key from a BIO. + * + * @param [in] bio BIO to read EC private key from. + * @param [out] out Pointer to return EC key object through. May be NULL. + * @param [in] cb Password callback when PEM encrypted. + * @param [in] pass NUL terminated string for passphrase when PEM + * encrypted. + * @return New EC key object on success. + * @return NULL on error. + */ +WOLFSSL_EC_KEY* wolfSSL_PEM_read_bio_ECPrivateKey(WOLFSSL_BIO* bio, + WOLFSSL_EC_KEY** out, wc_pem_password_cb* cb, void *pass) +{ + int err = 0; + WOLFSSL_EC_KEY* ec = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_ECPrivateKey"); + + /* Validate parameters. */ + if (bio == NULL) { + err = 1; + } + + if (!err) { + /* Create an empty EC key. */ + ec = wolfSSL_EC_KEY_new(); + if (ec == NULL) { + err = 1; + } + } + /* Read a PEM key in to a new DER buffer. + * To check ENC EC PRIVATE KEY, it uses PRIVATEKEY_TYPE to call + * pem_read_bio_key(), and then check key format if it is EC. + */ + if ((!err) && (pem_read_bio_key(bio, cb, pass, PRIVATEKEY_TYPE, + &keyFormat, &der) <= 0)) { + err = 1; + } + if (keyFormat != ECDSAk) { + WOLFSSL_ERROR_MSG("Error not EC key format"); + err = 1; + } + /* Load the EC key with the private key from the DER encoding. */ + if ((!err) && (wolfSSL_EC_KEY_LoadDer_ex(ec, der->buffer, (int)der->length, + WOLFSSL_EC_KEY_LOAD_PRIVATE) != 1)) { + WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_EC_KEY"); + err = 1; + } + + /* Dispose of dynamically allocated data not needed anymore. */ + FreeDer(&der); + if (err) { + wolfSSL_EC_KEY_free(ec); + ec = NULL; + } + + /* Return EC key through out if required. */ + if ((out != NULL) && (ec != NULL)) { + *out = ec; + } + return ec; +} +#endif /* !NO_BIO */ + +#if defined(WOLFSSL_KEY_GEN) && defined(HAVE_ECC_KEY_EXPORT) +#ifndef NO_BIO +/* Write out the EC public key as PEM to the BIO. + * + * @param [in] bio BIO to write PEM encoding to. + * @param [in] ec EC public key to encode. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_PEM_write_bio_EC_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_EC_KEY* ec) +{ + int ret = 1; + unsigned char* derBuf = NULL; + int derSz = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_EC_PUBKEY"); + + /* Validate parameters. */ + if ((bio == NULL) || (ec == NULL)) { + WOLFSSL_MSG("Bad Function Arguments"); + return 0; + } + + /* Encode public key in EC key as DER. */ + derSz = wolfssl_ec_key_to_pubkey_der(ec, &derBuf, ec->heap); + if (derSz == 0) { + ret = 0; + } + + /* Write out to BIO the PEM encoding of the EC public key. */ + if ((ret == 1) && (der_write_to_bio_as_pem(derBuf, derSz, bio, + ECC_PUBLICKEY_TYPE) != 1)) { + ret = 0; + } + + /* Dispose of any dynamically allocated data. */ + XFREE(derBuf, ec->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +/* Write out the EC private key as PEM to the BIO. + * + * Return code compliant with OpenSSL. + * + * @param [in] bio BIO to write PEM encoding to. + * @param [in] ec EC private key to encode. + * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. + * @param [in] passwd Password string when PEM encrypted. May be NULL. + * @param [in] passwdSz Length of password string when PEM encrypted. + * @param [in] cb Password callback when PEM encrypted. Unused. + * @param [in] pass NUL terminated string for passphrase when PEM + * encrypted. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_PEM_write_bio_ECPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EC_KEY* ec, + const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, + wc_pem_password_cb* cb, void* arg) +{ + int ret = 1; + unsigned char* pem = NULL; + int pLen = 0; + + (void)cb; + (void)arg; + + /* Validate parameters. */ + if ((bio == NULL) || (ec == NULL)) { + ret = 0; + } + + /* Write EC private key to PEM. */ + if ((ret == 1) && (wolfSSL_PEM_write_mem_ECPrivateKey(ec, cipher, passwd, + passwdSz, &pem, &pLen) != 1)) { + ret = 0; + } + /* Write PEM to BIO. */ + if ((ret == 1) && (wolfSSL_BIO_write(bio, pem, pLen) != pLen)) { + WOLFSSL_ERROR_MSG("EC private key BIO write failed"); + ret = 0; + } + + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + + return ret; +} + +#endif /* !NO_BIO */ + +/* Encode the EC private key as PEM into buffer. + * + * Return code compliant with OpenSSL. + * Not an OpenSSL API. + * + * @param [in] ec EC private key to encode. + * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. + * @param [in] passwd Password string when PEM encrypted. May be NULL. + * @param [in] passwdSz Length of password string when PEM encrypted. + * @param [out] pem Newly allocated buffer holding PEM encoding. + * @param [out] pLen Length of PEM encoding in bytes. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_PEM_write_mem_ECPrivateKey(WOLFSSL_EC_KEY* ec, + const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, + unsigned char **pem, int *pLen) +{ +#if defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM) + int ret = 1; + byte* derBuf = NULL; + word32 der_max_len = 0; + int derSz = 0; + + WOLFSSL_MSG("wolfSSL_PEM_write_mem_ECPrivateKey"); + + /* Validate parameters. */ + if ((pem == NULL) || (pLen == NULL) || (ec == NULL) || + (ec->internal == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = 0; + } + + /* Ensure internal EC key is set from external. */ + if ((ret == 1) && (ec->inSet == 0)) { + WOLFSSL_MSG("No ECC internal set, do it"); + + if (SetECKeyInternal(ec) != 1) { + WOLFSSL_MSG("SetECKeyInternal failed"); + ret = 0; + } + } + + if (ret == 1) { + /* Calculate maximum size of DER encoding. + * 4 > size of pub, priv + ASN.1 additional information */ + der_max_len = 4 * (word32)wc_ecc_size((ecc_key*)ec->internal) + + WC_AES_BLOCK_SIZE; + + /* Allocate buffer big enough to hold encoding. */ + derBuf = (byte*)XMALLOC((size_t)der_max_len, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) { + WOLFSSL_MSG("malloc failed"); + ret = 0; + } + } + + if (ret == 1) { + /* Encode EC private key as DER. */ + derSz = wc_EccKeyToDer((ecc_key*)ec->internal, derBuf, der_max_len); + if (derSz < 0) { + WOLFSSL_MSG("wc_EccKeyToDer failed"); + XFREE(derBuf, NULL, DYNAMIC_TYPE_DER); + ret = 0; + } + } + + /* Convert DER to PEM - possibly encrypting. */ + if ((ret == 1) && (der_to_enc_pem_alloc(derBuf, derSz, cipher, passwd, + passwdSz, ECC_PRIVATEKEY_TYPE, NULL, pem, pLen) != 1)) { + WOLFSSL_ERROR_MSG("der_to_enc_pem_alloc failed"); + ret = 0; + } + + return ret; +#else + (void)ec; + (void)cipher; + (void)passwd; + (void)passwdSz; + (void)pem; + (void)pLen; + return 0; +#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ +} + +#ifndef NO_FILESYSTEM +/* Write out the EC private key as PEM to file. + * + * Return code compliant with OpenSSL. + * + * @param [in] fp File pointer to write PEM encoding to. + * @param [in] ec EC private key to encode. + * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. + * @param [in] passwd Password string when PEM encrypted. May be NULL. + * @param [in] passwdSz Length of password string when PEM encrypted. + * @param [in] cb Password callback when PEM encrypted. Unused. + * @param [in] pass NUL terminated string for passphrase when PEM + * encrypted. Unused. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_PEM_write_ECPrivateKey(XFILE fp, WOLFSSL_EC_KEY *ec, + const WOLFSSL_EVP_CIPHER *cipher, unsigned char *passwd, int passwdSz, + wc_pem_password_cb *cb, void *pass) +{ + int ret = 1; + byte *pem = NULL; + int pLen = 0; + + (void)cb; + (void)pass; + + WOLFSSL_MSG("wolfSSL_PEM_write_ECPrivateKey"); + + /* Validate parameters. */ + if ((fp == XBADFILE) || (ec == NULL) || (ec->internal == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + ret = 0; + } + + /* Write EC private key to PEM. */ + if ((ret == 1) && (wolfSSL_PEM_write_mem_ECPrivateKey(ec, cipher, passwd, + passwdSz, &pem, &pLen) != 1)) { + WOLFSSL_MSG("wolfSSL_PEM_write_mem_ECPrivateKey failed"); + ret = 0; + } + + /* Write out to file the PEM encoding of the EC private key. */ + if ((ret == 1) && ((int)XFWRITE(pem, 1, (size_t)pLen, fp) != pLen)) { + WOLFSSL_MSG("ECC private key file write failed"); + ret = 0; + } + + /* Dispose of any dynamically allocated data. */ + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + + return ret; +} + +#endif /* NO_FILESYSTEM */ +#endif /* WOLFSSL_KEY_GEN && HAVE_ECC_KEY_EXPORT */ + +/* + * EC key print APIs + */ + +#ifndef NO_CERTS + +#if defined(XFPRINTF) && !defined(NO_FILESYSTEM) && \ + !defined(NO_STDIO_FILESYSTEM) +/* Print the EC key to a file pointer as text. + * + * @param [in] fp File pointer. + * @param [in] key EC key to print. + * @param [in] indent Number of spaces to place before each line printed. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_EC_KEY_print_fp(XFILE fp, WOLFSSL_EC_KEY* key, int indent) +{ + int ret = 1; + int bits = 0; + int priv = 0; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_print_fp"); + + /* Validate parameters. */ + if ((fp == XBADFILE) || (key == NULL) || (key->group == NULL) || + (indent < 0)) { + ret = 0; + } + + if (ret == 1) { + /* Get EC groups order size in bits. */ + bits = wolfSSL_EC_GROUP_order_bits(key->group); + if (bits <= 0) { + WOLFSSL_MSG("Failed to get group order bits."); + ret = 0; + } + } + if (ret == 1) { + const char* keyType; + + /* Determine whether this is a private or public key. */ + if ((key->priv_key != NULL) && (!wolfSSL_BN_is_zero(key->priv_key))) { + keyType = "Private-Key"; + priv = 1; + } + else { + keyType = "Public-Key"; + } + + /* Print key header. */ + if (XFPRINTF(fp, "%*s%s: (%d bit)\n", indent, "", keyType, bits) < 0) { + ret = 0; + } + } + if ((ret == 1) && priv) { + /* Print the private key BN. */ + ret = pk_bn_field_print_fp(fp, indent, "priv", key->priv_key); + } + /* Check for public key data in EC key. */ + if ((ret == 1) && (key->pub_key != NULL) && (key->pub_key->exSet)) { + /* Get the public key point as one BN. */ + WOLFSSL_BIGNUM* pubBn = wolfSSL_EC_POINT_point2bn(key->group, + key->pub_key, WC_POINT_CONVERSION_UNCOMPRESSED, NULL, NULL); + if (pubBn == NULL) { + WOLFSSL_MSG("wolfSSL_EC_POINT_point2bn failed."); + ret = 0; + } + else { + /* Print the public key in a BN. */ + ret = pk_bn_field_print_fp(fp, indent, "pub", pubBn); + wolfSSL_BN_free(pubBn); + } + } + if (ret == 1) { + /* Get the NID of the group. */ + int nid = wolfSSL_EC_GROUP_get_curve_name(key->group); + if (nid > 0) { + /* Convert the NID into a long name and NIST name. */ + const char* curve = wolfSSL_OBJ_nid2ln(nid); + const char* nistName = wolfSSL_EC_curve_nid2nist(nid); + + /* Print OID name if known. */ + if ((curve != NULL) && + (XFPRINTF(fp, "%*sASN1 OID: %s\n", indent, "", curve) < 0)) { + ret = 0; + } + /* Print NIST curve name if known. */ + if ((nistName != NULL) && + (XFPRINTF(fp, "%*sNIST CURVE: %s\n", indent, "", + nistName) < 0)) { + ret = 0; + } + } + } + + + WOLFSSL_LEAVE("wolfSSL_EC_KEY_print_fp", ret); + + return ret; +} +#endif /* XFPRINTF && !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM */ + +#endif /* !NO_CERTS */ + +/* + * EC_KEY get/set/test APIs + */ + +/* Set data of internal, wolfCrypt EC key object into EC key. + * + * EC_KEY wolfSSL -> OpenSSL + * + * @param [in, out] p EC key to update. + * @return 1 on success. + * @return -1 on failure. + */ +int SetECKeyExternal(WOLFSSL_EC_KEY* eckey) +{ + int ret = 1; + + WOLFSSL_ENTER("SetECKeyExternal"); + + /* Validate parameter. */ + if ((eckey == NULL) || (eckey->internal == NULL)) { + WOLFSSL_MSG("ec key NULL error"); + ret = WOLFSSL_FATAL_ERROR; + } + else { + ecc_key* key = (ecc_key*)eckey->internal; + + /* Set group (OID, nid and idx) from wolfCrypt EC key. */ + eckey->group->curve_oid = (int)key->dp->oidSum; + eckey->group->curve_nid = EccEnumToNID(key->dp->id); + eckey->group->curve_idx = key->idx; + + if (eckey->pub_key->internal != NULL) { + /* Copy internal public point from internal key's public point. */ + if (wc_ecc_copy_point(&key->pubkey, + (ecc_point*)eckey->pub_key->internal) != MP_OKAY) { + WOLFSSL_MSG("SetECKeyExternal ecc_copy_point failed"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* Set external public key from internal wolfCrypt, public key. */ + if ((ret == 1) && (ec_point_external_set(eckey->pub_key) != 1)) { + WOLFSSL_MSG("SetECKeyExternal ec_point_external_set failed"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + /* set the external privkey */ + if ((ret == 1) && (key->type == ECC_PRIVATEKEY) && + (wolfssl_bn_set_value(&eckey->priv_key, + wc_ecc_key_get_priv(key)) != 1)) { + WOLFSSL_MSG("ec priv key error"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* External values set when operations succeeded. */ + eckey->exSet = (ret == 1); + } + + return ret; +} + +/* Set data of EC key into internal, wolfCrypt EC key object. + * + * EC_KEY Openssl -> WolfSSL + * + * @param [in, out] p EC key to update. + * @return 1 on success. + * @return -1 on failure. + */ +int SetECKeyInternal(WOLFSSL_EC_KEY* eckey) +{ + int ret = 1; + + WOLFSSL_ENTER("SetECKeyInternal"); + + /* Validate parameter. */ + if ((eckey == NULL) || (eckey->internal == NULL) || + (eckey->group == NULL)) { + WOLFSSL_MSG("ec key NULL error"); + ret = WOLFSSL_FATAL_ERROR; + } + else { + ecc_key* key = (ecc_key*)eckey->internal; + int pubSet = 0; + + /* Validate group. */ + if ((eckey->group->curve_idx < 0) || + (wc_ecc_is_valid_idx(eckey->group->curve_idx) == 0)) { + WOLFSSL_MSG("invalid curve idx"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 1) { + /* Set group (idx of curve and corresponding domain parameters). */ + key->idx = eckey->group->curve_idx; + key->dp = &ecc_sets[key->idx]; + pubSet = (eckey->pub_key != NULL); + } + /* Set public key (point). */ + if ((ret == 1) && pubSet) { + if (ec_point_internal_set(eckey->pub_key) != 1) { + WOLFSSL_MSG("ec key pub error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* Copy public point to key. */ + if ((ret == 1) && (wc_ecc_copy_point( + (ecc_point*)eckey->pub_key->internal, &key->pubkey) != + MP_OKAY)) { + WOLFSSL_MSG("wc_ecc_copy_point error"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 1) { + /* Set that the internal key is a public key */ + key->type = ECC_PUBLICKEY; + } + } + + /* set privkey */ + if ((ret == 1) && (eckey->priv_key != NULL)) { + if (wolfssl_bn_get_value(eckey->priv_key, + wc_ecc_key_get_priv(key)) != 1) { + WOLFSSL_MSG("ec key priv error"); + ret = WOLFSSL_FATAL_ERROR; + } + /* private key */ + if ((ret == 1) && (!mp_iszero(wc_ecc_key_get_priv(key)))) { + if (pubSet) { + key->type = ECC_PRIVATEKEY; + } + else { + key->type = ECC_PRIVATEKEY_ONLY; + } + } + } + + /* Internal values set when operations succeeded. */ + eckey->inSet = (ret == 1); + } + + return ret; +} + +/* Get point conversion format of EC key. + * + * @param [in] key EC key. + * @return Point conversion format on success. + * @return -1 on error. + */ +wc_point_conversion_form_t wolfSSL_EC_KEY_get_conv_form( + const WOLFSSL_EC_KEY* key) +{ + if (key == NULL) + return WOLFSSL_FATAL_ERROR; + return key->form; +} + +/* Set point conversion format into EC key. + * + * @param [in, out] key EC key to set format into. + * @param [in] form Point conversion format. Valid values: + * WC_POINT_CONVERSION_UNCOMPRESSED, + * WC_POINT_CONVERSION_COMPRESSED (when HAVE_COMP_KEY) + */ +void wolfSSL_EC_KEY_set_conv_form(WOLFSSL_EC_KEY *key, int form) +{ + if (key == NULL) { + WOLFSSL_MSG("Key passed in NULL"); + } + else if (form == WC_POINT_CONVERSION_UNCOMPRESSED +#ifdef HAVE_COMP_KEY + || form == WC_POINT_CONVERSION_COMPRESSED +#endif + ) { + key->form = (unsigned char)form; + } + else { + WOLFSSL_MSG("Incorrect form or HAVE_COMP_KEY not compiled in"); + } +} + +/* Get the EC group object that is in EC key. + * + * @param [in] key EC key. + * @return EC group object on success. + * @return NULL when key is NULL. + */ +const WOLFSSL_EC_GROUP *wolfSSL_EC_KEY_get0_group(const WOLFSSL_EC_KEY *key) +{ + WOLFSSL_EC_GROUP* group = NULL; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_group"); + + if (key != NULL) { + group = key->group; + } + + return group; +} + +/* Set the group in WOLFSSL_EC_KEY + * + * @param [in, out] key EC key to update. + * @param [in] group EC group to copy. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_EC_KEY_set_group(WOLFSSL_EC_KEY *key, WOLFSSL_EC_GROUP *group) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_set_group"); + + /* Validate parameters. */ + if ((key == NULL) || (group == NULL)) { + ret = 0; + } + + if (ret == 1) { + /* Dispose of the current group. */ + if (key->group != NULL) { + wolfSSL_EC_GROUP_free(key->group); + } + /* Duplicate the passed in group into EC key. */ + key->group = wolfSSL_EC_GROUP_dup(group); + if (key->group == NULL) { + ret = 0; + } + } + + return ret; +} + +/* Get the BN object that is the private key in the EC key. + * + * @param [in] key EC key. + * @return BN object on success. + * @return NULL when key is NULL or private key is not set. + */ +WOLFSSL_BIGNUM *wolfSSL_EC_KEY_get0_private_key(const WOLFSSL_EC_KEY *key) +{ + WOLFSSL_BIGNUM* priv_key = NULL; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_private_key"); + + /* Validate parameter. */ + if (key == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_get0_private_key Bad arguments"); + } + /* Only return private key if it is not 0. */ + else if (!wolfSSL_BN_is_zero(key->priv_key)) { + priv_key = key->priv_key; + } + + return priv_key; +} + +/* Sets the private key value into EC key. + * + * Return code compliant with OpenSSL. + * + * @param [in, out] key EC key to set. + * @param [in] priv_key Private key value in a BN. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_EC_KEY_set_private_key(WOLFSSL_EC_KEY *key, + const WOLFSSL_BIGNUM *priv_key) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_set_private_key"); + + /* Validate parameters. */ + if ((key == NULL) || (priv_key == NULL)) { + WOLFSSL_MSG("Bad arguments"); + ret = 0; + } + + /* Check for obvious invalid values. */ + if (wolfSSL_BN_is_negative(priv_key) || wolfSSL_BN_is_zero(priv_key) || + wolfSSL_BN_is_one(priv_key)) { + WOLFSSL_MSG("Invalid private key value"); + ret = 0; + } + + if (ret == 1) { + /* Free key if previously set. */ + if (key->priv_key != NULL) { + wolfSSL_BN_free(key->priv_key); + } + + /* Duplicate the BN passed in. */ + key->priv_key = wolfSSL_BN_dup(priv_key); + if (key->priv_key == NULL) { + WOLFSSL_MSG("key ecc priv key NULL"); + ret = 0; + } + } + /* Set the external values into internal EC key. */ + if ((ret == 1) && (SetECKeyInternal(key) != 1)) { + WOLFSSL_MSG("SetECKeyInternal failed"); + /* Dispose of new private key on error. */ + wolfSSL_BN_free(key->priv_key); + key->priv_key = NULL; + ret = 0; + } + + return ret; +} + +/* Get the public key EC point object that is in EC key. + * + * @param [in] key EC key. + * @return EC point object that is the public key on success. + * @return NULL when key is NULL. + */ +WOLFSSL_EC_POINT* wolfSSL_EC_KEY_get0_public_key(const WOLFSSL_EC_KEY *key) +{ + WOLFSSL_EC_POINT* pub_key = NULL; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_get0_public_key"); + + if (key != NULL) { + pub_key = key->pub_key; + } + + return pub_key; +} + +/* + * Return code compliant with OpenSSL. + * + * @param [in, out] key EC key. + * @param [in] pub Public key as an EC point. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_EC_KEY_set_public_key(WOLFSSL_EC_KEY *key, + const WOLFSSL_EC_POINT *pub) +{ + int ret = 1; + ecc_point *pub_p = NULL; + ecc_point *key_p = NULL; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_set_public_key"); + + /* Validate parameters. */ + if ((key == NULL) || (key->internal == NULL) || (pub == NULL) || + (pub->internal == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_KEY_set_public_key Bad arguments"); + ret = 0; + } + + /* Ensure the internal EC key is set. */ + if ((ret == 1) && (key->inSet == 0) && (SetECKeyInternal(key) != 1)) { + WOLFSSL_MSG("SetECKeyInternal failed"); + ret = 0; + } + + /* Ensure the internal EC point of pub is setup. */ + if ((ret == 1) && (ec_point_setup(pub) != 1)) { + ret = 0; + } + + if (ret == 1) { + /* Get the internal point of pub and the public key in key. */ + pub_p = (ecc_point*)pub->internal; + key_p = (ecc_point*)key->pub_key->internal; + + /* Create new point if required. */ + if (key_p == NULL) { + key_p = wc_ecc_new_point(); + key->pub_key->internal = (void*)key_p; + } + /* Check point available. */ + if (key_p == NULL) { + WOLFSSL_MSG("key ecc point NULL"); + ret = 0; + } + } + + /* Copy the internal pub point into internal key point. */ + if ((ret == 1) && (wc_ecc_copy_point(pub_p, key_p) != MP_OKAY)) { + WOLFSSL_MSG("ecc_copy_point failure"); + ret = 0; + } + + /* Copy the internal point data into external. */ + if ((ret == 1) && (ec_point_external_set(key->pub_key) != 1)) { + WOLFSSL_MSG("SetECKeyInternal failed"); + ret = 0; + } + + /* Copy the internal key into external. */ + if ((ret == 1) && (SetECKeyInternal(key) != 1)) { + WOLFSSL_MSG("SetECKeyInternal failed"); + ret = 0; + } + + if (ret == 1) { + /* Dump out the point and the key's public key for debug. */ + wolfSSL_EC_POINT_dump("pub", pub); + wolfSSL_EC_POINT_dump("key->pub_key", key->pub_key); + } + + return ret; +} + +#ifndef NO_WOLFSSL_STUB +/* Set the ASN.1 encoding flag against the EC key. + * + * No implementation as only named curves supported for encoding. + * + * @param [in, out] key EC key. + * @param [in] flag ASN.1 flag to set. Valid values: + * OPENSSL_EC_EXPLICIT_CURVE, OPENSSL_EC_NAMED_CURVE + */ +void wolfSSL_EC_KEY_set_asn1_flag(WOLFSSL_EC_KEY *key, int asn1_flag) +{ + (void)key; + (void)asn1_flag; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_set_asn1_flag"); + WOLFSSL_STUB("EC_KEY_set_asn1_flag"); +} +#endif + +/* + * EC key generate key APIs + */ + +/* Generate an EC key. + * + * Uses the internal curve index set in the EC key or the default. + * + * @param [in, out] key EC key. + * @return 1 on success + * @return 0 on failure. + */ +int wolfSSL_EC_KEY_generate_key(WOLFSSL_EC_KEY *key) +{ + int res = 1; + int initTmpRng = 0; + WC_RNG* rng = NULL; + WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); + + WOLFSSL_ENTER("wolfSSL_EC_KEY_generate_key"); + + /* Validate parameters. */ + if ((key == NULL) || (key->internal == NULL) || (key->group == NULL)) { + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key Bad arguments"); + res = 0; + } + if (res == 1) { + /* Check if we know which internal curve index to use. */ + if (key->group->curve_idx < 0) { + /* Generate key using the default curve. */ +#if FIPS_VERSION3_GE(6,0,0) + key->group->curve_idx = ECC_SECP256R1; /* FIPS default to 256 */ +#else + key->group->curve_idx = ECC_CURVE_DEF; +#endif + } + + /* Create a random number generator. */ + rng = wolfssl_make_rng(tmpRng, &initTmpRng); + if (rng == NULL) { + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key failed to make RNG"); + res = 0; + } + } + if (res == 1) { + /* NIDToEccEnum returns -1 for invalid NID so if key->group->curve_nid + * is 0 then pass ECC_CURVE_DEF as arg */ + int eccEnum = key->group->curve_nid ? +#if FIPS_VERSION3_GE(6,0,0) + NIDToEccEnum(key->group->curve_nid) : ECC_SECP256R1; +#else + NIDToEccEnum(key->group->curve_nid) : ECC_CURVE_DEF; +#endif + /* Get the internal EC key. */ + ecc_key* ecKey = (ecc_key*)key->internal; + /* Make the key using internal API. */ + int ret = 0; + +#if FIPS_VERSION3_GE(6,0,0) + /* In the case of FIPS only allow key generation with approved curves */ + if (eccEnum != ECC_SECP256R1 && eccEnum != ECC_SECP224R1 && + eccEnum != ECC_SECP384R1 && eccEnum != ECC_SECP521R1) { + WOLFSSL_MSG("Unsupported curve selected in FIPS mode"); + res = 0; + } + if (res == 1) { +#endif + ret = wc_ecc_make_key_ex(rng, 0, ecKey, eccEnum); +#if FIPS_VERSION3_GE(6,0,0) + } +#endif + + #if defined(WOLFSSL_ASYNC_CRYPT) + /* Wait on asynchronouse operation. */ + ret = wc_AsyncWait(ret, &ecKey->asyncDev, WC_ASYNC_FLAG_NONE); + #endif + if (ret != 0) { + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key wc_ecc_make_key failed"); + res = 0; + } + } + + /* Dispose of local random number generator if initialized. */ + if (initTmpRng) { + wc_FreeRng(rng); + WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG); + } + + /* Set the external key from new internal key values. */ + if ((res == 1) && (SetECKeyExternal(key) != 1)) { + WOLFSSL_MSG("wolfSSL_EC_KEY_generate_key SetECKeyExternal failed"); + res = 0; + } + + return res; +} + +/* + * EC key check key APIs + */ + +/* Check that the EC key is valid. + * + * @param [in] key EC key. + * @return 1 on valid. + * @return 0 on invalid or error. + */ +int wolfSSL_EC_KEY_check_key(const WOLFSSL_EC_KEY *key) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_EC_KEY_check_key"); + + /* Validate parameter. */ + if ((key == NULL) || (key->internal == NULL)) { + WOLFSSL_MSG("Bad parameter"); + ret = 0; + } + + /* Set the external EC key values into internal if not already. */ + if ((ret == 1) && (key->inSet == 0) && (SetECKeyInternal( + (WOLFSSL_EC_KEY*)key) != 1)) { + WOLFSSL_MSG("SetECKeyInternal failed"); + ret = 0; + } + + if (ret == 1) { + /* Have internal EC implementation check key. */ + ret = wc_ecc_check_key((ecc_key*)key->internal) == 0; + } + + return ret; +} + +/* End EC_KEY */ + +#if !defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0) +/* Get the supported, built-in EC curves + * + * @param [in, out] curves Pre-allocated list to put supported curves into. + * @param [in] len Maximum number of items to place in list. + * @return Number of built-in EC curves when curves is NULL or len is 0. + * @return Number of items placed in list otherwise. + */ +size_t wolfSSL_EC_get_builtin_curves(WOLFSSL_EC_BUILTIN_CURVE *curves, + size_t len) +{ + size_t i; + size_t cnt; +#ifdef HAVE_SELFTEST + /* Defined in ecc.h when available. */ + size_t ecc_sets_count; + + /* Count the pre-defined curves since global not available. */ + for (i = 0; ecc_sets[i].size != 0 && ecc_sets[i].name != NULL; i++) { + /* Do nothing. */ + } + ecc_sets_count = i; +#endif + + /* Assume we are going to return total count. */ + cnt = ecc_sets_count; + /* Check we have a list that can hold data. */ + if ((curves != NULL) && (len != 0)) { + /* Limit count to length of list. */ + if (cnt > len) { + cnt = len; + } + + /* Put in built-in EC curve nid and short name. */ + for (i = 0; i < cnt; i++) { + curves[i].nid = EccEnumToNID(ecc_sets[i].id); + curves[i].comment = wolfSSL_OBJ_nid2sn(curves[i].nid); + } + } + + return cnt; +} +#endif /* !HAVE_FIPS || FIPS_VERSION_GT(2,0) */ + +/* Start ECDSA_SIG */ + +/* Allocate a new ECDSA signature object. + * + * @return New, allocated ECDSA signature object on success. + * @return NULL on error. + */ +WOLFSSL_ECDSA_SIG *wolfSSL_ECDSA_SIG_new(void) +{ + int err = 0; + WOLFSSL_ECDSA_SIG *sig; + + WOLFSSL_ENTER("wolfSSL_ECDSA_SIG_new"); + + /* Allocate memory for ECDSA signature object. */ + sig = (WOLFSSL_ECDSA_SIG*)XMALLOC(sizeof(WOLFSSL_ECDSA_SIG), NULL, + DYNAMIC_TYPE_ECC); + if (sig == NULL) { + WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA signature failure"); + err = 1; + } + + if (!err) { + /* Set s to NULL in case of error. */ + sig->s = NULL; + /* Allocate BN into r. */ + sig->r = wolfSSL_BN_new(); + if (sig->r == NULL) { + WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA r failure"); + err = 1; + } + } + if (!err) { + /* Allocate BN into s. */ + sig->s = wolfSSL_BN_new(); + if (sig->s == NULL) { + WOLFSSL_MSG("wolfSSL_ECDSA_SIG_new malloc ECDSA s failure"); + err = 1; + } + } + + if (err && (sig != NULL)) { + /* Dispose of allocated memory. */ + wolfSSL_ECDSA_SIG_free(sig); + sig = NULL; + } + return sig; +} + +/* Dispose of ECDSA signature object. + * + * Cannot use object after this call. + * + * @param [in] sig ECDSA signature object to free. + */ +void wolfSSL_ECDSA_SIG_free(WOLFSSL_ECDSA_SIG *sig) +{ + WOLFSSL_ENTER("wolfSSL_ECDSA_SIG_free"); + + if (sig != NULL) { + /* Dispose of BNs allocated for r and s. */ + wolfSSL_BN_free(sig->r); + wolfSSL_BN_free(sig->s); + + /* Dispose of memory associated with ECDSA signature object. */ + XFREE(sig, NULL, DYNAMIC_TYPE_ECC); + } +} + +/* Create an ECDSA signature from the DER encoding. + * + * @param [in, out] sig Reference to ECDSA signature object. May be NULL. + * @param [in, out] pp On in, reference to buffer containing DER encoding. + * On out, reference to buffer after signature data. + * @param [in] len Length of the data in the buffer. May be more than + * the length of the signature. + * @return ECDSA signature object on success. + * @return NULL on error. + */ +WOLFSSL_ECDSA_SIG* wolfSSL_d2i_ECDSA_SIG(WOLFSSL_ECDSA_SIG** sig, + const unsigned char** pp, long len) +{ + int err = 0; + /* ECDSA signature object to return. */ + WOLFSSL_ECDSA_SIG *s = NULL; + + /* Validate parameter. */ + if (pp == NULL) { + err = 1; + } + if (!err) { + if (sig != NULL) { + /* Use the ECDSA signature object passed in. */ + s = *sig; + } + if (s == NULL) { + /* No ECDSA signature object passed in - create a new one. */ + s = wolfSSL_ECDSA_SIG_new(); + if (s == NULL) { + err = 1; + } + } + } + if (!err) { + /* DecodeECC_DSA_Sig calls mp_init, so free these. */ + mp_free((mp_int*)s->r->internal); + mp_free((mp_int*)s->s->internal); + + /* Decode the signature into internal r and s fields. */ + if (DecodeECC_DSA_Sig(*pp, (word32)len, (mp_int*)s->r->internal, + (mp_int*)s->s->internal) != MP_OKAY) { + err = 1; + } + } + + if (!err) { + /* Move pointer passed signature data successfully decoded. */ + *pp += wolfssl_der_length(*pp, (int)len); + if (sig != NULL) { + /* Update reference to ECDSA signature object. */ + *sig = s; + } + } + + /* Dispose of newly allocated object on error. */ + if (err) { + if ((s != NULL) && ((sig == NULL) || (*sig != s))) { + wolfSSL_ECDSA_SIG_free(s); + } + /* Return NULL for object on error. */ + s = NULL; + } + return s; +} + +/* Encode the ECDSA signature as DER. + * + * @param [in] sig ECDSA signature object. + * @param [in, out] pp On in, reference to buffer in which to place encoding. + * On out, reference to buffer after encoding. + * May be NULL or point to NULL in which case no encoding + * is done. + * @return Length of encoding on success. + * @return 0 on error. + */ +int wolfSSL_i2d_ECDSA_SIG(const WOLFSSL_ECDSA_SIG *sig, unsigned char **pp) +{ + word32 len = 0; + int update_p = 1; + + /* Validate parameter. */ + if (sig != NULL) { + /* ASN.1: SEQ + INT + INT + * ASN.1 Integer must be a positive value - prepend zero if number has + * top bit set. + */ + /* Get total length of r including any prepended zero. */ + word32 rLen = (word32)(mp_leading_bit((mp_int*)sig->r->internal) + + mp_unsigned_bin_size((mp_int*)sig->r->internal)); + /* Get total length of s including any prepended zero. */ + word32 sLen = (word32)(mp_leading_bit((mp_int*)sig->s->internal) + + mp_unsigned_bin_size((mp_int*)sig->s->internal)); + /* Calculate length of data in sequence. */ + len = (word32)1 + ASN_LEN_SIZE(rLen) + rLen + + (word32)1 + ASN_LEN_SIZE(sLen) + sLen; + /* Add in the length of the SEQUENCE. */ + len += (word32)1 + ASN_LEN_SIZE(len); + + #ifdef WOLFSSL_I2D_ECDSA_SIG_ALLOC + if ((pp != NULL) && (*pp == NULL)) { + *pp = (unsigned char *)XMALLOC(len, NULL, DYNAMIC_TYPE_OPENSSL); + if (*pp != NULL) { + WOLFSSL_MSG("malloc error"); + return 0; + } + update_p = 0; + } + #endif + + /* Encode only if there is a buffer to encode into. */ + if ((pp != NULL) && (*pp != NULL)) { + /* Encode using the internal representations of r and s. */ + if (StoreECC_DSA_Sig(*pp, &len, (mp_int*)sig->r->internal, + (mp_int*)sig->s->internal) != MP_OKAY) { + /* No bytes encoded. */ + len = 0; + } + else if (update_p) { + /* Update pointer to after encoding. */ + *pp += len; + } + } + } + + return (int)len; +} + +/* Get the pointer to the fields of the ECDSA signature. + * + * r and s untouched when sig is NULL. + * + * @param [in] sig ECDSA signature object. + * @param [out] r R field of ECDSA signature as a BN. May be NULL. + * @param [out] s S field of ECDSA signature as a BN. May be NULL. + */ +void wolfSSL_ECDSA_SIG_get0(const WOLFSSL_ECDSA_SIG* sig, + const WOLFSSL_BIGNUM** r, const WOLFSSL_BIGNUM** s) +{ + /* Validate parameter. */ + if (sig != NULL) { + /* Return the r BN when pointer to return through. */ + if (r != NULL) { + *r = sig->r; + } + /* Return the s BN when pointer to return through. */ + if (s != NULL) { + *s = sig->s; + } + } +} + +/* Set the pointers to the fields of the ECDSA signature. + * + * @param [in, out] sig ECDSA signature object to update. + * @param [in] r R field of ECDSA signature as a BN. + * @param [in] s S field of ECDSA signature as a BN. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_ECDSA_SIG_set0(WOLFSSL_ECDSA_SIG* sig, WOLFSSL_BIGNUM* r, + WOLFSSL_BIGNUM* s) +{ + int ret = 1; + + /* Validate parameters. */ + if ((sig == NULL) || (r == NULL) || (s == NULL)) { + ret = 0; + } + + if (ret == 1) { + /* Dispose of old BN objects. */ + wolfSSL_BN_free(sig->r); + wolfSSL_BN_free(sig->s); + + /* Assign new BN objects. */ + sig->r = r; + sig->s = s; + } + + return ret; +} + +/* End ECDSA_SIG */ + +/* Start ECDSA */ + +/* Calculate maximum size of the DER encoded ECDSA signature for the curve. + * + * @param [in] key EC key. + * @return Size of DER encoded signature on success. + * @return 0 on error. + */ +int wolfSSL_ECDSA_size(const WOLFSSL_EC_KEY *key) +{ + int err = 0; + int len = 0; + const WOLFSSL_EC_GROUP *group = NULL; + int bits = 0; + + /* Validate parameter. */ + if (key == NULL) { + err = 1; + } + + /* Get group from key to get order bits. */ + if ((!err) && ((group = wolfSSL_EC_KEY_get0_group(key)) == NULL)) { + err = 1; + } + /* Get order bits of group. */ + if ((!err) && ((bits = wolfSSL_EC_GROUP_order_bits(group)) == 0)) { + /* Group is not set. */ + err = 1; + } + + if (!err) { + /* r and s are mod order. */ + int bytes = (bits + 7) / 8; /* Bytes needed to hold bits. */ + len = SIG_HEADER_SZ + /* 2*ASN_TAG + 2*LEN(ENUM) */ + ECC_MAX_PAD_SZ + /* possible leading zeroes in r and s */ + bytes + bytes; /* max r and s in bytes */ + } + + return len; +} + +/* Create ECDSA signature by signing digest with key. + * + * @param [in] dgst Digest to sign. + * @param [in] dLen Length of digest in bytes. + * @param [in] key EC key to sign with. + * @return ECDSA signature object on success. + * @return NULL on error. + */ +WOLFSSL_ECDSA_SIG *wolfSSL_ECDSA_do_sign(const unsigned char *dgst, int dLen, + WOLFSSL_EC_KEY *key) +{ + int err = 0; + WOLFSSL_ECDSA_SIG *sig = NULL; + WC_DECLARE_VAR(out, byte, ECC_BUFSIZE, 0); + unsigned int outLen = ECC_BUFSIZE; + + WOLFSSL_ENTER("wolfSSL_ECDSA_do_sign"); + + /* Validate parameters. */ + if ((dgst == NULL) || (key == NULL) || (key->internal == NULL)) { + WOLFSSL_MSG("wolfSSL_ECDSA_do_sign Bad arguments"); + err = 1; + } + + /* Ensure internal EC key is set from external. */ + if ((!err) && (key->inSet == 0)) { + WOLFSSL_MSG("wolfSSL_ECDSA_do_sign No EC key internal set, do it"); + + if (SetECKeyInternal(key) != 1) { + WOLFSSL_MSG("wolfSSL_ECDSA_do_sign SetECKeyInternal failed"); + err = 1; + } + } + +#ifdef WOLFSSL_SMALL_STACK + if (!err) { + /* Allocate buffer to hold encoded signature. */ + out = (byte*)XMALLOC(outLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (out == NULL) { + err = 1; + } + } +#endif + + /* Sign the digest with the key to create encoded ECDSA signature. */ + if ((!err) && (wolfSSL_ECDSA_sign(0, dgst, dLen, out, &outLen, key) != 1)) { + err = 1; + } + + if (!err) { + const byte* p = out; + /* Decode the ECDSA signature into a new object. */ + sig = wolfSSL_d2i_ECDSA_SIG(NULL, &p, outLen); + } + + WC_FREE_VAR_EX(out, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return sig; +} + +/* Verify ECDSA signature in the object using digest and key. + * + * Return code compliant with OpenSSL. + * + * @param [in] dgst Digest to verify. + * @param [in] dLen Length of the digest in bytes. + * @param [in] sig ECDSA signature object. + * @param [in] key EC key containing public key. + * @return 1 when signature is valid. + * @return 0 when signature is invalid. + * @return -1 on error. + */ +int wolfSSL_ECDSA_do_verify(const unsigned char *dgst, int dLen, + const WOLFSSL_ECDSA_SIG *sig, WOLFSSL_EC_KEY *key) +{ + int ret = 1; + int verified = 0; +#ifdef WOLF_CRYPTO_CB_ONLY_ECC + byte signature[ECC_MAX_SIG_SIZE]; + int signatureLen; + byte* p = signature; +#endif + + WOLFSSL_ENTER("wolfSSL_ECDSA_do_verify"); + + /* Validate parameters. */ + if ((dgst == NULL) || (sig == NULL) || (key == NULL) || + (key->internal == NULL)) { + WOLFSSL_MSG("wolfSSL_ECDSA_do_verify Bad arguments"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* Ensure internal EC key is set from external. */ + if ((ret == 1) && (key->inSet == 0)) { + WOLFSSL_MSG("No EC key internal set, do it"); + + if (SetECKeyInternal(key) != 1) { + WOLFSSL_MSG("SetECKeyInternal failed"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 1) { +#ifndef WOLF_CRYPTO_CB_ONLY_ECC + /* Verify hash using digest, r and s as MP ints and internal EC key. */ + if (wc_ecc_verify_hash_ex((mp_int*)sig->r->internal, + (mp_int*)sig->s->internal, dgst, (word32)dLen, &verified, + (ecc_key *)key->internal) != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_verify_hash failed"); + ret = WOLFSSL_FATAL_ERROR; + } + else if (verified == 0) { + WOLFSSL_MSG("wc_ecc_verify_hash incorrect signature detected"); + ret = 0; + } +#else + signatureLen = i2d_ECDSA_SIG(sig, &p); + if (signatureLen > 0) { + /* verify hash. expects to call wc_CryptoCb_EccVerify internally */ + ret = wc_ecc_verify_hash(signature, signatureLen, dgst, + (word32)dLen, &verified, (ecc_key*)key->internal); + if (ret != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_verify_hash failed"); + ret = WOLFSSL_FATAL_ERROR; + } + else if (verified == 0) { + WOLFSSL_MSG("wc_ecc_verify_hash incorrect signature detected"); + ret = 0; + } + } +#endif /* WOLF_CRYPTO_CB_ONLY_ECC */ + } + + return ret; +} + +/* Sign the digest with the key to produce a DER encode signature. + * + * @param [in] type Digest algorithm used to create digest. Unused. + * @param [in] digest Digest of the message to sign. + * @param [in] digestSz Size of the digest in bytes. + * @param [out] sig Buffer to hold signature. + * @param [in, out] sigSz On in, size of buffer in bytes. + * On out, size of signatre in bytes. + * @param [in] key EC key containing private key. + * @return 1 on success. + * @return 0 on error. + */ +int wolfSSL_ECDSA_sign(int type, const unsigned char *digest, int digestSz, + unsigned char *sig, unsigned int *sigSz, WOLFSSL_EC_KEY *key) +{ + int ret = 1; + WC_RNG* rng = NULL; + WC_DECLARE_VAR(tmpRng, WC_RNG, 1, 0); + int initTmpRng = 0; + + WOLFSSL_ENTER("wolfSSL_ECDSA_sign"); + + /* Digest algorithm not used in DER encoding. */ + (void)type; + + /* Validate parameters. */ + if (key == NULL) { + ret = 0; + } + + if (ret == 1) { + /* Make an RNG - create local or get global. */ + rng = wolfssl_make_rng(tmpRng, &initTmpRng); + if (rng == NULL) { + ret = 0; + } + } + /* Sign the digest with the key using the RNG and put signature into buffer + * update sigSz to be actual length. + */ + if ((ret == 1) && (wc_ecc_sign_hash(digest, (word32)digestSz, sig, sigSz, + rng, (ecc_key*)key->internal) != 0)) { + ret = 0; + } + + if (initTmpRng) { + wc_FreeRng(rng); + WC_FREE_VAR_EX(rng, NULL, DYNAMIC_TYPE_RNG); + } + + return ret; +} + +/* Verify the signature with the digest and key. + * + * @param [in] type Digest algorithm used to create digest. Unused. + * @param [in] digest Digest of the message to verify. + * @param [in] digestSz Size of the digest in bytes. + * @param [in] sig Buffer holding signature. + * @param [in] sigSz Size of signature data in bytes. + * @param [in] key EC key containing public key. + * @return 1 when signature is valid. + * @return 0 when signature is invalid or error. + */ +int wolfSSL_ECDSA_verify(int type, const unsigned char *digest, int digestSz, + const unsigned char *sig, int sigSz, WOLFSSL_EC_KEY *key) +{ + int ret = 1; + int verify = 0; + + WOLFSSL_ENTER("wolfSSL_ECDSA_verify"); + + /* Digest algorithm not used in DER encoding. */ + (void)type; + + /* Validate parameters. */ + if (key == NULL) { + ret = 0; + } + + /* Verify signature using digest and key. */ + if ((ret == 1) && (wc_ecc_verify_hash(sig, (word32)sigSz, digest, + (word32)digestSz, &verify, (ecc_key*)key->internal) != 0)) { + ret = 0; + } + /* When no error, verification may still have failed - check now. */ + if ((ret == 1) && (verify != 1)) { + WOLFSSL_MSG("wolfSSL_ECDSA_verify failed"); + ret = 0; + } + + return ret; +} + +/* End ECDSA */ + +/* Start ECDH */ + +#ifndef WOLF_CRYPTO_CB_ONLY_ECC +/* Compute the shared secret (key) using ECDH. + * + * KDF not supported. + * + * Return code compliant with OpenSSL. + * + * @param [out] out Buffer to hold key. + * @param [in] outLen Length of buffer in bytes. + * @param [in] pubKey Public key as an EC point. + * @param [in] privKey EC key holding a private key. + * @param [in] kdf Key derivation function to apply to secret. + * @return Length of computed key on success + * @return 0 on error. + */ +int wolfSSL_ECDH_compute_key(void *out, size_t outLen, + const WOLFSSL_EC_POINT *pubKey, WOLFSSL_EC_KEY *privKey, + void *(*kdf) (const void *in, size_t inlen, void *out, size_t *outLen)) +{ + int err = 0; + word32 len = 0; + ecc_key* key = NULL; +#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,0)) + int setGlobalRNG = 0; +#endif + + /* TODO: support using the KDF. */ + (void)kdf; + + WOLFSSL_ENTER("wolfSSL_ECDH_compute_key"); + + /* Validate parameters. */ + if ((out == NULL) || (pubKey == NULL) || (pubKey->internal == NULL) || + (privKey == NULL) || (privKey->internal == NULL)) { + WOLFSSL_MSG("Bad function arguments"); + err = 1; + } + + /* Ensure internal EC key is set from external. */ + if ((!err) && (privKey->inSet == 0)) { + WOLFSSL_MSG("No EC key internal set, do it"); + + if (SetECKeyInternal(privKey) != 1) { + WOLFSSL_MSG("SetECKeyInternal failed"); + err = 1; + } + } + + if (!err) { + int ret; + + /* Get the internal key. */ + key = (ecc_key*)privKey->internal; + /* Set length into variable of type suitable for wolfSSL API. */ + len = (word32)outLen; + + #if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,0)) + /* An RNG is needed. */ + if (key->rng == NULL) { + key->rng = wolfssl_make_global_rng(); + /* RNG set and needs to be unset. */ + setGlobalRNG = 1; + } + #endif + + PRIVATE_KEY_UNLOCK(); + /* Create secret using wolfSSL. */ + ret = wc_ecc_shared_secret_ex(key, (ecc_point*)pubKey->internal, + (byte *)out, &len); + PRIVATE_KEY_LOCK(); + if (ret != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_shared_secret failed"); + err = 1; + } + } + +#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,0)) + /* Remove global from key. */ + if (setGlobalRNG) { + key->rng = NULL; + } +#endif + + if (err) { + /* Make returned value zero. */ + len = 0; + } + return (int)len; +} +#endif /* WOLF_CRYPTO_CB_ONLY_ECC */ + +/* End ECDH */ + +#ifndef NO_WOLFSSL_STUB +const WOLFSSL_EC_KEY_METHOD *wolfSSL_EC_KEY_OpenSSL(void) +{ + WOLFSSL_STUB("wolfSSL_EC_KEY_OpenSSL"); + + return NULL; +} + +WOLFSSL_EC_KEY_METHOD *wolfSSL_EC_KEY_METHOD_new( + const WOLFSSL_EC_KEY_METHOD *meth) +{ + WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_new"); + + (void)meth; + + return NULL; +} + +void wolfSSL_EC_KEY_METHOD_free(WOLFSSL_EC_KEY_METHOD *meth) +{ + WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_free"); + + (void)meth; +} + +void wolfSSL_EC_KEY_METHOD_set_init(WOLFSSL_EC_KEY_METHOD *meth, + void* a1, void* a2, void* a3, void* a4, void* a5, void* a6) +{ + WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_set_init"); + + (void)meth; + (void)a1; + (void)a2; + (void)a3; + (void)a4; + (void)a5; + (void)a6; +} + +void wolfSSL_EC_KEY_METHOD_set_sign(WOLFSSL_EC_KEY_METHOD *meth, + void* a1, void* a2, void* a3) +{ + WOLFSSL_STUB("wolfSSL_EC_KEY_METHOD_set_sign"); + + (void)meth; + (void)a1; + (void)a2; + (void)a3; +} + +const WOLFSSL_EC_KEY_METHOD *wolfSSL_EC_KEY_get_method( + const WOLFSSL_EC_KEY *key) +{ + WOLFSSL_STUB("wolfSSL_EC_KEY_get_method"); + + (void)key; + + return NULL; +} + +int wolfSSL_EC_KEY_set_method(WOLFSSL_EC_KEY *key, + const WOLFSSL_EC_KEY_METHOD *meth) +{ + WOLFSSL_STUB("wolfSSL_EC_KEY_set_method"); + + (void)key; + (void)meth; + + return 0; +} + +#endif /* !NO_WOLFSSL_STUB */ + +#endif /* OPENSSL_EXTRA */ + +#endif /* HAVE_ECC */ + +/******************************************************************************* + * END OF EC API + ******************************************************************************/ + +#endif /* !WOLFSSL_PK_EC_INCLUDED */ + diff --git a/src/pk_rsa.c b/src/pk_rsa.c new file mode 100644 index 0000000000..abef08bf8d --- /dev/null +++ b/src/pk_rsa.c @@ -0,0 +1,3943 @@ +/* pk_rsa.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 + +#include +#ifndef WC_NO_RNG + #include +#endif + +#if !defined(WOLFSSL_PK_RSA_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning pk_rsa.c does not need to be compiled separately from ssl.c + #endif +#else + +#ifndef NO_RSA + #include +#endif + +/******************************************************************************* + * START OF RSA API + ******************************************************************************/ + +#ifndef NO_RSA + +/* + * RSA METHOD + * Could be used to hold function pointers to implementations of RSA operations. + */ + +#if defined(OPENSSL_EXTRA) +/* Return a blank RSA method and set the name and flags. + * + * Only one implementation of RSA operations. + * name is duplicated. + * + * @param [in] name Name to use in method. + * @param [in] flags Flags to set into method. + * @return Newly allocated RSA method on success. + * @return NULL on failure. + */ +WOLFSSL_RSA_METHOD *wolfSSL_RSA_meth_new(const char *name, int flags) +{ + WOLFSSL_RSA_METHOD* meth = NULL; + int name_len = 0; + int err; + + /* Validate name is not NULL. */ + if (name == NULL) + return NULL; + /* Allocate an RSA METHOD to return. */ + meth = (WOLFSSL_RSA_METHOD*)XMALLOC(sizeof(WOLFSSL_RSA_METHOD), NULL, + DYNAMIC_TYPE_OPENSSL); + if (meth == NULL) + return NULL; + + XMEMSET(meth, 0, sizeof(*meth)); + meth->flags = flags; + meth->dynamic = 1; + + name_len = (int)XSTRLEN(name); + meth->name = (char*)XMALLOC((size_t)(name_len + 1), NULL, + DYNAMIC_TYPE_OPENSSL); + err = (meth->name == NULL); + + if (!err) { + XMEMCPY(meth->name, name, (size_t)(name_len + 1)); + } + + if (err) { + /* meth->name won't be allocated on error. */ + XFREE(meth, NULL, DYNAMIC_TYPE_OPENSSL); + meth = NULL; + } + return meth; +} + +/* Default RSA method is one with wolfSSL name and no flags. + * + * @return Newly allocated wolfSSL RSA method on success. + * @return NULL on failure. + */ +const WOLFSSL_RSA_METHOD* wolfSSL_RSA_get_default_method(void) +{ + static const WOLFSSL_RSA_METHOD wolfssl_rsa_meth = { + 0, /* No flags. */ + (char*)"wolfSSL RSA", + 0 /* Static definition. */ + }; + return &wolfssl_rsa_meth; +} + +/* Dispose of RSA method and allocated data. + * + * @param [in] meth RSA method to free. + */ +void wolfSSL_RSA_meth_free(WOLFSSL_RSA_METHOD *meth) +{ + /* Free method if available and dynamically allocated. */ + if ((meth != NULL) && meth->dynamic) { + /* Name was duplicated and must be freed. */ + XFREE(meth->name, NULL, DYNAMIC_TYPE_OPENSSL); + /* Dispose of RSA method. */ + XFREE(meth, NULL, DYNAMIC_TYPE_OPENSSL); + } +} + +#ifndef NO_WOLFSSL_STUB +/* Stub function for any RSA method setting function. + * + * Nothing is stored - not even flags or name. + * + * @param [in] meth RSA method. + * @param [in] p A pointer. + * @return 1 to indicate success. + */ +int wolfSSL_RSA_meth_set(WOLFSSL_RSA_METHOD *meth, void* p) +{ + WOLFSSL_STUB("RSA_METHOD is not implemented."); + + (void)meth; + (void)p; + + return 1; +} +#endif /* !NO_WOLFSSL_STUB */ +#endif /* OPENSSL_EXTRA */ + +/* + * RSA constructor/deconstructor APIs + */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Dispose of RSA key and allocated data. + * + * Cannot use rsa after this call. + * + * @param [in] rsa RSA key to free. + */ +void wolfSSL_RSA_free(WOLFSSL_RSA* rsa) +{ + int doFree = 1; + + WOLFSSL_ENTER("wolfSSL_RSA_free"); + + /* Validate parameter. */ + if (rsa == NULL) { + doFree = 0; + } + if (doFree) { + int err; + + /* Decrement reference count. */ + wolfSSL_RefDec(&rsa->ref, &doFree, &err); + #ifndef WOLFSSL_REFCNT_ERROR_RETURN + (void)err; + #endif + } + if (doFree) { + void* heap = rsa->heap; + + /* Dispose of allocated reference counting data. */ + wolfSSL_RefFree(&rsa->ref); + + #ifdef HAVE_EX_DATA_CLEANUP_HOOKS + wolfSSL_CRYPTO_cleanup_ex_data(&rsa->ex_data); + #endif + + if (rsa->internal != NULL) { + #if !defined(HAVE_FIPS) && defined(WC_RSA_BLINDING) + /* Check if RNG is owned before freeing it. */ + if (rsa->ownRng) { + WC_RNG* rng = ((RsaKey*)(rsa->internal))->rng; + if ((rng != NULL) && (rng != wolfssl_get_global_rng())) { + wc_FreeRng(rng); + XFREE(rng, heap, DYNAMIC_TYPE_RNG); + } + /* RNG isn't freed by wolfCrypt RSA free. */ + } + #endif + /* Dispose of allocated data in wolfCrypt RSA key. */ + wc_FreeRsaKey((RsaKey*)rsa->internal); + /* Dispose of memory for wolfCrypt RSA key. */ + XFREE(rsa->internal, heap, DYNAMIC_TYPE_RSA); + } + + /* Dispose of external representation of RSA values. */ + wolfSSL_BN_clear_free(rsa->iqmp); + wolfSSL_BN_clear_free(rsa->dmq1); + wolfSSL_BN_clear_free(rsa->dmp1); + wolfSSL_BN_clear_free(rsa->q); + wolfSSL_BN_clear_free(rsa->p); + wolfSSL_BN_clear_free(rsa->d); + wolfSSL_BN_free(rsa->e); + wolfSSL_BN_free(rsa->n); + + #if defined(OPENSSL_EXTRA) + if (rsa->meth) { + wolfSSL_RSA_meth_free((WOLFSSL_RSA_METHOD*)rsa->meth); + } + #endif + + /* Set back to NULLs for safety. */ + ForceZero(rsa, sizeof(*rsa)); + + XFREE(rsa, heap, DYNAMIC_TYPE_RSA); + (void)heap; + } +} + +/* Allocate and initialize a new RSA key. + * + * Not OpenSSL API. + * + * @param [in] heap Heap hint for dynamic memory allocation. + * @param [in] devId Device identifier value. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA* wolfSSL_RSA_new_ex(void* heap, int devId) +{ + WOLFSSL_RSA* rsa = NULL; + RsaKey* key = NULL; + int err = 0; + int rsaKeyInited = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_new"); + + /* Allocate memory for new wolfCrypt RSA key. */ + key = (RsaKey*)XMALLOC(sizeof(RsaKey), heap, DYNAMIC_TYPE_RSA); + if (key == NULL) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_new malloc RsaKey failure"); + err = 1; + } + if (!err) { + /* Allocate memory for new RSA key. */ + rsa = (WOLFSSL_RSA*)XMALLOC(sizeof(WOLFSSL_RSA), heap, + DYNAMIC_TYPE_RSA); + if (rsa == NULL) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_new malloc WOLFSSL_RSA failure"); + err = 1; + } + } + if (!err) { + /* Clear all fields of RSA key. */ + XMEMSET(rsa, 0, sizeof(WOLFSSL_RSA)); + /* Cache heap to use for all allocations. */ + rsa->heap = heap; + #ifdef OPENSSL_EXTRA + /* Always have a method set. */ + rsa->meth = wolfSSL_RSA_get_default_method(); + #endif + + /* Initialize reference counting. */ + wolfSSL_RefInit(&rsa->ref, &err); +#ifdef WOLFSSL_REFCNT_ERROR_RETURN + } + if (!err) { +#endif + /* Initialize wolfCrypt RSA key. */ + if (wc_InitRsaKey_ex(key, heap, devId) != 0) { + WOLFSSL_ERROR_MSG("InitRsaKey WOLFSSL_RSA failure"); + err = 1; + } + else { + rsaKeyInited = 1; + } + } + #if !defined(HAVE_FIPS) && defined(WC_RSA_BLINDING) + if (!err) { + WC_RNG* rng; + + /* Create a local RNG. */ + rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), heap, DYNAMIC_TYPE_RNG); + if ((rng != NULL) && (wc_InitRng_ex(rng, heap, devId) != 0)) { + WOLFSSL_MSG("InitRng failure, attempting to use global RNG"); + XFREE(rng, heap, DYNAMIC_TYPE_RNG); + rng = NULL; + } + + rsa->ownRng = 1; + if (rng == NULL) { + /* Get the wolfSSL global RNG - not thread safe. */ + rng = wolfssl_get_global_rng(); + rsa->ownRng = 0; + } + if (rng == NULL) { + /* Couldn't create global either. */ + WOLFSSL_ERROR_MSG("wolfSSL_RSA_new no WC_RNG for blinding"); + err = 1; + } + else { + /* Set the local or global RNG into the wolfCrypt RSA key. */ + (void)wc_RsaSetRNG(key, rng); + /* Won't fail as key and rng are not NULL. */ + } + } + #endif /* !HAVE_FIPS && WC_RSA_BLINDING */ + if (!err) { + /* Set wolfCrypt RSA key into RSA key. */ + rsa->internal = key; + /* Data from external RSA key has not been set into internal one. */ + rsa->inSet = 0; + } + + if (err) { + /* Dispose of any allocated data on error. */ + /* No failure after RNG allocation - no need to free RNG. */ + if (rsaKeyInited) { + wc_FreeRsaKey(key); + } + XFREE(key, heap, DYNAMIC_TYPE_RSA); + XFREE(rsa, heap, DYNAMIC_TYPE_RSA); + /* Return NULL. */ + rsa = NULL; + } + return rsa; +} + +/* Allocate and initialize a new RSA key. + * + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA* wolfSSL_RSA_new(void) +{ + /* Call wolfSSL API to do work. */ + return wolfSSL_RSA_new_ex(NULL, INVALID_DEVID); +} + +/* Increments ref count of RSA key. + * + * @param [in, out] rsa RSA key. + * @return 1 on success + * @return 0 on error + */ +int wolfSSL_RSA_up_ref(WOLFSSL_RSA* rsa) +{ + int err = 0; + if (rsa != NULL) { + wolfSSL_RefInc(&rsa->ref, &err); + } + return !err; +} + +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +#ifdef OPENSSL_EXTRA + +#if defined(WOLFSSL_KEY_GEN) + +/* Allocate a new RSA key and make it a copy. + * + * Encodes to and from DER to copy. + * + * @param [in] rsa RSA key to duplicate. + * @return RSA key on success. + * @return NULL on error. + */ +WOLFSSL_RSA* wolfSSL_RSAPublicKey_dup(WOLFSSL_RSA *rsa) +{ + WOLFSSL_RSA* ret = NULL; + int derSz = 0; + byte* derBuf = NULL; + int err; + + WOLFSSL_ENTER("wolfSSL_RSAPublicKey_dup"); + + err = (rsa == NULL); + if (!err) { + /* Create a new RSA key to return. */ + ret = wolfSSL_RSA_new(); + if (ret == NULL) { + WOLFSSL_ERROR_MSG("Error creating a new WOLFSSL_RSA structure"); + err = 1; + } + } + if (!err) { + /* Encode RSA public key to copy to DER - allocates DER buffer. */ + if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1, rsa->heap)) < 0) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); + err = 1; + } + } + if (!err) { + /* Decode DER of the RSA public key into new key. */ + if (wolfSSL_RSA_LoadDer_ex(ret, derBuf, derSz, + WOLFSSL_RSA_LOAD_PUBLIC) != 1) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_LoadDer_ex failed"); + err = 1; + } + } + + /* Dispose of any allocated DER buffer. */ + XFREE(derBuf, rsa ? rsa->heap : NULL, DYNAMIC_TYPE_ASN1); + if (err) { + /* Disposes of any created RSA key - on error. */ + wolfSSL_RSA_free(ret); + ret = NULL; + } + return ret; +} + +/* wolfSSL_RSAPrivateKey_dup not supported */ + +#endif /* WOLFSSL_KEY_GEN */ + +static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, + void* heap); + +/* + * RSA to/from bin APIs + */ + +/* Convert RSA public key data to internal. + * + * Creates new RSA key from the DER encoded RSA public key. + * + * @param [out] out Pointer to RSA key to return through. May be NULL. + * @param [in, out] derBuf Pointer to start of DER encoded data. + * @param [in] derSz Length of the data in the DER buffer. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA *wolfSSL_d2i_RSAPublicKey(WOLFSSL_RSA **out, + const unsigned char **derBuf, long derSz) +{ + WOLFSSL_RSA *rsa = NULL; + int err = 0; + + WOLFSSL_ENTER("wolfSSL_d2i_RSAPublicKey"); + + /* Validate parameters. */ + if (derBuf == NULL) { + WOLFSSL_ERROR_MSG("Bad argument"); + err = 1; + } + /* Create a new RSA key to return. */ + if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) { + WOLFSSL_ERROR_MSG("RSA_new failed"); + err = 1; + } + /* Decode RSA key from DER. */ + if ((!err) && (wolfSSL_RSA_LoadDer_ex(rsa, *derBuf, (int)derSz, + WOLFSSL_RSA_LOAD_PUBLIC) != 1)) { + WOLFSSL_ERROR_MSG("RSA_LoadDer failed"); + err = 1; + } + if ((!err) && (out != NULL)) { + /* Return through parameter too. */ + *out = rsa; + /* Move buffer on by the used amount. */ + *derBuf += wolfssl_der_length(*derBuf, (int)derSz); + } + + if (err) { + /* Dispose of any created RSA key. */ + wolfSSL_RSA_free(rsa); + rsa = NULL; + } + return rsa; +} + +/* Convert RSA private key data to internal. + * + * Create a new RSA key from the DER encoded RSA private key. + * + * @param [out] out Pointer to RSA key to return through. May be NULL. + * @param [in, out] derBuf Pointer to start of DER encoded data. + * @param [in] derSz Length of the data in the DER buffer. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA *wolfSSL_d2i_RSAPrivateKey(WOLFSSL_RSA **out, + const unsigned char **derBuf, long derSz) +{ + WOLFSSL_RSA *rsa = NULL; + int err = 0; + + WOLFSSL_ENTER("wolfSSL_d2i_RSAPublicKey"); + + /* Validate parameters. */ + if (derBuf == NULL) { + WOLFSSL_ERROR_MSG("Bad argument"); + err = 1; + } + /* Create a new RSA key to return. */ + if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) { + WOLFSSL_ERROR_MSG("RSA_new failed"); + err = 1; + } + /* Decode RSA key from DER. */ + if ((!err) && (wolfSSL_RSA_LoadDer_ex(rsa, *derBuf, (int)derSz, + WOLFSSL_RSA_LOAD_PRIVATE) != 1)) { + WOLFSSL_ERROR_MSG("RSA_LoadDer failed"); + err = 1; + } + if ((!err) && (out != NULL)) { + /* Return through parameter too. */ + *out = rsa; + /* Move buffer on by the used amount. */ + *derBuf += wolfssl_der_length(*derBuf, (int)derSz); + } + + if (err) { + /* Dispose of any created RSA key. */ + wolfSSL_RSA_free(rsa); + rsa = NULL; + } + return rsa; +} + +/* Converts an internal RSA structure to DER format for the private key. + * + * If "pp" is null then buffer size only is returned. + * If "*pp" is null then a created buffer is set in *pp and the caller is + * responsible for free'ing it. + * + * @param [in] rsa RSA key. + * @param [in, out] pp On in, pointer to allocated buffer or NULL. + * May be NULL. + * On out, newly allocated buffer or pointer to byte after + * encoding in passed in buffer. + * + * @return Size of DER encoding on success + * @return BAD_FUNC_ARG when rsa is NULL. + * @return 0 on failure. + */ +int wolfSSL_i2d_RSAPrivateKey(WOLFSSL_RSA *rsa, unsigned char **pp) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_i2d_RSAPrivateKey"); + + /* Validate parameters. */ + if (rsa == NULL) { + WOLFSSL_ERROR_MSG("Bad Function Arguments"); + ret = BAD_FUNC_ARG; + } + /* Encode the RSA key as a DER. Call allocates buffer into pp. + * No heap hint as this gets returned to the user */ + else if ((ret = wolfSSL_RSA_To_Der_ex(rsa, pp, 0, NULL)) < 0) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); + ret = 0; + } + + /* Size of DER encoding. */ + return ret; +} + +/* Converts an internal RSA structure to DER format for the public key. + * + * If "pp" is null then buffer size only is returned. + * If "*pp" is null then a created buffer is set in *pp and the caller is + * responsible for free'ing it. + * + * @param [in] rsa RSA key. + * @param [in, out] pp On in, pointer to allocated buffer or NULL. + * May be NULL. + * On out, newly allocated buffer or pointer to byte after + * encoding in passed in buffer. + * @return Size of DER encoding on success + * @return BAD_FUNC_ARG when rsa is NULL. + * @return 0 on failure. + */ +int wolfSSL_i2d_RSAPublicKey(WOLFSSL_RSA *rsa, unsigned char **pp) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_i2d_RSAPublicKey"); + + /* check for bad functions arguments */ + if (rsa == NULL) { + WOLFSSL_ERROR_MSG("Bad Function Arguments"); + ret = BAD_FUNC_ARG; + } + /* Encode the RSA key as a DER. Call allocates buffer into pp. + * No heap hint as this gets returned to the user */ + else if ((ret = wolfSSL_RSA_To_Der_ex(rsa, pp, 1, NULL)) < 0) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); + ret = 0; + } + + return ret; +} + +#endif /* OPENSSL_EXTRA */ + +/* + * RSA to/from BIO APIs + */ + +/* wolfSSL_d2i_RSAPublicKey_bio not supported */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || defined(WOLFSSL_HAPROXY) \ + || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) + +#if defined(WOLFSSL_KEY_GEN) && !defined(NO_BIO) + +/* Read DER data from a BIO. + * + * DER structures start with a constructed sequence. Use this to calculate the + * total length of the DER data. + * + * @param [in] bio BIO object to read from. + * @param [out] out Buffer holding DER encoding. + * @return Number of bytes to DER encoding on success. + * @return 0 on failure. + */ +static int wolfssl_read_der_bio(WOLFSSL_BIO* bio, unsigned char** out) +{ + int err = 0; + unsigned char seq[MAX_SEQ_SZ]; + unsigned char* der = NULL; + int derLen = 0; + + /* Read in a minimal amount to get a SEQUENCE header of any size. */ + if (wolfSSL_BIO_read(bio, seq, sizeof(seq)) != sizeof(seq)) { + WOLFSSL_ERROR_MSG("wolfSSL_BIO_read() of sequence failure"); + err = 1; + } + /* Calculate complete DER encoding length. */ + if ((!err) && ((derLen = wolfssl_der_length(seq, sizeof(seq))) <= 0)) { + WOLFSSL_ERROR_MSG("DER SEQUENCE decode failed"); + err = 1; + } + /* Allocate a buffer to read DER data into. */ + if ((!err) && ((der = (unsigned char*)XMALLOC((size_t)derLen, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER)) == NULL)) { + WOLFSSL_ERROR_MSG("Malloc failure"); + err = 1; + } + if ((!err) && (derLen <= (int)sizeof(seq))) { + /* Copy the previously read data into the buffer. */ + XMEMCPY(der, seq, derLen); + } + else if (!err) { + /* Calculate the unread amount. */ + int len = derLen - (int)sizeof(seq); + /* Copy the previously read data into the buffer. */ + XMEMCPY(der, seq, sizeof(seq)); + /* Read rest of DER data from BIO. */ + if (wolfSSL_BIO_read(bio, der + sizeof(seq), len) != len) { + WOLFSSL_ERROR_MSG("wolfSSL_BIO_read() failure"); + err = 1; + } + } + if (!err) { + /* Return buffer through parameter. */ + *out = der; + } + + if (err) { + /* Dispose of any allocated buffer on error. */ + XFREE(der, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + derLen = 0; + } + return derLen; +} + +/* Reads the RSA private key data from a BIO to the internal form. + * + * Creates new RSA key from the DER encoded RSA private key read from the BIO. + * + * @param [in] bio BIO object to read from. + * @param [out] out Pointer to RSA key to return through. May be NULL. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA* wolfSSL_d2i_RSAPrivateKey_bio(WOLFSSL_BIO *bio, WOLFSSL_RSA **out) +{ + WOLFSSL_RSA* key = NULL; + unsigned char* der = NULL; + int derLen = 0; + int err; + + WOLFSSL_ENTER("wolfSSL_d2i_RSAPrivateKey_bio"); + + /* Validate parameters. */ + err = (bio == NULL); + /* Read just DER encoding from BIO - buffer allocated in call. */ + if ((!err) && ((derLen = wolfssl_read_der_bio(bio, &der)) == 0)) { + err = 1; + } + if (!err) { + /* Keep der for call to deallocate. */ + const unsigned char* cder = der; + /* Create an RSA key from the data from the BIO. */ + key = wolfSSL_d2i_RSAPrivateKey(NULL, &cder, derLen); + err = (key == NULL); + } + if ((!err) && (out != NULL)) { + /* Return the created RSA key through the parameter. */ + *out = key; + } + + if (err) { + /* Dispose of created key on error. */ + wolfSSL_RSA_free(key); + key = NULL; + } + /* Dispose of allocated data. */ + XFREE(der, bio ? bio->heap : NULL, DYNAMIC_TYPE_TMP_BUFFER); + return key; +} +#endif /* defined(WOLFSSL_KEY_GEN) && !NO_BIO */ + +#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */ + +/* + * RSA DER APIs + */ + +#ifdef OPENSSL_EXTRA + +/* Create a DER encoding of key. + * + * Not OpenSSL API. + * + * @param [in] rsa RSA key. + * @param [out] outBuf Allocated buffer containing DER encoding. + * May be NULL. + * @param [in] publicKey Whether to encode as public key. + * @param [in] heap Heap hint. + * @return Encoding size on success. + * @return Negative on failure. + */ +int wolfSSL_RSA_To_Der(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, + void* heap) +{ + byte* p = NULL; + int ret; + + if (outBuf != NULL) { + p = *outBuf; + } + ret = wolfSSL_RSA_To_Der_ex(rsa, outBuf, publicKey, heap); + if ((ret > 0) && (p != NULL)) { + *outBuf = p; + } + return ret; +} + +/* Create a DER encoding of key. + * + * Buffer allocated with heap and DYNAMIC_TYPE_TMP_BUFFER. + * + * @param [in] rsa RSA key. + * @param [in, out] outBuf On in, pointer to allocated buffer or NULL. + * May be NULL. + * On out, newly allocated buffer or pointer to byte + * after encoding in passed in buffer. + * @param [in] publicKey Whether to encode as public key. + * @param [in] heap Heap hint. + * @return Encoding size on success. + * @return Negative on failure. + */ +static int wolfSSL_RSA_To_Der_ex(WOLFSSL_RSA* rsa, byte** outBuf, int publicKey, + void* heap) +{ + int ret = 1; + int derSz = 0; + byte* derBuf = NULL; + + WOLFSSL_ENTER("wolfSSL_RSA_To_Der"); + + /* Unused if memory is disabled. */ + (void)heap; + + /* Validate parameters. */ + if ((rsa == NULL) || ((publicKey != 0) && (publicKey != 1))) { + WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", BAD_FUNC_ARG); + ret = BAD_FUNC_ARG; + } + /* Push external RSA data into internal RSA key if not set. */ + if ((ret == 1) && (!rsa->inSet)) { + ret = SetRsaInternal(rsa); + } + /* wc_RsaKeyToPublicDer encode regardless of values. */ + if ((ret == 1) && publicKey && (mp_iszero(&((RsaKey*)rsa->internal)->n) || + mp_iszero(&((RsaKey*)rsa->internal)->e))) { + ret = BAD_FUNC_ARG; + } + + if (ret == 1) { + if (publicKey) { + /* Calculate length of DER encoded RSA public key. */ + derSz = wc_RsaPublicKeyDerSize((RsaKey*)rsa->internal, 1); + if (derSz < 0) { + WOLFSSL_ERROR_MSG("wc_RsaPublicKeyDerSize failed"); + ret = derSz; + } + } + else { + /* Calculate length of DER encoded RSA private key. */ + derSz = wc_RsaKeyToDer((RsaKey*)rsa->internal, NULL, 0); + if (derSz < 0) { + WOLFSSL_ERROR_MSG("wc_RsaKeyToDer failed"); + ret = derSz; + } + } + } + + if ((ret == 1) && (outBuf != NULL)) { + derBuf = *outBuf; + if (derBuf == NULL) { + /* Allocate buffer to hold DER encoded RSA key. */ + derBuf = (byte*)XMALLOC((size_t)derSz, heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) { + WOLFSSL_ERROR_MSG("Memory allocation failed"); + ret = MEMORY_ERROR; + } + } + } + if ((ret == 1) && (outBuf != NULL)) { + if (publicKey > 0) { + /* RSA public key to DER. */ + derSz = wc_RsaKeyToPublicDer((RsaKey*)rsa->internal, derBuf, + (word32)derSz); + } + else { + /* RSA private key to DER. */ + derSz = wc_RsaKeyToDer((RsaKey*)rsa->internal, derBuf, + (word32)derSz); + } + if (derSz < 0) { + WOLFSSL_ERROR_MSG("RSA key encoding failed"); + ret = derSz; + } + else if ((*outBuf) != NULL) { + derBuf = NULL; + *outBuf += derSz; + } + else { + /* Return allocated buffer. */ + *outBuf = derBuf; + } + } + if (ret == 1) { + /* Success - return DER encoding size. */ + ret = derSz; + } + + if ((outBuf != NULL) && (*outBuf != derBuf)) { + /* Not returning buffer, needs to be disposed of. */ + XFREE(derBuf, heap, DYNAMIC_TYPE_TMP_BUFFER); + } + WOLFSSL_LEAVE("wolfSSL_RSA_To_Der", ret); + return ret; +} + +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Load the DER encoded private RSA key. + * + * Not OpenSSL API. + * + * @param [in] rsa RSA key. + * @param [in] derBuf Buffer holding DER encoding. + * @param [in] derSz Length of DER encoding. + * @return 1 on success. + * @return -1 on failure. + */ +int wolfSSL_RSA_LoadDer(WOLFSSL_RSA* rsa, const unsigned char* derBuf, + int derSz) +{ + /* Call implementation that handles both private and public keys. */ + return wolfSSL_RSA_LoadDer_ex(rsa, derBuf, derSz, WOLFSSL_RSA_LOAD_PRIVATE); +} + +/* Load the DER encoded public or private RSA key. + * + * Not OpenSSL API. + * + * @param [in] rsa RSA key. + * @param [in] derBuf Buffer holding DER encoding. + * @param [in] derSz Length of DER encoding. + * @param [in] opt Indicates public or private key. + * (WOLFSSL_RSA_LOAD_PUBLIC or WOLFSSL_RSA_LOAD_PRIVATE) + * @return 1 on success. + * @return -1 on failure. + */ +int wolfSSL_RSA_LoadDer_ex(WOLFSSL_RSA* rsa, const unsigned char* derBuf, + int derSz, int opt) +{ + int ret = 1; + int res; + word32 idx = 0; + word32 algId; + + WOLFSSL_ENTER("wolfSSL_RSA_LoadDer"); + + /* Validate parameters. */ + if ((rsa == NULL) || (rsa->internal == NULL) || (derBuf == NULL) || + (derSz <= 0)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 1) { + rsa->pkcs8HeaderSz = 0; + /* Check if input buffer has PKCS8 header. In the case that it does not + * have a PKCS8 header then do not error out. */ + res = ToTraditionalInline_ex((const byte*)derBuf, &idx, (word32)derSz, + &algId); + if (res > 0) { + /* Store size of PKCS#8 header for encoding. */ + WOLFSSL_MSG("Found PKCS8 header"); + rsa->pkcs8HeaderSz = (word16)idx; + } + /* When decoding and not PKCS#8, return will be ASN_PARSE_E. */ + else if (res != WC_NO_ERR_TRACE(ASN_PARSE_E)) { + /* Something went wrong while decoding. */ + WOLFSSL_ERROR_MSG("Unexpected error with trying to remove PKCS#8 " + "header"); + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 1) { + /* Decode private or public key data. */ + if (opt == WOLFSSL_RSA_LOAD_PRIVATE) { + res = wc_RsaPrivateKeyDecode(derBuf, &idx, (RsaKey*)rsa->internal, + (word32)derSz); + } + else { + res = wc_RsaPublicKeyDecode(derBuf, &idx, (RsaKey*)rsa->internal, + (word32)derSz); + } + /* Check for error. */ + if (res < 0) { + if (opt == WOLFSSL_RSA_LOAD_PRIVATE) { + WOLFSSL_ERROR_MSG("RsaPrivateKeyDecode failed"); + } + else { + WOLFSSL_ERROR_MSG("RsaPublicKeyDecode failed"); + } + WOLFSSL_ERROR_VERBOSE(res); + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 1) { + /* Set external RSA key data from wolfCrypt key. */ + if (SetRsaExternal(rsa) != 1) { + ret = WOLFSSL_FATAL_ERROR; + } + else { + rsa->inSet = 1; + } + } + + return ret; +} + +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) + +#if !defined(NO_BIO) || !defined(NO_FILESYSTEM) +/* Load DER encoded data into WOLFSSL_RSA object. + * + * Creates a new WOLFSSL_RSA object if one is not passed in. + * + * @param [in, out] rsa WOLFSSL_RSA object to load into. + * When rsa or *rsa is NULL a new object is created. + * When not NULL and *rsa is NULL then new object + * returned through pointer. + * @param [in] in DER encoded RSA key data. + * @param [in] inSz Size of DER encoded data in bytes. + * @param [in] opt Public or private key encoded in data. Valid values: + * WOLFSSL_RSA_LOAD_PRIVATE, WOLFSSL_RSA_LOAD_PUBLIC. + * @return NULL on failure. + * @return WOLFSSL_RSA object on success. + */ +static WOLFSSL_RSA* wolfssl_rsa_d2i(WOLFSSL_RSA** rsa, const unsigned char* in, + long inSz, int opt) +{ + WOLFSSL_RSA* ret = NULL; + + if ((rsa != NULL) && (*rsa != NULL)) { + ret = *rsa; + } + else { + ret = wolfSSL_RSA_new(); + } + if ((ret != NULL) && (wolfSSL_RSA_LoadDer_ex(ret, in, (int)inSz, opt) + != 1)) { + if ((rsa == NULL) || (ret != *rsa)) { + wolfSSL_RSA_free(ret); + } + ret = NULL; + } + + if ((rsa != NULL) && (*rsa == NULL)) { + *rsa = ret; + } + return ret; +} +#endif + +#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ + +/* + * RSA PEM APIs + */ + +#ifdef OPENSSL_EXTRA + +#ifndef NO_BIO +#if defined(WOLFSSL_KEY_GEN) +/* Writes PEM encoding of an RSA public key to a BIO. + * + * @param [in] bio BIO object to write to. + * @param [in] rsa RSA key to write. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_bio_RSA_PUBKEY(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa) +{ + int ret = 1; + int derSz = 0; + byte* derBuf = NULL; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_RSA_PUBKEY"); + + /* Validate parameters. */ + if ((bio == NULL) || (rsa == NULL)) { + WOLFSSL_ERROR_MSG("Bad Function Arguments"); + return 0; + } + + if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1, bio->heap)) < 0) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); + ret = 0; + } + if (derBuf == NULL) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed to get buffer"); + ret = 0; + } + if ((ret == 1) && (der_write_to_bio_as_pem(derBuf, derSz, bio, + PUBLICKEY_TYPE) != 1)) { + ret = 0; + } + + /* Dispose of DER buffer. */ + XFREE(derBuf, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} + +#endif /* WOLFSSL_KEY_GEN */ +#endif /* !NO_BIO */ + +#if defined(WOLFSSL_KEY_GEN) +#ifndef NO_FILESYSTEM + +/* Writes PEM encoding of an RSA public key to a file pointer. + * + * @param [in] fp File pointer to write to. + * @param [in] rsa RSA key to write. + * @param [in] type PEM type to write out. + * @return 1 on success. + * @return 0 on failure. + */ +static int wolfssl_pem_write_rsa_public_key(XFILE fp, WOLFSSL_RSA* rsa, + int type) +{ + int ret = 1; + int derSz; + byte* derBuf = NULL; + + /* Validate parameters. */ + if ((fp == XBADFILE) || (rsa == NULL)) { + WOLFSSL_ERROR_MSG("Bad Function Arguments"); + return 0; + } + + if ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 1, rsa->heap)) < 0) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); + ret = 0; + } + if (derBuf == NULL) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed to get buffer"); + ret = 0; + } + if ((ret == 1) && (der_write_to_file_as_pem(derBuf, derSz, fp, type, + rsa->heap) != 1)) { + ret = 0; + } + + /* Dispose of DER buffer. */ + XFREE(derBuf, rsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +/* Writes PEM encoding of an RSA public key to a file pointer. + * + * Header/footer will contain: PUBLIC KEY + * + * @param [in] fp File pointer to write to. + * @param [in] rsa RSA key to write. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_RSA_PUBKEY(XFILE fp, WOLFSSL_RSA* rsa) +{ + return wolfssl_pem_write_rsa_public_key(fp, rsa, PUBLICKEY_TYPE); +} + +/* Writes PEM encoding of an RSA public key to a file pointer. + * + * Header/footer will contain: RSA PUBLIC KEY + * + * @param [in] fp File pointer to write to. + * @param [in] rsa RSA key to write. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_RSAPublicKey(XFILE fp, WOLFSSL_RSA* rsa) +{ + return wolfssl_pem_write_rsa_public_key(fp, rsa, RSA_PUBLICKEY_TYPE); +} +#endif /* !NO_FILESYSTEM */ +#endif /* WOLFSSL_KEY_GEN */ + +#ifndef NO_BIO +/* Create an RSA public key by reading the PEM encoded data from the BIO. + * + * @param [in] bio BIO object to read from. + * @param [out] out RSA key created. + * @param [in] cb Password callback when PEM encrypted. + * @param [in] pass NUL terminated string for passphrase when PEM encrypted. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA *wolfSSL_PEM_read_bio_RSA_PUBKEY(WOLFSSL_BIO* bio, + WOLFSSL_RSA** out, wc_pem_password_cb* cb, void *pass) +{ + WOLFSSL_RSA* rsa = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_RSA_PUBKEY"); + + if ((bio != NULL) && (pem_read_bio_key(bio, cb, pass, PUBLICKEY_TYPE, + &keyFormat, &der) >= 0)) { + rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, + WOLFSSL_RSA_LOAD_PUBLIC); + if (rsa == NULL) { + WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); + } + } + + FreeDer(&der); + if ((out != NULL) && (rsa != NULL)) { + *out = rsa; + } + return rsa; +} + +WOLFSSL_RSA *wolfSSL_d2i_RSA_PUBKEY_bio(WOLFSSL_BIO *bio, WOLFSSL_RSA **out) +{ + char* data = NULL; + int dataSz = 0; + int memAlloced = 0; + WOLFSSL_RSA* rsa = NULL; + + WOLFSSL_ENTER("wolfSSL_d2i_RSA_PUBKEY_bio"); + + if (bio == NULL) + return NULL; + + if (wolfssl_read_bio(bio, &data, &dataSz, &memAlloced) != 0) { + if (memAlloced) + XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + + rsa = wolfssl_rsa_d2i(out, (const unsigned char*)data, dataSz, + WOLFSSL_RSA_LOAD_PUBLIC); + if (memAlloced) + XFREE(data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return rsa; +} +#endif /* !NO_BIO */ + +#ifndef NO_FILESYSTEM +/* Create an RSA public key by reading the PEM encoded data from the BIO. + * + * Header/footer should contain: PUBLIC KEY + * PEM decoder supports either 'RSA PUBLIC KEY' or 'PUBLIC KEY'. + * + * @param [in] fp File pointer to read from. + * @param [out] out RSA key created. + * @param [in] cb Password callback when PEM encrypted. + * @param [in] pass NUL terminated string for passphrase when PEM encrypted. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA *wolfSSL_PEM_read_RSA_PUBKEY(XFILE fp, + WOLFSSL_RSA** out, wc_pem_password_cb* cb, void *pass) +{ + WOLFSSL_RSA* rsa = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_RSA_PUBKEY"); + + if ((fp != XBADFILE) && (pem_read_file_key(fp, cb, pass, PUBLICKEY_TYPE, + &keyFormat, &der) >= 0)) { + rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, + WOLFSSL_RSA_LOAD_PUBLIC); + if (rsa == NULL) { + WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); + } + } + + FreeDer(&der); + if ((out != NULL) && (rsa != NULL)) { + *out = rsa; + } + return rsa; +} + +/* Create an RSA public key by reading the PEM encoded data from the BIO. + * + * Header/footer should contain: RSA PUBLIC KEY + * PEM decoder supports either 'RSA PUBLIC KEY' or 'PUBLIC KEY'. + * + * @param [in] fp File pointer to read from. + * @param [out] rsa RSA key created. + * @param [in] cb Password callback when PEM encrypted. May be NULL. + * @param [in] pass NUL terminated string for passphrase when PEM encrypted. + * May be NULL. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA* wolfSSL_PEM_read_RSAPublicKey(XFILE fp, WOLFSSL_RSA** rsa, + wc_pem_password_cb* cb, void* pass) +{ + return wolfSSL_PEM_read_RSA_PUBKEY(fp, rsa, cb, pass); +} + +#endif /* NO_FILESYSTEM */ + +#if defined(WOLFSSL_KEY_GEN) && \ + (defined(WOLFSSL_PEM_TO_DER) || defined(WOLFSSL_DER_TO_PEM)) + +/* Writes PEM encoding of an RSA private key to newly allocated buffer. + * + * Buffer returned was allocated with: DYNAMIC_TYPE_KEY. + * + * @param [in] rsa RSA key to write. + * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. + * @param [in] passwd Password string when PEM encrypted. May be NULL. + * @param [in] passwdSz Length of password string when PEM encrypted. + * @param [out] pem Allocated buffer with PEM encoding. + * @param [out] pLen Length of PEM encoding. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_mem_RSAPrivateKey(WOLFSSL_RSA* rsa, + const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int passwdSz, + unsigned char **pem, int *pLen) +{ + int ret = 1; + byte* derBuf = NULL; + int derSz = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_write_mem_RSAPrivateKey"); + + /* Validate parameters. */ + if ((pem == NULL) || (pLen == NULL) || (rsa == NULL) || + (rsa->internal == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = 0; + } + + /* Set the RSA key data into the wolfCrypt RSA key if not done so. */ + if ((ret == 1) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { + ret = 0; + } + + /* Encode wolfCrypt RSA key to DER - derBuf allocated in call. */ + if ((ret == 1) && ((derSz = wolfSSL_RSA_To_Der(rsa, &derBuf, 0, + rsa->heap)) < 0)) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_To_Der failed"); + ret = 0; + } + + if ((ret == 1) && (der_to_enc_pem_alloc(derBuf, derSz, cipher, passwd, + passwdSz, PRIVATEKEY_TYPE, NULL, pem, pLen) != 1)) { + WOLFSSL_ERROR_MSG("der_to_enc_pem_alloc failed"); + ret = 0; + } + + return ret; +} + +#ifndef NO_BIO +/* Writes PEM encoding of an RSA private key to a BIO. + * + * @param [in] bio BIO object to write to. + * @param [in] rsa RSA key to write. + * @param [in] cipher Cipher to use when PEM encrypted. + * @param [in] passwd Password string when PEM encrypted. + * @param [in] len Length of password string when PEM encrypted. + * @param [in] cb Password callback to use when PEM encrypted. + * @param [in] arg NUL terminated string for passphrase when PEM encrypted. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_bio_RSAPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa, + const WOLFSSL_EVP_CIPHER* cipher, unsigned char* passwd, int len, + wc_pem_password_cb* cb, void* arg) +{ + int ret = 1; + byte* pem = NULL; + int pLen = 0; + + (void)cb; + (void)arg; + + WOLFSSL_ENTER("wolfSSL_PEM_write_bio_RSAPrivateKey"); + + /* Validate parameters. */ + if ((bio == NULL) || (rsa == NULL) || (rsa->internal == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = 0; + } + + if (ret == 1) { + /* Write PEM to buffer that is allocated in the call. */ + ret = wolfSSL_PEM_write_mem_RSAPrivateKey(rsa, cipher, passwd, len, + &pem, &pLen); + if (ret != 1) { + WOLFSSL_ERROR_MSG("wolfSSL_PEM_write_mem_RSAPrivateKey failed"); + } + } + /* Write PEM to BIO. */ + if ((ret == 1) && (wolfSSL_BIO_write(bio, pem, pLen) <= 0)) { + WOLFSSL_ERROR_MSG("RSA private key BIO write failed"); + ret = 0; + } + + /* Dispose of any allocated PEM buffer. */ + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + return ret; +} +#endif /* !NO_BIO */ + +#ifndef NO_FILESYSTEM +/* Writes PEM encoding of an RSA private key to a file pointer. + * + * TODO: Support use of the password callback and callback context. + * + * @param [in] fp File pointer to write to. + * @param [in] rsa RSA key to write. + * @param [in] cipher Cipher to use when PEM encrypted. May be NULL. + * @param [in] passwd Password string when PEM encrypted. May be NULL. + * @param [in] passwdSz Length of password string when PEM encrypted. + * @param [in] cb Password callback to use when PEM encrypted. Unused. + * @param [in] arg NUL terminated string for passphrase when PEM + * encrypted. Unused. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_PEM_write_RSAPrivateKey(XFILE fp, WOLFSSL_RSA *rsa, + const WOLFSSL_EVP_CIPHER *cipher, unsigned char *passwd, int passwdSz, + wc_pem_password_cb *cb, void *arg) +{ + int ret = 1; + byte* pem = NULL; + int pLen = 0; + + (void)cb; + (void)arg; + + WOLFSSL_ENTER("wolfSSL_PEM_write_RSAPrivateKey"); + + /* Validate parameters. */ + if ((fp == XBADFILE) || (rsa == NULL) || (rsa->internal == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = 0; + } + + if (ret == 1) { + /* Write PEM to buffer that is allocated in the call. */ + ret = wolfSSL_PEM_write_mem_RSAPrivateKey(rsa, cipher, passwd, passwdSz, + &pem, &pLen); + if (ret != 1) { + WOLFSSL_ERROR_MSG("wolfSSL_PEM_write_mem_RSAPrivateKey failed"); + } + } + /* Write PEM to file pointer. */ + if ((ret == 1) && ((int)XFWRITE(pem, 1, (size_t)pLen, fp) != pLen)) { + WOLFSSL_ERROR_MSG("RSA private key file write failed"); + ret = 0; + } + + /* Dispose of any allocated PEM buffer. */ + XFREE(pem, NULL, DYNAMIC_TYPE_KEY); + return ret; +} +#endif /* NO_FILESYSTEM */ +#endif /* WOLFSSL_KEY_GEN && WOLFSSL_PEM_TO_DER */ + +#ifndef NO_BIO +/* Create an RSA private key by reading the PEM encoded data from the BIO. + * + * @param [in] bio BIO object to read from. + * @param [out] out RSA key created. + * @param [in] cb Password callback when PEM encrypted. + * @param [in] pass NUL terminated string for passphrase when PEM encrypted. + * @return RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA* wolfSSL_PEM_read_bio_RSAPrivateKey(WOLFSSL_BIO* bio, + WOLFSSL_RSA** out, wc_pem_password_cb* cb, void* pass) +{ + WOLFSSL_RSA* rsa = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_bio_RSAPrivateKey"); + + if ((bio != NULL) && (pem_read_bio_key(bio, cb, pass, PRIVATEKEY_TYPE, + &keyFormat, &der) >= 0)) { + rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, + WOLFSSL_RSA_LOAD_PRIVATE); + if (rsa == NULL) { + WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); + } + } + + FreeDer(&der); + if ((out != NULL) && (rsa != NULL)) { + *out = rsa; + } + return rsa; +} +#endif /* !NO_BIO */ + +/* Create an RSA private key by reading the PEM encoded data from the file + * pointer. + * + * @param [in] fp File pointer to read from. + * @param [out] out RSA key created. + * @param [in] cb Password callback when PEM encrypted. + * @param [in] pass NUL terminated string for passphrase when PEM encrypted. + * @return RSA key on success. + * @return NULL on failure. + */ +#ifndef NO_FILESYSTEM +WOLFSSL_RSA* wolfSSL_PEM_read_RSAPrivateKey(XFILE fp, WOLFSSL_RSA** out, + wc_pem_password_cb* cb, void* pass) +{ + WOLFSSL_RSA* rsa = NULL; + DerBuffer* der = NULL; + int keyFormat = 0; + + WOLFSSL_ENTER("wolfSSL_PEM_read_RSAPrivateKey"); + + if ((fp != XBADFILE) && (pem_read_file_key(fp, cb, pass, PRIVATEKEY_TYPE, + &keyFormat, &der) >= 0)) { + rsa = wolfssl_rsa_d2i(out, der->buffer, der->length, + WOLFSSL_RSA_LOAD_PRIVATE); + if (rsa == NULL) { + WOLFSSL_ERROR_MSG("Error loading DER buffer into WOLFSSL_RSA"); + } + } + + FreeDer(&der); + if ((out != NULL) && (rsa != NULL)) { + *out = rsa; + } + return rsa; +} +#endif /* !NO_FILESYSTEM */ + +/* + * RSA print APIs + */ + +#if defined(XFPRINTF) && !defined(NO_FILESYSTEM) && \ + !defined(NO_STDIO_FILESYSTEM) +/* Print an RSA key to a file pointer. + * + * @param [in] fp File pointer to write to. + * @param [in] rsa RSA key to write. + * @param [in] indent Number of spaces to prepend to each line. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_print_fp(XFILE fp, WOLFSSL_RSA* rsa, int indent) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_RSA_print_fp"); + + /* Validate parameters. */ + if ((fp == XBADFILE) || (rsa == NULL)) { + ret = 0; + } + + /* Set the external data from the wolfCrypt RSA key if not done. */ + if ((ret == 1) && (!rsa->exSet)) { + ret = SetRsaExternal(rsa); + } + + /* Get the key size from modulus if available. */ + if ((ret == 1) && (rsa->n != NULL)) { + int keySize = wolfSSL_BN_num_bits(rsa->n); + if (keySize == 0) { + ret = 0; + } + else { + if (XFPRINTF(fp, "%*s", indent, "") < 0) + ret = 0; + else if (XFPRINTF(fp, "RSA Private-Key: (%d bit, 2 primes)\n", + keySize) < 0) + ret = 0; + } + } + /* Print out any components available. */ + if ((ret == 1) && (rsa->n != NULL)) { + ret = pk_bn_field_print_fp(fp, indent, "modulus", rsa->n); + } + if ((ret == 1) && (rsa->d != NULL)) { + ret = pk_bn_field_print_fp(fp, indent, "privateExponent", rsa->d); + } + if ((ret == 1) && (rsa->p != NULL)) { + ret = pk_bn_field_print_fp(fp, indent, "prime1", rsa->p); + } + if ((ret == 1) && (rsa->q != NULL)) { + ret = pk_bn_field_print_fp(fp, indent, "prime2", rsa->q); + } + if ((ret == 1) && (rsa->dmp1 != NULL)) { + ret = pk_bn_field_print_fp(fp, indent, "exponent1", rsa->dmp1); + } + if ((ret == 1) && (rsa->dmq1 != NULL)) { + ret = pk_bn_field_print_fp(fp, indent, "exponent2", rsa->dmq1); + } + if ((ret == 1) && (rsa->iqmp != NULL)) { + ret = pk_bn_field_print_fp(fp, indent, "coefficient", rsa->iqmp); + } + + WOLFSSL_LEAVE("wolfSSL_RSA_print_fp", ret); + + return ret; +} +#endif /* XFPRINTF && !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM */ + +#if defined(XSNPRINTF) && !defined(NO_BIO) +/* snprintf() must be available */ + +/* Maximum size of a header line. */ +#define RSA_PRINT_MAX_HEADER_LINE PRINT_NUM_MAX_INDENT + +/* Writes the human readable form of RSA to a BIO. + * + * @param [in] bio BIO object to write to. + * @param [in] rsa RSA key to write. + * @param [in] indent Number of spaces before each line. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_print(WOLFSSL_BIO* bio, WOLFSSL_RSA* rsa, int indent) +{ + int ret = 1; + int sz = 0; + RsaKey* key = NULL; + char line[RSA_PRINT_MAX_HEADER_LINE]; + int i = 0; + mp_int *num = NULL; + /* Header strings. */ + const char *name[] = { + "Modulus:", "Exponent:", "PrivateExponent:", "Prime1:", "Prime2:", + "Exponent1:", "Exponent2:", "Coefficient:" + }; + + WOLFSSL_ENTER("wolfSSL_RSA_print"); + + /* Validate parameters. */ + if ((bio == NULL) || (rsa == NULL) || (indent > PRINT_NUM_MAX_INDENT)) { + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 1) { + key = (RsaKey*)rsa->internal; + + /* Get size in bits of key for printing out. */ + sz = wolfSSL_RSA_bits(rsa); + if (sz <= 0) { + WOLFSSL_ERROR_MSG("Error getting RSA key size"); + ret = 0; + } + } + if (ret == 1) { + /* Print any indent spaces. */ + ret = wolfssl_print_indent(bio, line, sizeof(line), indent); + } + if (ret == 1) { + /* Print header line. */ + int len = XSNPRINTF(line, sizeof(line), "\nRSA %s: (%d bit)\n", + (!mp_iszero(&key->d)) ? "Private-Key" : "Public-Key", sz); + if (len >= (int)sizeof(line)) { + WOLFSSL_ERROR_MSG("Buffer overflow while formatting key preamble"); + ret = 0; + } + else { + if (wolfSSL_BIO_write(bio, line, len) <= 0) { + ret = 0; + } + } + } + + for (i = 0; (ret == 1) && (i < RSA_INTS); i++) { + /* Get mp_int for index. */ + switch (i) { + case 0: + /* Print out modulus */ + num = &key->n; + break; + case 1: + num = &key->e; + break; + case 2: + num = &key->d; + break; + case 3: + num = &key->p; + break; + case 4: + num = &key->q; + break; + case 5: + num = &key->dP; + break; + case 6: + num = &key->dQ; + break; + case 7: + num = &key->u; + break; + default: + WOLFSSL_ERROR_MSG("Bad index value"); + } + + if (i == 1) { + /* Print exponent as a 32-bit value. */ + ret = wolfssl_print_value(bio, num, name[i], indent); + } + else if (!mp_iszero(num)) { + /* Print name and MP integer. */ + ret = wolfssl_print_number(bio, num, name[i], indent); + } + } + + return ret; +} +#endif /* XSNPRINTF && !NO_BIO */ + +#endif /* OPENSSL_EXTRA */ + +/* + * RSA get/set/test APIs + */ + +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +/* Set RSA key data (external) from wolfCrypt RSA key (internal). + * + * @param [in, out] rsa RSA key. + * @return 1 on success. + * @return 0 on failure. + */ +int SetRsaExternal(WOLFSSL_RSA* rsa) +{ + int ret = 1; + + WOLFSSL_ENTER("SetRsaExternal"); + + /* Validate parameters. */ + if ((rsa == NULL) || (rsa->internal == NULL)) { + WOLFSSL_ERROR_MSG("rsa key NULL error"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 1) { + RsaKey* key = (RsaKey*)rsa->internal; + + /* Copy modulus. */ + ret = wolfssl_bn_set_value(&rsa->n, &key->n); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa n error"); + } + if (ret == 1) { + /* Copy public exponent. */ + ret = wolfssl_bn_set_value(&rsa->e, &key->e); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa e error"); + } + } + + if (key->type == RSA_PRIVATE) { + #ifndef WOLFSSL_RSA_PUBLIC_ONLY + if (ret == 1) { + /* Copy private exponent. */ + ret = wolfssl_bn_set_value(&rsa->d, &key->d); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa d error"); + } + } + if (ret == 1) { + /* Copy first prime. */ + ret = wolfssl_bn_set_value(&rsa->p, &key->p); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa p error"); + } + } + if (ret == 1) { + /* Copy second prime. */ + ret = wolfssl_bn_set_value(&rsa->q, &key->q); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa q error"); + } + } + #if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || \ + !defined(RSA_LOW_MEM) + if (ret == 1) { + /* Copy d mod p-1. */ + ret = wolfssl_bn_set_value(&rsa->dmp1, &key->dP); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa dP error"); + } + } + if (ret == 1) { + /* Copy d mod q-1. */ + ret = wolfssl_bn_set_value(&rsa->dmq1, &key->dQ); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa dq error"); + } + } + if (ret == 1) { + /* Copy 1/q mod p. */ + ret = wolfssl_bn_set_value(&rsa->iqmp, &key->u); + if (ret != 1) { + WOLFSSL_ERROR_MSG("rsa u error"); + } + } + #endif + #else + WOLFSSL_ERROR_MSG("rsa private key not compiled in "); + ret = 0; + #endif /* !WOLFSSL_RSA_PUBLIC_ONLY */ + } + } + if (ret == 1) { + /* External values set. */ + rsa->exSet = 1; + } + else { + /* Return 0 on failure. */ + ret = 0; + } + + return ret; +} +#endif /* (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) */ + +#ifdef OPENSSL_EXTRA + +/* Set wolfCrypt RSA key data (internal) from RSA key (external). + * + * @param [in, out] rsa RSA key. + * @return 1 on success. + * @return 0 on failure. + */ +int SetRsaInternal(WOLFSSL_RSA* rsa) +{ + int ret = 1; + + WOLFSSL_ENTER("SetRsaInternal"); + + /* Validate parameters. */ + if ((rsa == NULL) || (rsa->internal == NULL)) { + WOLFSSL_ERROR_MSG("rsa key NULL error"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 1) { + RsaKey* key = (RsaKey*)rsa->internal; + + /* Copy down modulus if available. */ + if ((rsa->n != NULL) && (wolfssl_bn_get_value(rsa->n, &key->n) != 1)) { + WOLFSSL_ERROR_MSG("rsa n key error"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* Copy down public exponent if available. */ + if ((ret == 1) && (rsa->e != NULL) && + (wolfssl_bn_get_value(rsa->e, &key->e) != 1)) { + WOLFSSL_ERROR_MSG("rsa e key error"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* Enough numbers for public key */ + key->type = RSA_PUBLIC; + +#ifndef WOLFSSL_RSA_PUBLIC_ONLY + /* Copy down private exponent if available. */ + if ((ret == 1) && (rsa->d != NULL)) { + if (wolfssl_bn_get_value(rsa->d, &key->d) != 1) { + WOLFSSL_ERROR_MSG("rsa d key error"); + ret = WOLFSSL_FATAL_ERROR; + } + else { + /* Enough numbers for private key */ + key->type = RSA_PRIVATE; + } + } + + /* Copy down first prime if available. */ + if ((ret == 1) && (rsa->p != NULL) && + (wolfssl_bn_get_value(rsa->p, &key->p) != 1)) { + WOLFSSL_ERROR_MSG("rsa p key error"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* Copy down second prime if available. */ + if ((ret == 1) && (rsa->q != NULL) && + (wolfssl_bn_get_value(rsa->q, &key->q) != 1)) { + WOLFSSL_ERROR_MSG("rsa q key error"); + ret = WOLFSSL_FATAL_ERROR; + } + +#if defined(WOLFSSL_KEY_GEN) || defined(OPENSSL_EXTRA) || !defined(RSA_LOW_MEM) + /* Copy down d mod p-1 if available. */ + if ((ret == 1) && (rsa->dmp1 != NULL) && + (wolfssl_bn_get_value(rsa->dmp1, &key->dP) != 1)) { + WOLFSSL_ERROR_MSG("rsa dP key error"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* Copy down d mod q-1 if available. */ + if ((ret == 1) && (rsa->dmq1 != NULL) && + (wolfssl_bn_get_value(rsa->dmq1, &key->dQ) != 1)) { + WOLFSSL_ERROR_MSG("rsa dQ key error"); + ret = WOLFSSL_FATAL_ERROR; + } + + /* Copy down 1/q mod p if available. */ + if ((ret == 1) && (rsa->iqmp != NULL) && + (wolfssl_bn_get_value(rsa->iqmp, &key->u) != 1)) { + WOLFSSL_ERROR_MSG("rsa u key error"); + ret = WOLFSSL_FATAL_ERROR; + } +#endif +#endif + + if (ret == 1) { + /* All available numbers have been set down. */ + rsa->inSet = 1; + } + } + + return ret; +} + +/* Set the RSA method into object. + * + * @param [in, out] rsa RSA key. + * @param [in] meth RSA method. + * @return 1 always. + */ +int wolfSSL_RSA_set_method(WOLFSSL_RSA *rsa, WOLFSSL_RSA_METHOD *meth) +{ + if (rsa != NULL) { + /* Store the method into object. */ + rsa->meth = meth; + /* Copy over flags. */ + rsa->flags = meth->flags; + } + /* OpenSSL always assumes it will work. */ + return 1; +} + +/* Get the RSA method from the RSA object. + * + * @param [in] rsa RSA key. + * @return RSA method on success. + * @return NULL when RSA is NULL or no method set. + */ +const WOLFSSL_RSA_METHOD* wolfSSL_RSA_get_method(const WOLFSSL_RSA *rsa) +{ + return (rsa != NULL) ? rsa->meth : NULL; +} + +/* Get the size in bytes of the RSA key. + * + * Return compliant with OpenSSL + * + * @param [in] rsa RSA key. + * @return RSA modulus size in bytes. + * @return 0 on error. + */ +int wolfSSL_RSA_size(const WOLFSSL_RSA* rsa) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_size"); + + if (rsa != NULL) { + /* Make sure we have set the RSA values into wolfCrypt RSA key. */ + if (rsa->inSet || (SetRsaInternal((WOLFSSL_RSA*)rsa) == 1)) { + /* Get key size in bytes using wolfCrypt RSA key. */ + ret = wc_RsaEncryptSize((RsaKey*)rsa->internal); + } + } + + return ret; +} + +/* Get the size in bits of the RSA key. + * + * Uses external modulus field. + * + * @param [in] rsa RSA key. + * @return RSA modulus size in bits. + * @return 0 on error. + */ +int wolfSSL_RSA_bits(const WOLFSSL_RSA* rsa) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_bits"); + + if (rsa != NULL) { + /* Get number of bits in external modulus. */ + ret = wolfSSL_BN_num_bits(rsa->n); + } + + return ret; +} + +/* Get the BN objects that are the Chinese-Remainder Theorem (CRT) parameters. + * + * Only for those that are not NULL parameters. + * + * @param [in] rsa RSA key. + * @param [out] dmp1 BN that is d mod (p - 1). May be NULL. + * @param [out] dmq1 BN that is d mod (q - 1). May be NULL. + * @param [out] iqmp BN that is 1/q mod p. May be NULL. + */ +void wolfSSL_RSA_get0_crt_params(const WOLFSSL_RSA *rsa, + const WOLFSSL_BIGNUM **dmp1, const WOLFSSL_BIGNUM **dmq1, + const WOLFSSL_BIGNUM **iqmp) +{ + WOLFSSL_ENTER("wolfSSL_RSA_get0_crt_params"); + + /* For any parameters not NULL, return the BN from the key or NULL. */ + if (dmp1 != NULL) { + *dmp1 = (rsa != NULL) ? rsa->dmp1 : NULL; + } + if (dmq1 != NULL) { + *dmq1 = (rsa != NULL) ? rsa->dmq1 : NULL; + } + if (iqmp != NULL) { + *iqmp = (rsa != NULL) ? rsa->iqmp : NULL; + } +} + +/* Set the BN objects that are the Chinese-Remainder Theorem (CRT) parameters + * into RSA key. + * + * If CRT parameter is NULL then there must be one in the RSA key already. + * + * @param [in, out] rsa RSA key. + * @param [in] dmp1 BN that is d mod (p - 1). May be NULL. + * @param [in] dmq1 BN that is d mod (q - 1). May be NULL. + * @param [in] iqmp BN that is 1/q mod p. May be NULL. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_set0_crt_params(WOLFSSL_RSA *rsa, WOLFSSL_BIGNUM *dmp1, + WOLFSSL_BIGNUM *dmq1, WOLFSSL_BIGNUM *iqmp) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_RSA_set0_crt_params"); + + /* If a param is NULL in rsa then it must be non-NULL in the + * corresponding user input. */ + if ((rsa == NULL) || ((rsa->dmp1 == NULL) && (dmp1 == NULL)) || + ((rsa->dmq1 == NULL) && (dmq1 == NULL)) || + ((rsa->iqmp == NULL) && (iqmp == NULL))) { + WOLFSSL_ERROR_MSG("Bad parameters"); + ret = 0; + } + if (ret == 1) { + /* Replace the BNs. */ + if (dmp1 != NULL) { + wolfSSL_BN_clear_free(rsa->dmp1); + rsa->dmp1 = dmp1; + } + if (dmq1 != NULL) { + wolfSSL_BN_clear_free(rsa->dmq1); + rsa->dmq1 = dmq1; + } + if (iqmp != NULL) { + wolfSSL_BN_clear_free(rsa->iqmp); + rsa->iqmp = iqmp; + } + + /* Set the values into the wolfCrypt RSA key. */ + if (SetRsaInternal(rsa) != 1) { + if (dmp1 != NULL) { + rsa->dmp1 = NULL; + } + if (dmq1 != NULL) { + rsa->dmq1 = NULL; + } + if (iqmp != NULL) { + rsa->iqmp = NULL; + } + ret = 0; + } + } + + return ret; +} + +/* Get the BN objects that are the factors of the RSA key (two primes p and q). + * + * @param [in] rsa RSA key. + * @param [out] p BN that is first prime. May be NULL. + * @param [out] q BN that is second prime. May be NULL. + */ +void wolfSSL_RSA_get0_factors(const WOLFSSL_RSA *rsa, const WOLFSSL_BIGNUM **p, + const WOLFSSL_BIGNUM **q) +{ + WOLFSSL_ENTER("wolfSSL_RSA_get0_factors"); + + /* For any primes not NULL, return the BN from the key or NULL. */ + if (p != NULL) { + *p = (rsa != NULL) ? rsa->p : NULL; + } + if (q != NULL) { + *q = (rsa != NULL) ? rsa->q : NULL; + } +} + +/* Set the BN objects that are the factors of the RSA key (two primes p and q). + * + * If factor parameter is NULL then there must be one in the RSA key already. + * + * @param [in, out] rsa RSA key. + * @param [in] p BN that is first prime. May be NULL. + * @param [in] q BN that is second prime. May be NULL. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_set0_factors(WOLFSSL_RSA *rsa, WOLFSSL_BIGNUM *p, + WOLFSSL_BIGNUM *q) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_RSA_set0_factors"); + + /* If a param is null in r then it must be non-null in the + * corresponding user input. */ + if (rsa == NULL || ((rsa->p == NULL) && (p == NULL)) || + ((rsa->q == NULL) && (q == NULL))) { + WOLFSSL_ERROR_MSG("Bad parameters"); + ret = 0; + } + if (ret == 1) { + /* Replace the BNs. */ + if (p != NULL) { + wolfSSL_BN_clear_free(rsa->p); + rsa->p = p; + } + if (q != NULL) { + wolfSSL_BN_clear_free(rsa->q); + rsa->q = q; + } + + /* Set the values into the wolfCrypt RSA key. */ + if (SetRsaInternal(rsa) != 1) { + if (p != NULL) { + rsa->p = NULL; + } + if (q != NULL) { + rsa->q = NULL; + } + ret = 0; + } + } + + return ret; +} + +/* Get the BN objects for the basic key numbers of the RSA key (modulus, public + * exponent, private exponent). + * + * @param [in] rsa RSA key. + * @param [out] n BN that is the modulus. May be NULL. + * @param [out] e BN that is the public exponent. May be NULL. + * @param [out] d BN that is the private exponent. May be NULL. + */ +void wolfSSL_RSA_get0_key(const WOLFSSL_RSA *rsa, const WOLFSSL_BIGNUM **n, + const WOLFSSL_BIGNUM **e, const WOLFSSL_BIGNUM **d) +{ + WOLFSSL_ENTER("wolfSSL_RSA_get0_key"); + + /* For any parameters not NULL, return the BN from the key or NULL. */ + if (n != NULL) { + *n = (rsa != NULL) ? rsa->n : NULL; + } + if (e != NULL) { + *e = (rsa != NULL) ? rsa->e : NULL; + } + if (d != NULL) { + *d = (rsa != NULL) ? rsa->d : NULL; + } +} + +/* Set the BN objects for the basic key numbers into the RSA key (modulus, + * public exponent, private exponent). + * + * If BN parameter is NULL then there must be one in the RSA key already. + * + * @param [in,out] rsa RSA key. + * @param [in] n BN that is the modulus. May be NULL. + * @param [in] e BN that is the public exponent. May be NULL. + * @param [in] d BN that is the private exponent. May be NULL. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_set0_key(WOLFSSL_RSA *rsa, WOLFSSL_BIGNUM *n, WOLFSSL_BIGNUM *e, + WOLFSSL_BIGNUM *d) +{ + int ret = 1; + + /* If the fields n and e in r are NULL, the corresponding input + * parameters MUST be non-NULL for n and e. d may be + * left NULL (in case only the public key is used). + */ + if ((rsa == NULL) || ((rsa->n == NULL) && (n == NULL)) || + ((rsa->e == NULL) && (e == NULL))) { + ret = 0; + } + if (ret == 1) { + /* Replace the BNs. */ + if (n != NULL) { + wolfSSL_BN_free(rsa->n); + rsa->n = n; + } + if (e != NULL) { + wolfSSL_BN_free(rsa->e); + rsa->e = e; + } + if (d != NULL) { + /* Private key is sensitive data. */ + wolfSSL_BN_clear_free(rsa->d); + rsa->d = d; + } + + /* Set the values into the wolfCrypt RSA key. */ + if (SetRsaInternal(rsa) != 1) { + if (n != NULL) { + rsa->n = NULL; + } + if (e != NULL) { + rsa->e = NULL; + } + if (d != NULL) { + rsa->d = NULL; + } + ret = 0; + } + } + + return ret; +} + +/* Get the flags of the RSA key. + * + * @param [in] rsa RSA key. + * @return Flags set in RSA key on success. + * @return 0 when RSA key is NULL. + */ +int wolfSSL_RSA_flags(const WOLFSSL_RSA *rsa) +{ + int ret = 0; + + /* Get flags from the RSA key if available. */ + if (rsa != NULL) { + ret = rsa->flags; + } + + return ret; +} + +/* Set the flags into the RSA key. + * + * @param [in, out] rsa RSA key. + * @param [in] flags Flags to set. + */ +void wolfSSL_RSA_set_flags(WOLFSSL_RSA *rsa, int flags) +{ + /* Add the flags into RSA key if available. */ + if (rsa != NULL) { + rsa->flags |= flags; + } +} + +/* Clear the flags in the RSA key. + * + * @param [in, out] rsa RSA key. + * @param [in] flags Flags to clear. + */ +void wolfSSL_RSA_clear_flags(WOLFSSL_RSA *rsa, int flags) +{ + /* Clear the flags passed in that are on the RSA key if available. */ + if (rsa != NULL) { + rsa->flags &= ~flags; + } +} + +/* Test the flags in the RSA key. + * + * @param [in] rsa RSA key. + * @return Matching flags of RSA key on success. + * @return 0 when RSA key is NULL. + */ +int wolfSSL_RSA_test_flags(const WOLFSSL_RSA *rsa, int flags) +{ + /* Return the flags passed in that are set on the RSA key if available. */ + return (rsa != NULL) ? (rsa->flags & flags) : 0; +} + +/* Get the extra data, by index, associated with the RSA key. + * + * @param [in] rsa RSA key. + * @param [in] idx Index of extra data. + * @return Extra data (anonymous type) on success. + * @return NULL on failure. + */ +void* wolfSSL_RSA_get_ex_data(const WOLFSSL_RSA *rsa, int idx) +{ + WOLFSSL_ENTER("wolfSSL_RSA_get_ex_data"); + +#ifdef HAVE_EX_DATA + return (rsa == NULL) ? NULL : + wolfSSL_CRYPTO_get_ex_data(&rsa->ex_data, idx); +#else + (void)rsa; + (void)idx; + + return NULL; +#endif +} + +/* Set extra data against the RSA key at an index. + * + * @param [in, out] rsa RSA key. + * @param [in] idx Index set set extra data at. + * @param [in] data Extra data of anonymous type. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_set_ex_data(WOLFSSL_RSA *rsa, int idx, void *data) +{ + WOLFSSL_ENTER("wolfSSL_RSA_set_ex_data"); + +#ifdef HAVE_EX_DATA + return (rsa == NULL) ? 0 : + wolfSSL_CRYPTO_set_ex_data(&rsa->ex_data, idx, data); +#else + (void)rsa; + (void)idx; + (void)data; + + return 0; +#endif +} + +#ifdef HAVE_EX_DATA_CLEANUP_HOOKS +/* Set the extra data and cleanup callback against the RSA key at an index. + * + * Not OpenSSL API. + * + * @param [in, out] rsa RSA key. + * @param [in] idx Index set set extra data at. + * @param [in] data Extra data of anonymous type. + * @param [in] freeCb Callback function to free extra data. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_set_ex_data_with_cleanup(WOLFSSL_RSA *rsa, int idx, void *data, + wolfSSL_ex_data_cleanup_routine_t freeCb) +{ + WOLFSSL_ENTER("wolfSSL_RSA_set_ex_data_with_cleanup"); + + return (rsa == NULL) ? 0 : + wolfSSL_CRYPTO_set_ex_data_with_cleanup(&rsa->ex_data, idx, data, + freeCb); +} +#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ + +/* + * RSA check key APIs + */ + +#ifdef WOLFSSL_RSA_KEY_CHECK +/* Check that the RSA key is valid using wolfCrypt. + * + * @param [in] rsa RSA key. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_check_key(const WOLFSSL_RSA* rsa) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_RSA_check_key"); + + /* Validate parameters. */ + if ((rsa == NULL) || (rsa->internal == NULL)) { + ret = 0; + } + + /* Constant RSA - assume internal data has been set. */ + + /* Check wolfCrypt RSA key. */ + if ((ret == 1) && (wc_CheckRsaKey((RsaKey*)rsa->internal) != 0)) { + ret = 0; + } + + WOLFSSL_LEAVE("wolfSSL_RSA_check_key", ret); + + return ret; +} +#endif /* WOLFSSL_RSA_KEY_CHECK */ + +/* + * RSA generate APIs + */ + +/* Get a random number generator associated with the RSA key. + * + * If not able, then get the global if possible. + * *tmpRng must not be an initialized RNG. + * *tmpRng is allocated when WOLFSSL_SMALL_STACK is defined and an RNG isn't + * associated with the wolfCrypt RSA key. + * + * @param [in] rsa RSA key. + * @param [out] tmpRng Temporary random number generator. + * @param [out] initTmpRng Temporary random number generator was initialized. + * + * @return A wolfCrypt RNG to use on success. + * @return NULL on error. + */ +WC_RNG* WOLFSSL_RSA_GetRNG(WOLFSSL_RSA* rsa, WC_RNG** tmpRng, int* initTmpRng) +{ + WC_RNG* rng = NULL; + int err = 0; + + /* Check validity of parameters. */ + if ((rsa == NULL) || (initTmpRng == NULL)) { + err = 1; + } + if (!err) { + /* Haven't initialized any RNG passed through tmpRng. */ + *initTmpRng = 0; + + #if !defined(HAVE_FIPS) && defined(WC_RSA_BLINDING) + /* Use wolfCrypt RSA key's RNG if available/set. */ + rng = ((RsaKey*)rsa->internal)->rng; + #endif + } + if ((!err) && (rng == NULL) && (tmpRng != NULL)) { + /* Make an RNG with tmpRng or get global. */ + rng = wolfssl_make_rng(*tmpRng, initTmpRng); + if ((rng != NULL) && *initTmpRng) { + *tmpRng = rng; + } + } + + return rng; +} + +/* Use the wolfCrypt RSA APIs to generate a new RSA key. + * + * @param [in, out] rsa RSA key. + * @param [in] bits Number of bits that the modulus must have. + * @param [in] e A BN object holding the public exponent to use. + * @param [in] cb Status callback. Unused. + * @return 0 on success. + * @return wolfSSL native error code on error. + */ +static int wolfssl_rsa_generate_key_native(WOLFSSL_RSA* rsa, int bits, + WOLFSSL_BIGNUM* e, void* cb) +{ +#ifdef WOLFSSL_KEY_GEN + int ret = 0; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRng = NULL; +#else + WC_RNG _tmpRng[1]; + WC_RNG* tmpRng = _tmpRng; +#endif + int initTmpRng = 0; + WC_RNG* rng = NULL; + long en = 0; +#endif + + (void)cb; + + WOLFSSL_ENTER("wolfssl_rsa_generate_key_native"); + +#ifdef WOLFSSL_KEY_GEN + /* Get RNG in wolfCrypt RSA key or initialize a new one (or global). */ + rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); + if (rng == NULL) { + /* Something went wrong so return memory error. */ + ret = MEMORY_E; + } + if ((ret == 0) && ((en = (long)wolfSSL_BN_get_word(e)) <= 0)) { + ret = BAD_FUNC_ARG; + } + if (ret == 0) { + /* Generate an RSA key. */ + ret = wc_MakeRsaKey((RsaKey*)rsa->internal, bits, en, rng); + if (ret != MP_OKAY) { + WOLFSSL_ERROR_MSG("wc_MakeRsaKey failed"); + } + } + if (ret == 0) { + /* Get the values from wolfCrypt RSA key into external RSA key. */ + ret = SetRsaExternal(rsa); + if (ret == 1) { + /* Internal matches external. */ + rsa->inSet = 1; + /* Return success. */ + ret = 0; + } + else { + /* Something went wrong so return memory error. */ + ret = MEMORY_E; + } + } + + /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ + if (initTmpRng) { + wc_FreeRng(tmpRng); + } + WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); + + return ret; +#else + WOLFSSL_ERROR_MSG("No Key Gen built in"); + + (void)rsa; + (void)e; + (void)bits; + + return NOT_COMPILED_IN; +#endif +} + +/* Generate an RSA key that has the specified modulus size and public exponent. + * + * Note: Because of wc_MakeRsaKey an RSA key size generated can be rounded + * down to nearest multiple of 8. For example generating a key of size + * 2999 bits will make a key of size 374 bytes instead of 375 bytes. + * + * @param [in] bits Number of bits that the modulus must have i.e. 2048. + * @param [in] e Public exponent to use i.e. 65537. + * @param [in] cb Status callback. Unused. + * @param [in] data Data to pass to status callback. Unused. + * @return A new RSA key on success. + * @return NULL on failure. + */ +WOLFSSL_RSA* wolfSSL_RSA_generate_key(int bits, unsigned long e, + void(*cb)(int, int, void*), void* data) +{ + WOLFSSL_RSA* rsa = NULL; + WOLFSSL_BIGNUM* bn = NULL; + int err = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_generate_key"); + + (void)cb; + (void)data; + + /* Validate bits. */ + if (bits < 0) { + WOLFSSL_ERROR_MSG("Bad argument: bits was less than 0"); + err = 1; + } + /* Create a new BN to hold public exponent - for when wolfCrypt supports + * longer values. */ + if ((!err) && ((bn = wolfSSL_BN_new()) == NULL)) { + WOLFSSL_ERROR_MSG("Error creating big number"); + err = 1; + } + /* Set public exponent. */ + if ((!err) && (wolfSSL_BN_set_word(bn, e) != 1)) { + WOLFSSL_ERROR_MSG("Error using e value"); + err = 1; + } + + /* Create an RSA key object to hold generated key. */ + if ((!err) && ((rsa = wolfSSL_RSA_new()) == NULL)) { + WOLFSSL_ERROR_MSG("memory error"); + err = 1; + } + while (!err) { + int ret; + + /* Use wolfCrypt to generate RSA key. */ + ret = wolfssl_rsa_generate_key_native(rsa, bits, bn, NULL); + #ifdef HAVE_FIPS + /* Keep trying if failed to find a prime. */ + if (ret == WC_NO_ERR_TRACE(PRIME_GEN_E)) { + continue; + } + #endif + if (ret != WOLFSSL_ERROR_NONE) { + /* Unrecoverable error in generation. */ + err = 1; + } + /* Done generating - unrecoverable error or success. */ + break; + } + if (err) { + /* Dispose of RSA key object if generation didn't work. */ + wolfSSL_RSA_free(rsa); + /* Returning NULL on error. */ + rsa = NULL; + } + /* Dispose of the temporary BN used for the public exponent. */ + wolfSSL_BN_free(bn); + + return rsa; +} + +/* Generate an RSA key that has the specified modulus size and public exponent. + * + * Note: Because of wc_MakeRsaKey an RSA key size generated can be rounded + * down to nearest multiple of 8. For example generating a key of size + * 2999 bits will make a key of size 374 bytes instead of 375 bytes. + * + * @param [in] bits Number of bits that the modulus must have i.e. 2048. + * @param [in] e Public exponent to use, i.e. 65537, as a BN. + * @param [in] cb Status callback. Unused. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_generate_key_ex(WOLFSSL_RSA* rsa, int bits, WOLFSSL_BIGNUM* e, + void* cb) +{ + int ret = 1; + + /* Validate parameters. */ + if ((rsa == NULL) || (rsa->internal == NULL)) { + WOLFSSL_ERROR_MSG("bad arguments"); + ret = 0; + } + else { + for (;;) { + /* Use wolfCrypt to generate RSA key. */ + int gen_ret = wolfssl_rsa_generate_key_native(rsa, bits, e, cb); + #ifdef HAVE_FIPS + /* Keep trying again if public key value didn't work. */ + if (gen_ret == WC_NO_ERR_TRACE(PRIME_GEN_E)) { + continue; + } + #endif + if (gen_ret != WOLFSSL_ERROR_NONE) { + /* Unrecoverable error in generation. */ + ret = 0; + } + /* Done generating - unrecoverable error or success. */ + break; + } + } + + return ret; +} + +#endif /* OPENSSL_EXTRA */ + +/* + * RSA padding APIs + */ + +#ifdef WC_RSA_PSS + +#if defined(OPENSSL_EXTRA) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) +static int rsa_pss_calc_salt(int saltLen, int hashLen, int emLen) +{ + /* Calculate the salt length to use for special cases. */ + switch (saltLen) { + /* Negative saltLen values are treated differently. */ + case WC_RSA_PSS_SALTLEN_DIGEST: + saltLen = hashLen; + break; + case WC_RSA_PSS_SALTLEN_MAX_SIGN: + case WC_RSA_PSS_SALTLEN_MAX: + #ifdef WOLFSSL_PSS_LONG_SALT + saltLen = emLen - hashLen - 2; + #else + saltLen = hashLen; + (void)emLen; + #endif + break; + default: + break; + } + if (saltLen < 0) { + /* log invalid salt, let wolfCrypt handle error */ + WOLFSSL_ERROR_MSG("invalid saltLen"); + saltLen = -3; /* for wolfCrypt to produce error must be < -2 */ + } + return saltLen; +} +#endif /* OPENSSL_EXTRA && !HAVE_SELFTEST */ + +#if (defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \ + defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX)) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + +/* Add PKCS#1 PSS padding to hash. + * + * + * +-----------+ + * | M | + * +-----------+ + * | + * V + * Hash + * | + * V + * +--------+----------+----------+ + * M' = |Padding1| mHash | salt | + * +--------+----------+----------+ + * | + * +--------+----------+ V + * DB = |Padding2|maskedseed| Hash + * +--------+----------+ | + * | | + * V | +--+ + * xor <--- MGF <---| |bc| + * | | +--+ + * | | | + * V V V + * +-------------------+----------+--+ + * EM = | maskedDB |maskedseed|bc| + * +-------------------+----------+--+ + * Diagram taken from https://tools.ietf.org/html/rfc3447#section-9.1 + * + * @param [in] rsa RSA key. + * @param [out] em Encoded message. + * @param [in[ mHash Message hash. + * @param [in] hashAlg Hash algorithm. + * @param [in] mgf1Hash MGF algorithm. + * @param [in] saltLen Length of salt to generate. + * @return 1 on success. + * @return 0 on failure. + */ + +int wolfSSL_RSA_padding_add_PKCS1_PSS_mgf1(WOLFSSL_RSA *rsa, unsigned char *em, + const unsigned char *mHash, const WOLFSSL_EVP_MD *hashAlg, + const WOLFSSL_EVP_MD *mgf1Hash, int saltLen) +{ + int ret = 1; + enum wc_HashType hashType = WC_HASH_TYPE_NONE; + int hashLen = 0; + int emLen = 0; + int mgf = 0; + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRng = NULL; +#else + WC_RNG _tmpRng[1]; + WC_RNG* tmpRng = _tmpRng; +#endif + + WOLFSSL_ENTER("wolfSSL_RSA_padding_add_PKCS1_PSS"); + + /* Validate parameters. */ + if ((rsa == NULL) || (em == NULL) || (mHash == NULL) || (hashAlg == NULL)) { + ret = 0; + } + + if (mgf1Hash == NULL) + mgf1Hash = hashAlg; + + if (ret == 1) { + /* Get/create an RNG. */ + rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); + if (rng == NULL) { + WOLFSSL_ERROR_MSG("WOLFSSL_RSA_GetRNG error"); + ret = 0; + } + } + + /* TODO: use wolfCrypt RSA key to get emLen and bits? */ + /* Set the external data from the wolfCrypt RSA key if not done. */ + if ((ret == 1) && (!rsa->exSet)) { + ret = SetRsaExternal(rsa); + } + + if (ret == 1) { + /* Get the wolfCrypt hash algorithm type. */ + hashType = EvpMd2MacType(hashAlg); + if (hashType > WC_HASH_TYPE_MAX) { + WOLFSSL_ERROR_MSG("EvpMd2MacType error"); + ret = 0; + } + } + if (ret == 1) { + /* Get the wolfCrypt MGF algorithm from hash algorithm. */ + mgf = wc_hash2mgf(EvpMd2MacType(mgf1Hash)); + if (mgf == WC_MGF1NONE) { + WOLFSSL_ERROR_MSG("wc_hash2mgf error"); + ret = 0; + } + } + if (ret == 1) { + /* Get the length of the hash output. */ + hashLen = wolfSSL_EVP_MD_size(hashAlg); + if (hashLen < 0) { + WOLFSSL_ERROR_MSG("wolfSSL_EVP_MD_size error"); + ret = 0; + } + } + + if (ret == 1) { + /* Get length of RSA key - encrypted message length. */ + emLen = wolfSSL_RSA_size(rsa); + if (emLen <= 0) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_size error"); + ret = 0; + } + } + + if (ret == 1) { + saltLen = rsa_pss_calc_salt(saltLen, hashLen, emLen); + } + + if (ret == 1) { + /* Generate RSA PKCS#1 PSS padding for hash using wolfCrypt. */ + if (wc_RsaPad_ex(mHash, (word32)hashLen, em, (word32)emLen, + RSA_BLOCK_TYPE_1, rng, WC_RSA_PSS_PAD, hashType, mgf, NULL, 0, + saltLen, wolfSSL_BN_num_bits(rsa->n), NULL) != MP_OKAY) { + WOLFSSL_ERROR_MSG("wc_RsaPad_ex error"); + ret = 0; + } + } + + /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ + if (initTmpRng) { + wc_FreeRng(tmpRng); + } + WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); + + return ret; +} + +int wolfSSL_RSA_padding_add_PKCS1_PSS(WOLFSSL_RSA *rsa, unsigned char *em, + const unsigned char *mHash, const WOLFSSL_EVP_MD *hashAlg, int saltLen) +{ + return wolfSSL_RSA_padding_add_PKCS1_PSS_mgf1(rsa, em, mHash, hashAlg, NULL, + saltLen); +} + +/* Checks that the hash is valid for the RSA PKCS#1 PSS encoded message. + * + * Refer to wolfSSL_RSA_padding_add_PKCS1_PSS for a diagram. + * + * @param [in] rsa RSA key. + * @param [in[ mHash Message hash. + * @param [in] hashAlg Hash algorithm. + * @param [in] mgf1Hash MGF algorithm. + * @param [in] em Encoded message. + * @param [in] saltLen Length of salt to generate. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_verify_PKCS1_PSS_mgf1(WOLFSSL_RSA *rsa, + const unsigned char *mHash, const WOLFSSL_EVP_MD *hashAlg, + const WOLFSSL_EVP_MD *mgf1Hash, const unsigned char *em, int saltLen) +{ + int ret = 1; + int hashLen = 0; + int mgf = 0; + int emLen = 0; + int mPrimeLen = 0; + enum wc_HashType hashType = WC_HASH_TYPE_NONE; + byte *mPrime = NULL; + byte *buf = NULL; + + WOLFSSL_ENTER("wolfSSL_RSA_verify_PKCS1_PSS"); + + /* Validate parameters. */ + if ((rsa == NULL) || (mHash == NULL) || (hashAlg == NULL) || (em == NULL)) { + ret = 0; + } + + if (mgf1Hash == NULL) + mgf1Hash = hashAlg; + + /* TODO: use wolfCrypt RSA key to get emLen and bits? */ + /* Set the external data from the wolfCrypt RSA key if not done. */ + if ((ret == 1) && (!rsa->exSet)) { + ret = SetRsaExternal(rsa); + } + + if (ret == 1) { + /* Get hash length for hash algorithm. */ + hashLen = wolfSSL_EVP_MD_size(hashAlg); + if (hashLen < 0) { + ret = 0; + } + } + + if (ret == 1) { + /* Get length of RSA key - encrypted message length. */ + emLen = wolfSSL_RSA_size(rsa); + if (emLen <= 0) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_size error"); + ret = 0; + } + } + + if (ret == 1) { + saltLen = rsa_pss_calc_salt(saltLen, hashLen, emLen); + } + + if (ret == 1) { + /* Get the wolfCrypt hash algorithm type. */ + hashType = EvpMd2MacType(hashAlg); + if (hashType > WC_HASH_TYPE_MAX) { + WOLFSSL_ERROR_MSG("EvpMd2MacType error"); + ret = 0; + } + } + + if (ret == 1) { + /* Get the wolfCrypt MGF algorithm from hash algorithm. */ + if ((mgf = wc_hash2mgf(EvpMd2MacType(mgf1Hash))) == WC_MGF1NONE) { + WOLFSSL_ERROR_MSG("wc_hash2mgf error"); + ret = 0; + } + } + + if (ret == 1) { + /* Allocate buffer to unpad inline with. */ + buf = (byte*)XMALLOC((size_t)emLen, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + WOLFSSL_ERROR_MSG("malloc error"); + ret = 0; + } + } + + if (ret == 1) { + /* Copy encrypted message to temp for inline unpadding. */ + XMEMCPY(buf, em, (size_t)emLen); + + /* Remove and verify the PSS padding. */ + mPrimeLen = wc_RsaUnPad_ex(buf, (word32)emLen, &mPrime, + RSA_BLOCK_TYPE_1, WC_RSA_PSS_PAD, hashType, mgf, NULL, 0, saltLen, + wolfSSL_BN_num_bits(rsa->n), NULL); + if (mPrimeLen < 0) { + WOLFSSL_ERROR_MSG("wc_RsaPad_ex error"); + ret = 0; + } + } + + if (ret == 1) { + /* Verify the hash is correct. */ + if (wc_RsaPSS_CheckPadding_ex(mHash, (word32)hashLen, mPrime, + (word32)mPrimeLen, hashType, saltLen, + wolfSSL_BN_num_bits(rsa->n)) != MP_OKAY) { + WOLFSSL_ERROR_MSG("wc_RsaPSS_CheckPadding_ex error"); + ret = 0; + } + } + + /* Dispose of any allocated buffer. */ + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return ret; +} + +int wolfSSL_RSA_verify_PKCS1_PSS(WOLFSSL_RSA *rsa, const unsigned char *mHash, + const WOLFSSL_EVP_MD *hashAlg, + const unsigned char *em, int saltLen) +{ + return wolfSSL_RSA_verify_PKCS1_PSS_mgf1(rsa, mHash, hashAlg, NULL, em, + saltLen); +} +#endif /* (!HAVE_FIPS || FIPS_VERSION_GT(2,0)) && \ + (OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_NGINX) */ +#endif /* WC_RSA_PSS */ + +/* + * RSA sign/verify APIs + */ + +#if defined(WC_RSA_PSS) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,1)) + #ifndef WOLFSSL_PSS_SALT_LEN_DISCOVER + #define DEF_PSS_SALT_LEN RSA_PSS_SALT_LEN_DEFAULT + #else + #define DEF_PSS_SALT_LEN RSA_PSS_SALT_LEN_DISCOVER + #endif +#else + #define DEF_PSS_SALT_LEN 0 /* not used */ +#endif + +#if defined(OPENSSL_EXTRA) + +/* Encode the message hash. + * + * Used by signing and verification. + * + * @param [in] hashAlg Hash algorithm OID. + * @param [in] hash Hash of message to encode for signing. + * @param [in] hLen Length of hash of message. + * @param [out] enc Encoded message hash. + * @param [out] encLen Length of encoded message hash. + * @param [in] padding Which padding scheme is being used. + * @return 1 on success. + * @return 0 on failure. + */ +static int wolfssl_rsa_sig_encode(int hashAlg, const unsigned char* hash, + unsigned int hLen, unsigned char* enc, unsigned int* encLen, int padding) +{ + int ret = 1; + int hType = WC_HASH_TYPE_NONE; + + /* Validate parameters. */ + if ((hash == NULL) || (enc == NULL) || (encLen == NULL)) { + ret = 0; + } + + if ((ret == 1) && (hashAlg != WC_NID_undef) && + (padding == WC_RSA_PKCS1_PADDING)) { + /* Convert hash algorithm to hash type for PKCS#1.5 padding. */ + hType = (int)nid2oid(hashAlg, oidHashType); + if (hType == -1) { + ret = 0; + } + } + if ((ret == 1) && (padding == WC_RSA_PKCS1_PADDING)) { + /* PKCS#1.5 encoding. */ + word32 encSz = wc_EncodeSignature(enc, hash, hLen, hType); + if (encSz == 0) { + WOLFSSL_ERROR_MSG("Bad Encode Signature"); + ret = 0; + } + else { + *encLen = (unsigned int)encSz; + } + } + /* Other padding schemes require the hash as is. */ + if ((ret == 1) && (padding != WC_RSA_PKCS1_PADDING)) { + XMEMCPY(enc, hash, hLen); + *encLen = hLen; + } + + return ret; +} + +/* Sign the message hash using hash algorithm and RSA key. + * + * @param [in] hashAlg Hash algorithm OID. + * @param [in] hash Hash of message to encode for signing. + * @param [in] hLen Length of hash of message. + * @param [out] enc Encoded message hash. + * @param [out] encLen Length of encoded message hash. + * @param [in] rsa RSA key. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_sign(int hashAlg, const unsigned char* hash, unsigned int hLen, + unsigned char* sigRet, unsigned int* sigLen, WOLFSSL_RSA* rsa) +{ + if (sigLen != NULL) { + /* No size checking in this API */ + *sigLen = RSA_MAX_SIZE / CHAR_BIT; + } + /* flag is 1: output complete signature. */ + return wolfSSL_RSA_sign_generic_padding(hashAlg, hash, hLen, sigRet, + sigLen, rsa, 1, WC_RSA_PKCS1_PADDING); +} + +/* Sign the message hash using hash algorithm and RSA key. + * + * Not OpenSSL API. + * + * @param [in] hashAlg Hash algorithm NID. + * @param [in] hash Hash of message to encode for signing. + * @param [in] hLen Length of hash of message. + * @param [out] enc Encoded message hash. + * @param [out] encLen Length of encoded message hash. + * @param [in] rsa RSA key. + * @param [in] flag When 1: Output encrypted signature. + * When 0: Output encoded hash. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_sign_ex(int hashAlg, const unsigned char* hash, + unsigned int hLen, unsigned char* sigRet, unsigned int* sigLen, + WOLFSSL_RSA* rsa, int flag) +{ + int ret = 0; + + if ((flag == 0) || (flag == 1)) { + if (sigLen != NULL) { + /* No size checking in this API */ + *sigLen = RSA_MAX_SIZE / CHAR_BIT; + } + ret = wolfSSL_RSA_sign_generic_padding(hashAlg, hash, hLen, sigRet, + sigLen, rsa, flag, WC_RSA_PKCS1_PADDING); + } + + return ret; +} + +int wolfSSL_RSA_sign_generic_padding(int hashAlg, const unsigned char* hash, + unsigned int hLen, unsigned char* sigRet, unsigned int* sigLen, + WOLFSSL_RSA* rsa, int flag, int padding) +{ + return wolfSSL_RSA_sign_mgf(hashAlg, hash, hLen, sigRet, sigLen, rsa, flag, + padding, hashAlg, DEF_PSS_SALT_LEN); +} + +/** + * Sign a message hash with the chosen message digest, padding, and RSA key. + * + * Not OpenSSL API. + * + * @param [in] hashAlg Hash NID + * @param [in] hash Message hash to sign. + * @param [in] mLen Length of message hash to sign. + * @param [out] sigRet Output buffer. + * @param [in, out] sigLen On Input: length of sigRet buffer. + * On Output: length of data written to sigRet. + * @param [in] rsa RSA key used to sign the input. + * @param [in] flag 1: Output the signature. + * 0: Output the value that the unpadded signature + * should be compared to. + * @param [in] padding Padding to use. Only RSA_PKCS1_PSS_PADDING and + * WC_RSA_PKCS1_PADDING are currently supported for + * signing. + * @param [in] mgf1Hash MGF1 Hash NID + * @param [in] saltLen Length of RSA PSS salt + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_sign_mgf(int hashAlg, const unsigned char* hash, + unsigned int hLen, unsigned char* sigRet, unsigned int* sigLen, + WOLFSSL_RSA* rsa, int flag, int padding, int mgf1Hash, int saltLen) +{ + int ret = 1; + word32 outLen = 0; + int signSz = 0; + WC_RNG* rng = NULL; + int initTmpRng = 0; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRng = NULL; + byte* encodedSig = NULL; +#else + WC_RNG _tmpRng[1]; + WC_RNG* tmpRng = _tmpRng; + byte encodedSig[MAX_ENCODED_SIG_SZ]; +#endif + unsigned int encSz = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_sign_mgf"); + + if (flag == 0) { + /* Only encode message. */ + return wolfssl_rsa_sig_encode(hashAlg, hash, hLen, sigRet, sigLen, + padding); + } + + /* Validate parameters. */ + if ((hash == NULL) || (sigRet == NULL) || sigLen == NULL || rsa == NULL) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = 0; + } + + /* Set wolfCrypt RSA key data from external if not already done. */ + if ((ret == 1) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { + ret = 0; + } + + if (ret == 1) { + /* Get the maximum signature length. */ + outLen = (word32)wolfSSL_BN_num_bytes(rsa->n); + /* Check not an error return. */ + if (outLen == 0) { + WOLFSSL_ERROR_MSG("Bad RSA size"); + ret = 0; + } + /* Check signature buffer is big enough. */ + else if (outLen > *sigLen) { + WOLFSSL_ERROR_MSG("Output buffer too small"); + ret = 0; + } + } + +#ifdef WOLFSSL_SMALL_STACK + if (ret == 1) { + /* Allocate encoded signature buffer if doing PKCS#1 padding. */ + encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, + DYNAMIC_TYPE_SIGNATURE); + if (encodedSig == NULL) { + ret = 0; + } + } +#endif + + if (ret == 1) { + /* Get/create an RNG. */ + rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); + if (rng == NULL) { + WOLFSSL_ERROR_MSG("WOLFSSL_RSA_GetRNG error"); + ret = 0; + } + } + + /* Either encodes with PKCS#1.5 or copies hash into encodedSig. */ + if ((ret == 1) && (wolfssl_rsa_sig_encode(hashAlg, hash, hLen, encodedSig, + &encSz, padding) == 0)) { + WOLFSSL_ERROR_MSG("Bad Encode Signature"); + ret = 0; + } + + if (ret == 1) { + switch (padding) { + #if defined(WC_RSA_NO_PADDING) || defined(WC_RSA_DIRECT) + case WC_RSA_NO_PAD: + if ((signSz = wc_RsaDirect(encodedSig, encSz, sigRet, &outLen, + (RsaKey*)rsa->internal, RSA_PRIVATE_ENCRYPT, rng)) <= 0) { + WOLFSSL_ERROR_MSG("Bad RSA Sign no pad"); + ret = 0; + } + break; + #endif + #if defined(WC_RSA_PSS) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,1)) + case WC_RSA_PKCS1_PSS_PADDING: + { + RsaKey* key = (RsaKey*)rsa->internal; + enum wc_HashType mgf1, hType; + hType = wc_OidGetHash((int)nid2oid(hashAlg, oidHashType)); + if (mgf1Hash == WC_NID_undef) + mgf1Hash = hashAlg; + mgf1 = wc_OidGetHash((int)nid2oid(mgf1Hash, oidHashType)); + /* handle compat layer salt special cases */ + saltLen = rsa_pss_calc_salt(saltLen, wc_HashGetDigestSize(hType), + wolfSSL_RSA_size(rsa)); + + /* Create RSA PSS signature. */ + if ((signSz = wc_RsaPSS_Sign_ex(encodedSig, encSz, sigRet, outLen, + hType, wc_hash2mgf(mgf1), saltLen, key, rng)) <= 0) { + WOLFSSL_ERROR_MSG("Bad RSA PSS Sign"); + ret = 0; + } + break; + } + #endif + #ifndef WC_NO_RSA_OAEP + case WC_RSA_PKCS1_OAEP_PADDING: + /* Not a signature padding scheme. */ + WOLFSSL_ERROR_MSG("RSA_PKCS1_OAEP_PADDING not supported for " + "signing"); + ret = 0; + break; + #endif + case WC_RSA_PKCS1_PADDING: + { + /* Sign (private encrypt) PKCS#1 encoded signature. */ + if ((signSz = wc_RsaSSL_Sign(encodedSig, encSz, sigRet, outLen, + (RsaKey*)rsa->internal, rng)) <= 0) { + WOLFSSL_ERROR_MSG("Bad PKCS1 RSA Sign"); + ret = 0; + } + break; + } + default: + WOLFSSL_ERROR_MSG("Unsupported padding"); + (void)mgf1Hash; + (void)saltLen; + ret = 0; + break; + } + } + + if (ret == 1) { + /* Return the size of signature generated. */ + *sigLen = (unsigned int)signSz; + } + + /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ + if (initTmpRng) { + wc_FreeRng(tmpRng); + } + WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); + WC_FREE_VAR_EX(encodedSig, NULL, DYNAMIC_TYPE_SIGNATURE); + + WOLFSSL_LEAVE("wolfSSL_RSA_sign_mgf", ret); + return ret; +} + +/** + * Verify a message hash with the chosen message digest, padding, and RSA key. + * + * @param [in] hashAlg Hash NID + * @param [in] hash Message hash. + * @param [in] mLen Length of message hash. + * @param [in] sigRet Signature data. + * @param [in] sigLen Length of signature data. + * @param [in] rsa RSA key used to sign the input + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_verify(int hashAlg, const unsigned char* hash, + unsigned int hLen, const unsigned char* sig, unsigned int sigLen, + WOLFSSL_RSA* rsa) +{ + return wolfSSL_RSA_verify_ex(hashAlg, hash, hLen, sig, sigLen, rsa, + WC_RSA_PKCS1_PADDING); +} + +int wolfSSL_RSA_verify_ex(int hashAlg, const unsigned char* hash, + unsigned int hLen, const unsigned char* sig, unsigned int sigLen, + WOLFSSL_RSA* rsa, int padding) +{ + return wolfSSL_RSA_verify_mgf(hashAlg, hash, hLen, sig, sigLen, rsa, + padding, hashAlg, DEF_PSS_SALT_LEN); +} + +/** + * Verify a message hash with the chosen message digest, padding, and RSA key. + * + * Not OpenSSL API. + * + * @param [in] hashAlg Hash NID + * @param [in] hash Message hash. + * @param [in] mLen Length of message hash. + * @param [in] sigRet Signature data. + * @param [in] sigLen Length of signature data. + * @param [in] rsa RSA key used to sign the input + * @param [in] padding Padding to use. Only RSA_PKCS1_PSS_PADDING and + * WC_RSA_PKCS1_PADDING are currently supported for + * signing. + * @param [in] mgf1Hash MGF1 Hash NID + * @param [in] saltLen Length of RSA PSS salt + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_RSA_verify_mgf(int hashAlg, const unsigned char* hash, + unsigned int hLen, const unsigned char* sig, unsigned int sigLen, + WOLFSSL_RSA* rsa, int padding, int mgf1Hash, int saltLen) +{ + int ret = 1; +#ifdef WOLFSSL_SMALL_STACK + unsigned char* encodedSig = NULL; +#else + unsigned char encodedSig[MAX_ENCODED_SIG_SZ]; +#endif + unsigned char* sigDec = NULL; + unsigned int len = MAX_ENCODED_SIG_SZ; + int verLen = 0; +#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 1)) && !defined(HAVE_SELFTEST) + enum wc_HashType hType = WC_HASH_TYPE_NONE; +#endif + + WOLFSSL_ENTER("wolfSSL_RSA_verify_mgf"); + + /* Validate parameters. */ + if ((hash == NULL) || (sig == NULL) || (rsa == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = 0; + } + + if (ret == 1) { + /* Allocate memory for decrypted signature. */ + sigDec = (unsigned char *)XMALLOC(sigLen, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (sigDec == NULL) { + WOLFSSL_ERROR_MSG("Memory allocation failure"); + ret = 0; + } + } + if (ret == 1 && padding == WC_RSA_PKCS1_PSS_PADDING) { + #if defined(WC_RSA_PSS) && !defined(HAVE_SELFTEST) && \ + (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,1)) + RsaKey* key = (RsaKey*)rsa->internal; + enum wc_HashType mgf1; + hType = wc_OidGetHash((int)nid2oid(hashAlg, oidHashType)); + if (mgf1Hash == WC_NID_undef) + mgf1Hash = hashAlg; + mgf1 = wc_OidGetHash((int)nid2oid(mgf1Hash, oidHashType)); + + /* handle compat layer salt special cases */ + saltLen = rsa_pss_calc_salt(saltLen, wc_HashGetDigestSize(hType), + wolfSSL_RSA_size(rsa)); + + verLen = wc_RsaPSS_Verify_ex((byte*)sig, sigLen, sigDec, sigLen, + hType, wc_hash2mgf(mgf1), saltLen, key); + if (verLen > 0) { + /* Check PSS padding is valid. */ + if (wc_RsaPSS_CheckPadding_ex(hash, hLen, sigDec, (word32)verLen, + hType, saltLen, mp_count_bits(&key->n)) != 0) { + WOLFSSL_ERROR_MSG("wc_RsaPSS_CheckPadding_ex error"); + ret = WOLFSSL_FAILURE; + } + else { + /* Success! Free resources and return early */ + XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return WOLFSSL_SUCCESS; + } + } + else { + WOLFSSL_ERROR_MSG("wc_RsaPSS_Verify_ex failed!"); + ret = WOLFSSL_FAILURE; + } + #else + (void)mgf1Hash; + (void)saltLen; + WOLFSSL_ERROR_MSG("RSA PSS not compiled in!"); + ret = WOLFSSL_FAILURE; + #endif + } + +#ifdef WOLFSSL_SMALL_STACK + if (ret == 1) { + /* Allocate memory for encoded signature. */ + encodedSig = (unsigned char *)XMALLOC(len, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (encodedSig == NULL) { + WOLFSSL_ERROR_MSG("Memory allocation failure"); + ret = 0; + } + } +#endif + if (ret == 1) { + /* Make encoded signature to compare with decrypted signature. */ + if (wolfssl_rsa_sig_encode(hashAlg, hash, hLen, encodedSig, &len, + padding) <= 0) { + WOLFSSL_ERROR_MSG("Message Digest Error"); + ret = 0; + } + } + if (ret == 1) { + /* Decrypt signature */ + #if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5, 1)) && \ + !defined(HAVE_SELFTEST) + hType = wc_OidGetHash((int)nid2oid(hashAlg, oidHashType)); + if ((verLen = wc_RsaSSL_Verify_ex2(sig, sigLen, (unsigned char *)sigDec, + sigLen, (RsaKey*)rsa->internal, padding, hType)) <= 0) { + WOLFSSL_ERROR_MSG("RSA Decrypt error"); + ret = 0; + } + #else + verLen = wc_RsaSSL_Verify(sig, sigLen, (unsigned char *)sigDec, sigLen, + (RsaKey*)rsa->internal); + if (verLen < 0) { + ret = 0; + } + #endif + } + if (ret == 1) { + /* Compare decrypted signature to encoded signature. */ + if (((int)len != verLen) || + (XMEMCMP(encodedSig, sigDec, (size_t)verLen) != 0)) { + WOLFSSL_ERROR_MSG("wolfSSL_RSA_verify_ex failed"); + ret = 0; + } + } + + /* Dispose of any allocated data. */ + WC_FREE_VAR_EX(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(sigDec, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + WOLFSSL_LEAVE("wolfSSL_RSA_verify_mgf", ret); + return ret; +} + +/* + * RSA public/private encrypt/decrypt APIs + */ + +/* Encrypt with the RSA public key. + * + * Return compliant with OpenSSL. + * + * @param [in] len Length of data to encrypt. + * @param [in] from Data to encrypt. + * @param [out] to Encrypted data. + * @param [in] rsa RSA key. + * @param [in] padding Type of padding to place around plaintext. + * @return Size of encrypted data on success. + * @return -1 on failure. + */ +int wolfSSL_RSA_public_encrypt(int len, const unsigned char* from, + unsigned char* to, WOLFSSL_RSA* rsa, int padding) +{ + int ret = 0; + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRng = NULL; +#else + WC_RNG _tmpRng[1]; + WC_RNG* tmpRng = _tmpRng; +#endif +#if !defined(HAVE_FIPS) + int mgf = WC_MGF1NONE; + enum wc_HashType hash = WC_HASH_TYPE_NONE; + int pad_type = WC_RSA_NO_PAD; +#endif + int outLen = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_public_encrypt"); + + /* Validate parameters. */ + if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || + (from == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + #if !defined(HAVE_FIPS) + /* Convert to wolfCrypt padding, hash and MGF. */ + switch (padding) { + case WC_RSA_PKCS1_PADDING: + pad_type = WC_RSA_PKCSV15_PAD; + break; + case WC_RSA_PKCS1_OAEP_PADDING: + pad_type = WC_RSA_OAEP_PAD; + hash = WC_HASH_TYPE_SHA; + mgf = WC_MGF1SHA1; + break; + case WC_RSA_NO_PAD: + pad_type = WC_RSA_NO_PAD; + break; + default: + WOLFSSL_ERROR_MSG("RSA_public_encrypt doesn't support padding " + "scheme"); + ret = WOLFSSL_FATAL_ERROR; + } + #else + /* Check for supported padding schemes in FIPS. */ + /* TODO: Do we support more schemes in later versions of FIPS? */ + if (padding != WC_RSA_PKCS1_PADDING) { + WOLFSSL_ERROR_MSG("RSA_public_encrypt pad type not supported in " + "FIPS"); + ret = WOLFSSL_FATAL_ERROR; + } + #endif + } + + /* Set wolfCrypt RSA key data from external if not already done. */ + if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + /* Calculate maximum length of encrypted data. */ + outLen = wolfSSL_RSA_size(rsa); + if (outLen == 0) { + WOLFSSL_ERROR_MSG("Bad RSA size"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 0) { + /* Get an RNG. */ + rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); + if (rng == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 0) { + /* Use wolfCrypt to public-encrypt with RSA key. */ + #if !defined(HAVE_FIPS) + ret = wc_RsaPublicEncrypt_ex(from, (word32)len, to, (word32)outLen, + (RsaKey*)rsa->internal, rng, pad_type, hash, mgf, NULL, 0); + #else + ret = wc_RsaPublicEncrypt(from, (word32)len, to, (word32)outLen, + (RsaKey*)rsa->internal, rng); + #endif + } + + /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ + if (initTmpRng) { + wc_FreeRng(tmpRng); + } + WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); + + /* wolfCrypt error means return -1. */ + if (ret <= 0) { + ret = WOLFSSL_FATAL_ERROR; + } + WOLFSSL_LEAVE("wolfSSL_RSA_public_encrypt", ret); + return ret; +} + +/* Decrypt with the RSA public key. + * + * Return compliant with OpenSSL. + * + * @param [in] len Length of encrypted data. + * @param [in] from Encrypted data. + * @param [out] to Decrypted data. + * @param [in] rsa RSA key. + * @param [in] padding Type of padding to around plaintext to remove. + * @return Size of decrypted data on success. + * @return -1 on failure. + */ +int wolfSSL_RSA_private_decrypt(int len, const unsigned char* from, + unsigned char* to, WOLFSSL_RSA* rsa, int padding) +{ + int ret = 0; +#if !defined(HAVE_FIPS) + int mgf = WC_MGF1NONE; + enum wc_HashType hash = WC_HASH_TYPE_NONE; + int pad_type = WC_RSA_NO_PAD; +#endif + int outLen = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_private_decrypt"); + + /* Validate parameters. */ + if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || + (from == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + #if !defined(HAVE_FIPS) + switch (padding) { + case WC_RSA_PKCS1_PADDING: + pad_type = WC_RSA_PKCSV15_PAD; + break; + case WC_RSA_PKCS1_OAEP_PADDING: + pad_type = WC_RSA_OAEP_PAD; + hash = WC_HASH_TYPE_SHA; + mgf = WC_MGF1SHA1; + break; + case WC_RSA_NO_PAD: + pad_type = WC_RSA_NO_PAD; + break; + default: + WOLFSSL_ERROR_MSG("RSA_private_decrypt unsupported padding"); + ret = WOLFSSL_FATAL_ERROR; + } + #else + /* Check for supported padding schemes in FIPS. */ + /* TODO: Do we support more schemes in later versions of FIPS? */ + if (padding != WC_RSA_PKCS1_PADDING) { + WOLFSSL_ERROR_MSG("RSA_public_encrypt pad type not supported in " + "FIPS"); + ret = WOLFSSL_FATAL_ERROR; + } + #endif + } + + /* Set wolfCrypt RSA key data from external if not already done. */ + if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + /* Calculate maximum length of decrypted data. */ + outLen = wolfSSL_RSA_size(rsa); + if (outLen == 0) { + WOLFSSL_ERROR_MSG("Bad RSA size"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 0) { + /* Use wolfCrypt to private-decrypt with RSA key. + * Size of 'to' buffer must be size of RSA key */ + #if !defined(HAVE_FIPS) + ret = wc_RsaPrivateDecrypt_ex(from, (word32)len, to, (word32)outLen, + (RsaKey*)rsa->internal, pad_type, hash, mgf, NULL, 0); + #else + ret = wc_RsaPrivateDecrypt(from, (word32)len, to, (word32)outLen, + (RsaKey*)rsa->internal); + #endif + } + + /* wolfCrypt error means return -1. */ + if (ret <= 0) { + ret = WOLFSSL_FATAL_ERROR; + } + WOLFSSL_LEAVE("wolfSSL_RSA_private_decrypt", ret); + return ret; +} + +/* Decrypt with the RSA public key. + * + * @param [in] len Length of encrypted data. + * @param [in] from Encrypted data. + * @param [out] to Decrypted data. + * @param [in] rsa RSA key. + * @param [in] padding Type of padding to around plaintext to remove. + * @return Size of decrypted data on success. + * @return -1 on failure. + */ +int wolfSSL_RSA_public_decrypt(int len, const unsigned char* from, + unsigned char* to, WOLFSSL_RSA* rsa, int padding) +{ + int ret = 0; +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + int pad_type = WC_RSA_NO_PAD; +#endif + int outLen = 0; + + WOLFSSL_ENTER("wolfSSL_RSA_public_decrypt"); + + /* Validate parameters. */ + if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || + (from == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + switch (padding) { + case WC_RSA_PKCS1_PADDING: + pad_type = WC_RSA_PKCSV15_PAD; + break; + case WC_RSA_NO_PAD: + pad_type = WC_RSA_NO_PAD; + break; + /* TODO: RSA_X931_PADDING not supported */ + default: + WOLFSSL_ERROR_MSG("RSA_public_decrypt unsupported padding"); + ret = WOLFSSL_FATAL_ERROR; + } + #else + if (padding != WC_RSA_PKCS1_PADDING) { + WOLFSSL_ERROR_MSG("RSA_public_decrypt pad type not supported in " + "FIPS"); + ret = WOLFSSL_FATAL_ERROR; + } + #endif + } + + /* Set wolfCrypt RSA key data from external if not already done. */ + if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + /* Calculate maximum length of encrypted data. */ + outLen = wolfSSL_RSA_size(rsa); + if (outLen == 0) { + WOLFSSL_ERROR_MSG("Bad RSA size"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 0) { + /* Use wolfCrypt to public-decrypt with RSA key. */ + #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0)) + /* Size of 'to' buffer must be size of RSA key. */ + ret = wc_RsaSSL_Verify_ex(from, (word32)len, to, (word32)outLen, + (RsaKey*)rsa->internal, pad_type); + #else + /* For FIPS v1/v2 only PKCSV15 padding is supported */ + ret = wc_RsaSSL_Verify(from, (word32)len, to, (word32)outLen, + (RsaKey*)rsa->internal); + #endif + } + + /* wolfCrypt error means return -1. */ + if (ret <= 0) { + ret = WOLFSSL_FATAL_ERROR; + } + WOLFSSL_LEAVE("wolfSSL_RSA_public_decrypt", ret); + return ret; +} + +/* Encrypt with the RSA private key. + * + * Calls wc_RsaSSL_Sign. + * + * @param [in] len Length of data to encrypt. + * @param [in] from Data to encrypt. + * @param [out] to Encrypted data. + * @param [in] rsa RSA key. + * @param [in] padding Type of padding to place around plaintext. + * @return Size of encrypted data on success. + * @return -1 on failure. + */ +int wolfSSL_RSA_private_encrypt(int len, const unsigned char* from, + unsigned char* to, WOLFSSL_RSA* rsa, int padding) +{ + int ret = 0; + int initTmpRng = 0; + WC_RNG *rng = NULL; +#ifdef WOLFSSL_SMALL_STACK + WC_RNG* tmpRng = NULL; +#else + WC_RNG _tmpRng[1]; + WC_RNG* tmpRng = _tmpRng; +#endif + + WOLFSSL_ENTER("wolfSSL_RSA_private_encrypt"); + + /* Validate parameters. */ + if ((len < 0) || (rsa == NULL) || (rsa->internal == NULL) || + (from == NULL)) { + WOLFSSL_ERROR_MSG("Bad function arguments"); + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + switch (padding) { + case WC_RSA_PKCS1_PADDING: + #ifdef WC_RSA_NO_PADDING + case WC_RSA_NO_PAD: + #endif + break; + /* TODO: RSA_X931_PADDING not supported */ + default: + WOLFSSL_ERROR_MSG("RSA_private_encrypt unsupported padding"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + /* Set wolfCrypt RSA key data from external if not already done. */ + if ((ret == 0) && (!rsa->inSet) && (SetRsaInternal(rsa) != 1)) { + ret = WOLFSSL_FATAL_ERROR; + } + + if (ret == 0) { + /* Get an RNG. */ + rng = WOLFSSL_RSA_GetRNG(rsa, (WC_RNG**)&tmpRng, &initTmpRng); + if (rng == NULL) { + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 0) { + /* Use wolfCrypt to private-encrypt with RSA key. + * Size of output buffer must be size of RSA key. */ + if (padding == WC_RSA_PKCS1_PADDING) { + ret = wc_RsaSSL_Sign(from, (word32)len, to, + (word32)wolfSSL_RSA_size(rsa), (RsaKey*)rsa->internal, rng); + } + #ifdef WC_RSA_NO_PADDING + else if (padding == WC_RSA_NO_PAD) { + word32 outLen = (word32)wolfSSL_RSA_size(rsa); + ret = wc_RsaFunction(from, (word32)len, to, &outLen, + RSA_PRIVATE_ENCRYPT, (RsaKey*)rsa->internal, rng); + if (ret == 0) + ret = (int)outLen; + } + #endif + } + + /* Finalize RNG if initialized in WOLFSSL_RSA_GetRNG(). */ + if (initTmpRng) { + wc_FreeRng(tmpRng); + } + WC_FREE_VAR_EX(tmpRng, NULL, DYNAMIC_TYPE_RNG); + + /* wolfCrypt error means return -1. */ + if (ret <= 0) { + ret = WOLFSSL_FATAL_ERROR; + } + WOLFSSL_LEAVE("wolfSSL_RSA_private_encrypt", ret); + return ret; +} + +/* + * RSA misc operation APIs + */ + +/* Calculate d mod p-1 and q-1 into BNs. + * + * Not OpenSSL API. + * + * @param [in, out] rsa RSA key. + * @return 1 on success. + * @return -1 on failure. + */ +int wolfSSL_RSA_GenAdd(WOLFSSL_RSA* rsa) +{ + int ret = 1; + int err; + mp_int* t = NULL; + WC_DECLARE_VAR(tmp, mp_int, 1, 0); + + WOLFSSL_ENTER("wolfSSL_RsaGenAdd"); + + /* Validate parameters. */ + if ((rsa == NULL) || (rsa->p == NULL) || (rsa->q == NULL) || + (rsa->d == NULL) || (rsa->dmp1 == NULL) || (rsa->dmq1 == NULL)) { + WOLFSSL_ERROR_MSG("rsa no init error"); + ret = WOLFSSL_FATAL_ERROR; + } + +#ifdef WOLFSSL_SMALL_STACK + if (ret == 1) { + tmp = (mp_int *)XMALLOC(sizeof(*tmp), rsa->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (tmp == NULL) { + WOLFSSL_ERROR_MSG("Memory allocation failure"); + ret = WOLFSSL_FATAL_ERROR; + } + } +#endif + + if (ret == 1) { + /* Initialize temp MP integer. */ + if (mp_init(tmp) != MP_OKAY) { + WOLFSSL_ERROR_MSG("mp_init error"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 1) { + t = tmp; + + /* Sub 1 from p into temp. */ + err = mp_sub_d((mp_int*)rsa->p->internal, 1, tmp); + if (err != MP_OKAY) { + WOLFSSL_ERROR_MSG("mp_sub_d error"); + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 1) { + /* Calculate d mod (p - 1) into dmp1 MP integer of BN. */ + err = mp_mod((mp_int*)rsa->d->internal, tmp, + (mp_int*)rsa->dmp1->internal); + if (err != MP_OKAY) { + WOLFSSL_ERROR_MSG("mp_mod error"); + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 1) { + /* Sub 1 from q into temp. */ + err = mp_sub_d((mp_int*)rsa->q->internal, 1, tmp); + if (err != MP_OKAY) { + WOLFSSL_ERROR_MSG("mp_sub_d error"); + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 1) { + /* Calculate d mod (q - 1) into dmq1 MP integer of BN. */ + err = mp_mod((mp_int*)rsa->d->internal, tmp, + (mp_int*)rsa->dmq1->internal); + if (err != MP_OKAY) { + WOLFSSL_ERROR_MSG("mp_mod error"); + ret = WOLFSSL_FATAL_ERROR; + } + } + + mp_clear(t); + +#ifdef WOLFSSL_SMALL_STACK + if (rsa != NULL) { + XFREE(tmp, rsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + } +#endif + + return ret; +} + + +#ifndef NO_WOLFSSL_STUB +/* Enable blinding for RSA key operations. + * + * Blinding is a compile time option in wolfCrypt. + * + * @param [in] rsa RSA key. Unused. + * @param [in] bnCtx BN context to use for blinding. Unused. + * @return 1 always. + */ +int wolfSSL_RSA_blinding_on(WOLFSSL_RSA* rsa, WOLFSSL_BN_CTX* bnCtx) +{ + WOLFSSL_STUB("RSA_blinding_on"); + WOLFSSL_ENTER("wolfSSL_RSA_blinding_on"); + + (void)rsa; + (void)bnCtx; + + return 1; /* on by default */ +} +#endif + +#endif /* OPENSSL_EXTRA */ + +#endif /* !NO_RSA */ + +/******************************************************************************* + * END OF RSA API + ******************************************************************************/ + +#endif /* !WOLFSSL_PK_RSA_INCLUDED */ diff --git a/src/ssl.c b/src/ssl.c index ff0a4eb0e5..bff77b2ec1 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -190,6 +190,12 @@ #define WOLFSSL_SSL_SESS_INCLUDED #include "src/ssl_sess.c" + +#define WOLFSSL_SSL_API_CERT_INCLUDED +#include "src/ssl_api_cert.c" + +#define WOLFSSL_SSL_API_PK_INCLUDED +#include "src/ssl_api_pk.c" #endif #if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ @@ -359,6 +365,9 @@ WC_RNG* wolfssl_make_rng(WC_RNG* rng, int* local) #define WOLFSSL_PK_INCLUDED #include "src/pk.c" +#define WOLFSSL_EVP_PK_INCLUDED +#include "wolfcrypt/src/evp_pk.c" + #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) /* copies over data of "in" to "out" */ static void wolfSSL_CIPHER_copy(WOLFSSL_CIPHER* in, WOLFSSL_CIPHER* out) @@ -404,9038 +413,4838 @@ static WOLFSSL_X509_OBJECT* wolfSSL_X509_OBJECT_dup(WOLFSSL_X509_OBJECT* obj) #include -#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) -/* create the hpke key and ech config to send to clients */ -int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName, - word16 kemId, word16 kdfId, word16 aeadId) -{ - int ret = 0; - word16 encLen = DHKEM_X25519_ENC_LEN; - WOLFSSL_EchConfig* newConfig; - WOLFSSL_EchConfig* parentConfig; -#ifdef WOLFSSL_SMALL_STACK - Hpke* hpke = NULL; - WC_RNG* rng; -#else - Hpke hpke[1]; - WC_RNG rng[1]; -#endif - - if (ctx == NULL || publicName == NULL) - return BAD_FUNC_ARG; +#define WOLFSSL_SSL_ECH_INCLUDED +#include "src/ssl_ech.c" - WC_ALLOC_VAR_EX(rng, WC_RNG, 1, ctx->heap, DYNAMIC_TYPE_RNG, - return MEMORY_E); - ret = wc_InitRng(rng); - if (ret != 0) { - WC_FREE_VAR_EX(rng, ctx->heap, DYNAMIC_TYPE_RNG); - return ret; - } +#ifdef OPENSSL_EXTRA +static int wolfSSL_parse_cipher_list(WOLFSSL_CTX* ctx, WOLFSSL* ssl, + Suites* suites, const char* list); +#endif - newConfig = (WOLFSSL_EchConfig*)XMALLOC(sizeof(WOLFSSL_EchConfig), - ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (newConfig == NULL) - ret = MEMORY_E; - else - XMEMSET(newConfig, 0, sizeof(WOLFSSL_EchConfig)); +#if defined(WOLFSSL_RENESAS_TSIP_TLS) || defined(WOLFSSL_RENESAS_FSPSM_TLS) +#include +#endif - /* set random config id */ - if (ret == 0) - ret = wc_RNG_GenerateByte(rng, &newConfig->configId); +/* prevent multiple mutex initializations */ - /* if 0 is selected for algorithms use default, may change with draft */ - if (kemId == 0) - kemId = DHKEM_X25519_HKDF_SHA256; +/* note, initRefCount is not used for thread synchronization, only for + * bookkeeping while inits_count_mutex is held. + */ +static volatile WC_THREADSHARED int initRefCount = 0; - if (kdfId == 0) - kdfId = HKDF_SHA256; +/* init ref count mutex */ +static WC_THREADSHARED wolfSSL_Mutex inits_count_mutex + WOLFSSL_MUTEX_INITIALIZER_CLAUSE(inits_count_mutex); +#ifndef WOLFSSL_MUTEX_INITIALIZER +static WC_THREADSHARED volatile int inits_count_mutex_valid = 0; +#endif - if (aeadId == 0) - aeadId = HPKE_AES_128_GCM; +#ifdef NO_TLS +static const WOLFSSL_METHOD gNoTlsMethod; +#endif - if (ret == 0) { - /* set the kem id */ - newConfig->kemId = kemId; +/* Create a new WOLFSSL_CTX struct and return the pointer to created struct. + WOLFSSL_METHOD pointer passed in is given to ctx to manage. + This function frees the passed in WOLFSSL_METHOD struct on failure and on + success is freed when ctx is freed. + */ +WOLFSSL_CTX* wolfSSL_CTX_new_ex(WOLFSSL_METHOD* method, void* heap) +{ + WOLFSSL_CTX* ctx = NULL; - /* set the cipher suite, only 1 for now */ - newConfig->numCipherSuites = 1; - newConfig->cipherSuites = - (EchCipherSuite*)XMALLOC(sizeof(EchCipherSuite), ctx->heap, - DYNAMIC_TYPE_TMP_BUFFER); + WOLFSSL_ENTER("wolfSSL_CTX_new_ex"); - if (newConfig->cipherSuites == NULL) { - ret = MEMORY_E; - } - else { - newConfig->cipherSuites[0].kdfId = kdfId; - newConfig->cipherSuites[0].aeadId = aeadId; + if (initRefCount == 0) { + /* user no longer forced to call Init themselves */ + int ret = wolfSSL_Init(); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("wolfSSL_Init failed"); + WOLFSSL_LEAVE("wolfSSL_CTX_new_ex", 0); + XFREE(method, heap, DYNAMIC_TYPE_METHOD); + return NULL; } } -#ifdef WOLFSSL_SMALL_STACK - if (ret == 0) { - hpke = (Hpke*)XMALLOC(sizeof(Hpke), ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (hpke == NULL) - ret = MEMORY_E; - } +#ifndef NO_TLS + if (method == NULL) + return ctx; +#else + /* a blank TLS method */ + method = (WOLFSSL_METHOD*)&gNoTlsMethod; #endif - if (ret == 0) - ret = wc_HpkeInit(hpke, kemId, kdfId, aeadId, ctx->heap); - - /* generate the receiver private key */ - if (ret == 0) - ret = wc_HpkeGenerateKeyPair(hpke, &newConfig->receiverPrivkey, rng); - - /* done with RNG */ - wc_FreeRng(rng); - - /* serialize the receiver key */ - if (ret == 0) - ret = wc_HpkeSerializePublicKey(hpke, newConfig->receiverPrivkey, - newConfig->receiverPubkey, &encLen); + ctx = (WOLFSSL_CTX*)XMALLOC(sizeof(WOLFSSL_CTX), heap, DYNAMIC_TYPE_CTX); + if (ctx) { + int ret; - if (ret == 0) { - newConfig->publicName = (char*)XMALLOC(XSTRLEN(publicName) + 1, - ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (newConfig->publicName == NULL) { - ret = MEMORY_E; + ret = InitSSL_Ctx(ctx, method, heap); + #ifdef WOLFSSL_STATIC_MEMORY + if (heap != NULL) { + ctx->onHeapHint = 1; /* free the memory back to heap when done */ + } + #endif + if (ret < 0) { + WOLFSSL_MSG("Init CTX failed"); + wolfSSL_CTX_free(ctx); + ctx = NULL; } +#if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) \ + && !defined(NO_SHA256) && !defined(WC_NO_RNG) else { - XMEMCPY(newConfig->publicName, publicName, - XSTRLEN(publicName) + 1); + ctx->srp = (Srp*)XMALLOC(sizeof(Srp), heap, DYNAMIC_TYPE_SRP); + if (ctx->srp == NULL){ + WOLFSSL_MSG("Init CTX failed"); + wolfSSL_CTX_free(ctx); + return NULL; + } + XMEMSET(ctx->srp, 0, sizeof(Srp)); } +#endif + } + else { + WOLFSSL_MSG("Alloc CTX failed, method freed"); + XFREE(method, heap, DYNAMIC_TYPE_METHOD); } - if (ret != 0) { - if (newConfig) { - XFREE(newConfig->cipherSuites, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(newConfig->publicName, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(newConfig, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); +#ifdef OPENSSL_COMPATIBLE_DEFAULTS + if (ctx) { + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL); + wolfSSL_CTX_set_mode(ctx, WOLFSSL_MODE_AUTO_RETRY); + if (wolfSSL_CTX_set_min_proto_version(ctx, + (method->version.major == DTLS_MAJOR) ? + DTLS1_VERSION : SSL3_VERSION) != WOLFSSL_SUCCESS || +#ifdef HAVE_ANON + wolfSSL_CTX_allow_anon_cipher(ctx) != WOLFSSL_SUCCESS || +#endif + wolfSSL_CTX_set_group_messages(ctx) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Setting OpenSSL CTX defaults failed"); + wolfSSL_CTX_free(ctx); + ctx = NULL; } } - else { - parentConfig = ctx->echConfigs; +#endif - if (parentConfig == NULL) { - ctx->echConfigs = newConfig; - } - else { - while (parentConfig->next != NULL) { - parentConfig = parentConfig->next; - } +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + /* Load the crypto-policy ciphers if configured. */ + if (ctx && wolfSSL_crypto_policy_is_enabled()) { + const char * list = wolfSSL_crypto_policy_get_ciphers(); + int ret = 0; - parentConfig->next = newConfig; + if (list != NULL && *list != '\0') { + if (AllocateCtxSuites(ctx) != 0) { + WOLFSSL_MSG("allocate ctx suites failed"); + wolfSSL_CTX_free(ctx); + ctx = NULL; + } + else { + ret = wolfSSL_parse_cipher_list(ctx, NULL, ctx->suites, list); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("parse cipher list failed"); + wolfSSL_CTX_free(ctx); + ctx = NULL; + } + } } } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - if (ret == 0) - ret = WOLFSSL_SUCCESS; - - WC_FREE_VAR_EX(hpke, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - WC_FREE_VAR_EX(rng, ctx->heap, DYNAMIC_TYPE_RNG); - - return ret; + WOLFSSL_LEAVE("wolfSSL_CTX_new_ex", 0); + return ctx; } -int wolfSSL_CTX_SetEchConfigsBase64(WOLFSSL_CTX* ctx, const char* echConfigs64, - word32 echConfigs64Len) -{ - int ret = 0; - word32 decodedLen = echConfigs64Len * 3 / 4 + 1; - byte* decodedConfigs; - - if (ctx == NULL || echConfigs64 == NULL || echConfigs64Len == 0) - return BAD_FUNC_ARG; - - decodedConfigs = (byte*)XMALLOC(decodedLen, ctx->heap, - DYNAMIC_TYPE_TMP_BUFFER); - - if (decodedConfigs == NULL) - return MEMORY_E; - - decodedConfigs[decodedLen - 1] = 0; - - /* decode the echConfigs */ - ret = Base64_Decode((const byte*)echConfigs64, echConfigs64Len, - decodedConfigs, &decodedLen); - if (ret != 0) { - XFREE(decodedConfigs, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - return ret; - } - - ret = wolfSSL_CTX_SetEchConfigs(ctx, decodedConfigs, decodedLen); - - XFREE(decodedConfigs, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); - - return ret; +WOLFSSL_ABI +WOLFSSL_CTX* wolfSSL_CTX_new(WOLFSSL_METHOD* method) +{ +#ifdef WOLFSSL_HEAP_TEST + /* if testing the heap hint then set top level CTX to have test value */ + return wolfSSL_CTX_new_ex(method, (void*)WOLFSSL_HEAP_TEST); +#else + return wolfSSL_CTX_new_ex(method, NULL); +#endif } -int wolfSSL_CTX_SetEchConfigs(WOLFSSL_CTX* ctx, const byte* echConfigs, - word32 echConfigsLen) +/* increases CTX reference count to track proper time to "free" */ +int wolfSSL_CTX_up_ref(WOLFSSL_CTX* ctx) { int ret; + wolfSSL_RefWithMutexInc(&ctx->ref, &ret); +#ifdef WOLFSSL_REFCNT_ERROR_RETURN + return ((ret == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE); +#else + (void)ret; + return WOLFSSL_SUCCESS; +#endif +} - if (ctx == NULL || echConfigs == NULL || echConfigsLen == 0) - return BAD_FUNC_ARG; - - FreeEchConfigs(ctx->echConfigs, ctx->heap); - ctx->echConfigs = NULL; - ret = SetEchConfigsEx(&ctx->echConfigs, ctx->heap, echConfigs, - echConfigsLen); - - if (ret == 0) - return WOLFSSL_SUCCESS; +WOLFSSL_ABI +void wolfSSL_CTX_free(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_free"); + if (ctx) { + FreeSSL_Ctx(ctx); + } - return ret; + WOLFSSL_LEAVE("wolfSSL_CTX_free", 0); } -/* get the ech configs that the server context is using */ -int wolfSSL_CTX_GetEchConfigs(WOLFSSL_CTX* ctx, byte* output, - word32* outputLen) { - if (ctx == NULL || outputLen == NULL) - return BAD_FUNC_ARG; - - /* if we don't have ech configs */ - if (ctx->echConfigs == NULL) - return WOLFSSL_FATAL_ERROR; - return GetEchConfigsEx(ctx->echConfigs, output, outputLen); +#ifdef HAVE_ENCRYPT_THEN_MAC +/** + * Sets whether Encrypt-Then-MAC extension can be negotiated against context. + * The default value: enabled. + * + * ctx SSL/TLS context. + * set Whether to allow or not: 1 is allow and 0 is disallow. + * returns WOLFSSL_SUCCESS + */ +int wolfSSL_CTX_AllowEncryptThenMac(WOLFSSL_CTX *ctx, int set) +{ + ctx->disallowEncThenMac = !set; + return WOLFSSL_SUCCESS; } -void wolfSSL_CTX_SetEchEnable(WOLFSSL_CTX* ctx, byte enable) +/** + * Sets whether Encrypt-Then-MAC extension can be negotiated against context. + * The default value comes from context. + * + * ctx SSL/TLS context. + * set Whether to allow or not: 1 is allow and 0 is disallow. + * returns WOLFSSL_SUCCESS + */ +int wolfSSL_AllowEncryptThenMac(WOLFSSL *ssl, int set) { - if (ctx != NULL) { - ctx->disableECH = !enable; - if (ctx->disableECH) { - TLSX_Remove(&ctx->extensions, TLSX_ECH, ctx->heap); - FreeEchConfigs(ctx->echConfigs, ctx->heap); - ctx->echConfigs = NULL; - } - } + ssl->options.disallowEncThenMac = !set; + return WOLFSSL_SUCCESS; } +#endif -/* set the ech config from base64 for our client ssl object, base64 is the - * format ech configs are sent using dns records */ -int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64, - word32 echConfigs64Len) +#ifdef SINGLE_THREADED +/* no locking in single threaded mode, allow a CTX level rng to be shared with + * WOLFSSL objects, WOLFSSL_SUCCESS on ok */ +int wolfSSL_CTX_new_rng(WOLFSSL_CTX* ctx) { - int ret = 0; - word32 decodedLen = echConfigs64Len * 3 / 4 + 1; - byte* decodedConfigs; + WC_RNG* rng; + int ret; - if (ssl == NULL || echConfigs64 == NULL || echConfigs64Len == 0) + if (ctx == NULL) { return BAD_FUNC_ARG; - - /* already have ech configs */ - if (ssl->options.useEch == 1) { - return WOLFSSL_FATAL_ERROR; } - decodedConfigs = (byte*)XMALLOC(decodedLen, ssl->heap, - DYNAMIC_TYPE_TMP_BUFFER); - - if (decodedConfigs == NULL) + rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), ctx->heap, DYNAMIC_TYPE_RNG); + if (rng == NULL) { return MEMORY_E; + } - decodedConfigs[decodedLen - 1] = 0; - - /* decode the echConfigs */ - ret = Base64_Decode((byte*)echConfigs64, echConfigs64Len, - decodedConfigs, &decodedLen); - +#ifndef HAVE_FIPS + ret = wc_InitRng_ex(rng, ctx->heap, ctx->devId); +#else + ret = wc_InitRng(rng); +#endif if (ret != 0) { - XFREE(decodedConfigs, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(rng, ctx->heap, DYNAMIC_TYPE_RNG); return ret; } - ret = wolfSSL_SetEchConfigs(ssl, decodedConfigs, decodedLen); - - XFREE(decodedConfigs, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - - return ret; + ctx->rng = rng; + return WOLFSSL_SUCCESS; } +#endif + -/* set the ech config from a raw buffer, this is the format ech configs are - * sent using retry_configs from the ech server */ -int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs, - word32 echConfigsLen) +WOLFSSL_ABI +WOLFSSL* wolfSSL_new(WOLFSSL_CTX* ctx) { - int ret; + WOLFSSL* ssl = NULL; + int ret = 0; - if (ssl == NULL || echConfigs == NULL || echConfigsLen == 0) - return BAD_FUNC_ARG; + WOLFSSL_ENTER("wolfSSL_new"); - /* already have ech configs */ - if (ssl->options.useEch == 1) { - return WOLFSSL_FATAL_ERROR; + if (ctx == NULL) { + WOLFSSL_MSG("wolfSSL_new ctx is null"); + return NULL; } - ret = SetEchConfigsEx(&ssl->echConfigs, ssl->heap, echConfigs, - echConfigsLen); + ssl = (WOLFSSL*) XMALLOC(sizeof(WOLFSSL), ctx->heap, DYNAMIC_TYPE_SSL); - /* if we found valid configs */ - if (ret == 0) { - ssl->options.useEch = 1; - return WOLFSSL_SUCCESS; + if (ssl == NULL) { + WOLFSSL_MSG_EX("ssl xmalloc failed to allocate %d bytes", + (int)sizeof(WOLFSSL)); } + else { + ret = InitSSL(ssl, ctx, 0); + if (ret < 0) { + WOLFSSL_MSG_EX("wolfSSL_new failed during InitSSL. err = %d", ret); + FreeSSL(ssl, ctx->heap); + ssl = NULL; + } + else if (ret == 0) { + WOLFSSL_MSG("wolfSSL_new InitSSL success"); + } + else { + /* Only success (0) or negative values should ever be seen. */ + WOLFSSL_MSG_EX("WARNING: wolfSSL_new unexpected InitSSL return" + " value = %d", ret); + } /* InitSSL check */ + } /* ssl XMALLOC success */ - return ret; + WOLFSSL_LEAVE("wolfSSL_new InitSSL =", ret); + (void)ret; + + return ssl; } -/* get the raw ech config from our struct */ -int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen) + +WOLFSSL_ABI +void wolfSSL_free(WOLFSSL* ssl) { - int i; - word16 totalLen = 0; + WOLFSSL_ENTER("wolfSSL_free"); + + if (ssl) { + WOLFSSL_MSG_EX("Free SSL: %p", (wc_ptr_t)ssl); + FreeSSL(ssl, ssl->ctx->heap); + } + else { + WOLFSSL_MSG("Free SSL: wolfSSL_free already null"); + } + WOLFSSL_LEAVE("wolfSSL_free", 0); +} + - if (config == NULL || (output == NULL && outputLen == NULL)) +int wolfSSL_is_server(WOLFSSL* ssl) +{ + if (ssl == NULL) return BAD_FUNC_ARG; + return ssl->options.side == WOLFSSL_SERVER_END; +} - /* 2 for version */ - totalLen += 2; - /* 2 for length */ - totalLen += 2; - /* 1 for configId */ - totalLen += 1; - /* 2 for kemId */ - totalLen += 2; - /* 2 for hpke_len */ - totalLen += 2; - - /* hpke_pub_key */ - switch (config->kemId) { - case DHKEM_P256_HKDF_SHA256: - totalLen += DHKEM_P256_ENC_LEN; - break; - case DHKEM_P384_HKDF_SHA384: - totalLen += DHKEM_P384_ENC_LEN; - break; - case DHKEM_P521_HKDF_SHA512: - totalLen += DHKEM_P521_ENC_LEN; - break; - case DHKEM_X25519_HKDF_SHA256: - totalLen += DHKEM_X25519_ENC_LEN; - break; - case DHKEM_X448_HKDF_SHA512: - totalLen += DHKEM_X448_ENC_LEN; - break; - } +#ifdef HAVE_WRITE_DUP - /* cipherSuitesLen */ - totalLen += 2; - /* cipherSuites */ - totalLen += config->numCipherSuites * 4; - /* public name len */ - totalLen += 2; +/* + * Release resources around WriteDup object + * + * ssl WOLFSSL object + * + * no return, destruction so make best attempt +*/ +void FreeWriteDup(WOLFSSL* ssl) +{ + int doFree = 0; - /* public name */ - totalLen += XSTRLEN(config->publicName); - /* trailing zeros */ - totalLen += 2; + WOLFSSL_ENTER("FreeWriteDup"); - if (output == NULL) { - *outputLen = totalLen; - return WC_NO_ERR_TRACE(LENGTH_ONLY_E); + if (ssl->dupWrite) { + if (wc_LockMutex(&ssl->dupWrite->dupMutex) == 0) { + ssl->dupWrite->dupCount--; + if (ssl->dupWrite->dupCount == 0) { + doFree = 1; + } else { + WOLFSSL_MSG("WriteDup count not zero, no full free"); + } + wc_UnLockMutex(&ssl->dupWrite->dupMutex); + } } - if (totalLen > *outputLen) { - *outputLen = totalLen; - return INPUT_SIZE_E; + if (doFree) { + WOLFSSL_MSG("Doing WriteDup full free, count to zero"); + wc_FreeMutex(&ssl->dupWrite->dupMutex); + XFREE(ssl->dupWrite, ssl->heap, DYNAMIC_TYPE_WRITEDUP); } +} - /* version */ - c16toa(TLSX_ECH, output); - output += 2; - - /* length - 4 for version and length itself */ - c16toa(totalLen - 4, output); - output += 2; - - /* configId */ - *output = config->configId; - output++; - /* kemId */ - c16toa(config->kemId, output); - output += 2; - - /* length and key itself */ - switch (config->kemId) { - case DHKEM_P256_HKDF_SHA256: - c16toa(DHKEM_P256_ENC_LEN, output); - output += 2; - XMEMCPY(output, config->receiverPubkey, DHKEM_P256_ENC_LEN); - output += DHKEM_P256_ENC_LEN; - break; - case DHKEM_P384_HKDF_SHA384: - c16toa(DHKEM_P384_ENC_LEN, output); - output += 2; - XMEMCPY(output, config->receiverPubkey, DHKEM_P384_ENC_LEN); - output += DHKEM_P384_ENC_LEN; - break; - case DHKEM_P521_HKDF_SHA512: - c16toa(DHKEM_P521_ENC_LEN, output); - output += 2; - XMEMCPY(output, config->receiverPubkey, DHKEM_P521_ENC_LEN); - output += DHKEM_P521_ENC_LEN; - break; - case DHKEM_X25519_HKDF_SHA256: - c16toa(DHKEM_X25519_ENC_LEN, output); - output += 2; - XMEMCPY(output, config->receiverPubkey, DHKEM_X25519_ENC_LEN); - output += DHKEM_X25519_ENC_LEN; - break; - case DHKEM_X448_HKDF_SHA512: - c16toa(DHKEM_X448_ENC_LEN, output); - output += 2; - XMEMCPY(output, config->receiverPubkey, DHKEM_X448_ENC_LEN); - output += DHKEM_X448_ENC_LEN; - break; - } - /* cipherSuites len */ - c16toa(config->numCipherSuites * 4, output); - output += 2; +/* + * duplicate existing ssl members into dup needed for writing + * + * dup write only WOLFSSL + * ssl existing WOLFSSL + * + * 0 on success +*/ +static int DupSSL(WOLFSSL* dup, WOLFSSL* ssl) +{ + word16 tmp_weOwnRng; - /* cipherSuites */ - for (i = 0; i < config->numCipherSuites; i++) { - c16toa(config->cipherSuites[i].kdfId, output); - output += 2; - c16toa(config->cipherSuites[i].aeadId, output); - output += 2; + /* shared dupWrite setup */ + ssl->dupWrite = (WriteDup*)XMALLOC(sizeof(WriteDup), ssl->heap, + DYNAMIC_TYPE_WRITEDUP); + if (ssl->dupWrite == NULL) { + return MEMORY_E; } + XMEMSET(ssl->dupWrite, 0, sizeof(WriteDup)); - /* set maximum name length to 0 */ - *output = 0; - output++; + if (wc_InitMutex(&ssl->dupWrite->dupMutex) != 0) { + XFREE(ssl->dupWrite, ssl->heap, DYNAMIC_TYPE_WRITEDUP); + ssl->dupWrite = NULL; + return BAD_MUTEX_E; + } + ssl->dupWrite->dupCount = 2; /* both sides have a count to start */ + dup->dupWrite = ssl->dupWrite; /* each side uses */ - /* publicName len */ - *output = XSTRLEN(config->publicName); - output++; + tmp_weOwnRng = dup->options.weOwnRng; - /* publicName */ - XMEMCPY(output, config->publicName, - XSTRLEN(config->publicName)); - output += XSTRLEN(config->publicName); + /* copy write parts over to dup writer */ + XMEMCPY(&dup->specs, &ssl->specs, sizeof(CipherSpecs)); + XMEMCPY(&dup->options, &ssl->options, sizeof(Options)); + XMEMCPY(&dup->keys, &ssl->keys, sizeof(Keys)); + XMEMCPY(&dup->encrypt, &ssl->encrypt, sizeof(Ciphers)); + XMEMCPY(&dup->version, &ssl->version, sizeof(ProtocolVersion)); + XMEMCPY(&dup->chVersion, &ssl->chVersion, sizeof(ProtocolVersion)); - /* terminating zeros */ - c16toa(0, output); - /* output += 2; */ +#ifdef HAVE_ONE_TIME_AUTH +#ifdef HAVE_POLY1305 + if (ssl->auth.setup && ssl->auth.poly1305 != NULL) { + dup->auth.poly1305 = (Poly1305*)XMALLOC(sizeof(Poly1305), dup->heap, + DYNAMIC_TYPE_CIPHER); + if (dup->auth.poly1305 == NULL) + return MEMORY_E; + dup->auth.setup = 1; + } +#endif +#endif - *outputLen = totalLen; + /* dup side now owns encrypt/write ciphers */ + XMEMSET(&ssl->encrypt, 0, sizeof(Ciphers)); - return 0; -} + dup->IOCB_WriteCtx = ssl->IOCB_WriteCtx; + dup->CBIOSend = ssl->CBIOSend; +#ifdef OPENSSL_EXTRA + dup->cbioFlag = ssl->cbioFlag; +#endif + dup->wfd = ssl->wfd; + dup->wflags = ssl->wflags; +#ifndef WOLFSSL_AEAD_ONLY + dup->hmac = ssl->hmac; +#endif +#ifdef HAVE_TRUNCATED_HMAC + dup->truncated_hmac = ssl->truncated_hmac; +#endif -/* wrapper function to get ech configs from application code */ -int wolfSSL_GetEchConfigs(WOLFSSL* ssl, byte* output, word32* outputLen) -{ - if (ssl == NULL || outputLen == NULL) - return BAD_FUNC_ARG; + /* Restore rng option */ + dup->options.weOwnRng = tmp_weOwnRng; - /* if we don't have ech configs */ - if (ssl->options.useEch != 1) { - return WOLFSSL_FATAL_ERROR; - } + /* unique side dup setup */ + dup->dupSide = WRITE_DUP_SIDE; + ssl->dupSide = READ_DUP_SIDE; - return GetEchConfigsEx(ssl->echConfigs, output, outputLen); + return 0; } -void wolfSSL_SetEchEnable(WOLFSSL* ssl, byte enable) -{ - if (ssl != NULL) { - ssl->options.disableECH = !enable; - if (ssl->options.disableECH) { - TLSX_Remove(&ssl->extensions, TLSX_ECH, ssl->heap); - FreeEchConfigs(ssl->echConfigs, ssl->heap); - ssl->echConfigs = NULL; - } - } -} -int SetEchConfigsEx(WOLFSSL_EchConfig** outputConfigs, void* heap, - const byte* echConfigs, word32 echConfigsLen) +/* + * duplicate a WOLFSSL object post handshake for writing only + * turn existing object into read only. Allows concurrent access from two + * different threads. + * + * ssl existing WOLFSSL object + * + * return dup'd WOLFSSL object on success +*/ +WOLFSSL* wolfSSL_write_dup(WOLFSSL* ssl) { + WOLFSSL* dup = NULL; int ret = 0; - int i; - int j; - word16 totalLength; - word16 version; - word16 length; - word16 hpkePubkeyLen; - word16 cipherSuitesLen; - word16 publicNameLen; - WOLFSSL_EchConfig* configList = NULL; - WOLFSSL_EchConfig* workingConfig = NULL; - WOLFSSL_EchConfig* lastConfig = NULL; - byte* echConfig = NULL; - - if (outputConfigs == NULL || echConfigs == NULL || echConfigsLen == 0) - return BAD_FUNC_ARG; - /* check that the total length is well formed */ - ato16(echConfigs, &totalLength); + (void)ret; + WOLFSSL_ENTER("wolfSSL_write_dup"); - if (totalLength != echConfigsLen - 2) { - return WOLFSSL_FATAL_ERROR; + if (ssl == NULL) { + return ssl; } - /* skip the total length uint16_t */ - i = 2; - - do { - echConfig = (byte*)echConfigs + i; - ato16(echConfig, &version); - ato16(echConfig + 2, &length); - - /* if the version does not match */ - if (version != TLSX_ECH) { - /* we hit the end of the configs */ - if ( (word32)i + 2 >= echConfigsLen ) { - break; - } + if (ssl->options.handShakeDone == 0) { + WOLFSSL_MSG("wolfSSL_write_dup called before handshake complete"); + return NULL; + } - /* skip this config, +4 for version and length */ - i += length + 4; - continue; - } + if (ssl->dupWrite) { + WOLFSSL_MSG("wolfSSL_write_dup already called once"); + return NULL; + } - /* check if the length will overrun the buffer */ - if ((word32)i + length + 4 > echConfigsLen) { - break; + dup = (WOLFSSL*) XMALLOC(sizeof(WOLFSSL), ssl->ctx->heap, DYNAMIC_TYPE_SSL); + if (dup) { + if ( (ret = InitSSL(dup, ssl->ctx, 1)) < 0) { + FreeSSL(dup, ssl->ctx->heap); + dup = NULL; + } else if ( (ret = DupSSL(dup, ssl)) < 0) { + FreeSSL(dup, ssl->ctx->heap); + dup = NULL; } + } - if (workingConfig == NULL) { - workingConfig = - (WOLFSSL_EchConfig*)XMALLOC(sizeof(WOLFSSL_EchConfig), heap, - DYNAMIC_TYPE_TMP_BUFFER); - configList = workingConfig; - if (workingConfig != NULL) { - workingConfig->next = NULL; - } - } - else { - lastConfig = workingConfig; - workingConfig->next = - (WOLFSSL_EchConfig*)XMALLOC(sizeof(WOLFSSL_EchConfig), - heap, DYNAMIC_TYPE_TMP_BUFFER); - workingConfig = workingConfig->next; - } + WOLFSSL_LEAVE("wolfSSL_write_dup", ret); - if (workingConfig == NULL) { - ret = MEMORY_E; - break; - } + return dup; +} - XMEMSET(workingConfig, 0, sizeof(WOLFSSL_EchConfig)); - /* rawLen */ - workingConfig->rawLen = length + 4; +/* + * Notify write dup side of fatal error or close notify + * + * ssl WOLFSSL object + * err Notify err + * + * 0 on success +*/ +int NotifyWriteSide(WOLFSSL* ssl, int err) +{ + int ret; - /* raw body */ - workingConfig->raw = (byte*)XMALLOC(workingConfig->rawLen, - heap, DYNAMIC_TYPE_TMP_BUFFER); - if (workingConfig->raw == NULL) { - ret = MEMORY_E; - break; - } + WOLFSSL_ENTER("NotifyWriteSide"); - XMEMCPY(workingConfig->raw, echConfig, workingConfig->rawLen); - - /* skip over version and length */ - echConfig += 4; - - /* configId, 1 byte */ - workingConfig->configId = *(echConfig); - echConfig++; - /* kemId, 2 bytes */ - ato16(echConfig, &workingConfig->kemId); - echConfig += 2; - /* hpke public_key length, 2 bytes */ - ato16(echConfig, &hpkePubkeyLen); - echConfig += 2; - /* hpke public_key */ - XMEMCPY(workingConfig->receiverPubkey, echConfig, hpkePubkeyLen); - echConfig += hpkePubkeyLen; - /* cipherSuitesLen */ - ato16(echConfig, &cipherSuitesLen); - - workingConfig->cipherSuites = (EchCipherSuite*)XMALLOC(cipherSuitesLen, - heap, DYNAMIC_TYPE_TMP_BUFFER); - if (workingConfig->cipherSuites == NULL) { - ret = MEMORY_E; - break; - } + ret = wc_LockMutex(&ssl->dupWrite->dupMutex); + if (ret == 0) { + ssl->dupWrite->dupErr = err; + ret = wc_UnLockMutex(&ssl->dupWrite->dupMutex); + } - echConfig += 2; - workingConfig->numCipherSuites = cipherSuitesLen / 4; - /* cipherSuites */ - for (j = 0; j < workingConfig->numCipherSuites; j++) { - ato16(echConfig + j * 4, &workingConfig->cipherSuites[j].kdfId); - ato16(echConfig + j * 4 + 2, - &workingConfig->cipherSuites[j].aeadId); - } - echConfig += cipherSuitesLen; - /* ignore the maximum name length */ - echConfig++; - /* publicNameLen */ - publicNameLen = *(echConfig); - workingConfig->publicName = (char*)XMALLOC(publicNameLen + 1, - heap, DYNAMIC_TYPE_TMP_BUFFER); - if (workingConfig->publicName == NULL) { - ret = MEMORY_E; - break; - } - echConfig++; - /* publicName */ - XMEMCPY(workingConfig->publicName, echConfig, publicNameLen); - /* null terminated */ - workingConfig->publicName[publicNameLen] = 0; + return ret; +} - /* add length to go to next config, +4 for version and length */ - i += length + 4; - /* check that we support this config */ - for (j = 0; j < HPKE_SUPPORTED_KEM_LEN; j++) { - if (hpkeSupportedKem[j] == workingConfig->kemId) - break; - } +#endif /* HAVE_WRITE_DUP */ - /* if we don't support the kem or at least one cipher suite */ - if (j >= HPKE_SUPPORTED_KEM_LEN || - EchConfigGetSupportedCipherSuite(workingConfig) < 0) - { - XFREE(workingConfig->cipherSuites, heap, - DYNAMIC_TYPE_TMP_BUFFER); - XFREE(workingConfig->publicName, heap, - DYNAMIC_TYPE_TMP_BUFFER); - XFREE(workingConfig->raw, heap, DYNAMIC_TYPE_TMP_BUFFER); - workingConfig = lastConfig; - } - } while ((word32)i < echConfigsLen); - /* if we found valid configs */ - if (ret == 0 && configList != NULL) { - *outputConfigs = configList; +#ifdef HAVE_POLY1305 +/* set if to use old poly 1 for yes 0 to use new poly */ +int wolfSSL_use_old_poly(WOLFSSL* ssl, int value) +{ + (void)ssl; + (void)value; - return ret; - } +#ifndef WOLFSSL_NO_TLS12 + WOLFSSL_ENTER("wolfSSL_use_old_poly"); + WOLFSSL_MSG("Warning SSL connection auto detects old/new and this function" + "is depreciated"); + ssl->options.oldPoly = (word16)value; + WOLFSSL_LEAVE("wolfSSL_use_old_poly", 0); +#endif + return 0; +} +#endif - workingConfig = configList; - while (workingConfig != NULL) { - lastConfig = workingConfig; - workingConfig = workingConfig->next; +WOLFSSL_ABI +int wolfSSL_set_fd(WOLFSSL* ssl, int fd) +{ + int ret; - XFREE(lastConfig->cipherSuites, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(lastConfig->publicName, heap, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(lastConfig->raw, heap, DYNAMIC_TYPE_TMP_BUFFER); + WOLFSSL_ENTER("wolfSSL_set_fd"); - XFREE(lastConfig, heap, DYNAMIC_TYPE_TMP_BUFFER); + if (ssl == NULL) { + return BAD_FUNC_ARG; } - if (ret == 0) - return WOLFSSL_FATAL_ERROR; + ret = wolfSSL_set_read_fd(ssl, fd); + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_set_write_fd(ssl, fd); + } return ret; } -/* get the raw ech configs from our linked list of ech config structs */ -int GetEchConfigsEx(WOLFSSL_EchConfig* configs, byte* output, word32* outputLen) +#ifdef WOLFSSL_DTLS +int wolfSSL_set_dtls_fd_connected(WOLFSSL* ssl, int fd) { - int ret = 0; - WOLFSSL_EchConfig* workingConfig = NULL; - byte* outputStart = output; - word32 totalLen = 2; - word32 workingOutputLen = 0; + int ret; + + WOLFSSL_ENTER("wolfSSL_set_dtls_fd_connected"); - if (configs == NULL || outputLen == NULL || - (output != NULL && *outputLen < totalLen)) { + if (ssl == NULL) { return BAD_FUNC_ARG; } + ret = wolfSSL_set_fd(ssl, fd); + if (ret == WOLFSSL_SUCCESS) + ssl->buffers.dtlsCtx.connected = 1; - /* skip over total length which we fill in later */ - if (output != NULL) { - workingOutputLen = *outputLen - totalLen; - output += 2; - } - else { - /* caller getting the size only, set current 2 byte length size */ - *outputLen = totalLen; - } + return ret; +} +#endif - workingConfig = configs; - while (workingConfig != NULL) { - /* get this config */ - ret = GetEchConfig(workingConfig, output, &workingOutputLen); +int wolfSSL_set_read_fd(WOLFSSL* ssl, int fd) +{ + WOLFSSL_ENTER("wolfSSL_set_read_fd"); - if (output != NULL) - output += workingOutputLen; + if (ssl == NULL) { + return BAD_FUNC_ARG; + } - /* add this config's length to the total length */ - totalLen += workingOutputLen; + ssl->rfd = fd; /* not used directly to allow IO callbacks */ + ssl->IOCB_ReadCtx = &ssl->rfd; - if (totalLen > *outputLen) - workingOutputLen = 0; - else - workingOutputLen = *outputLen - totalLen; + #ifdef WOLFSSL_DTLS + ssl->buffers.dtlsCtx.connected = 0; + if (ssl->options.dtls) { + ssl->IOCB_ReadCtx = &ssl->buffers.dtlsCtx; + ssl->buffers.dtlsCtx.rfd = fd; + } + #endif - /* only error we break on, other 2 we need to keep finding length */ - if (ret == WC_NO_ERR_TRACE(BAD_FUNC_ARG)) - return BAD_FUNC_ARG; + WOLFSSL_LEAVE("wolfSSL_set_read_fd", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; +} - workingConfig = workingConfig->next; - } - if (output == NULL) { - *outputLen = totalLen; - return WC_NO_ERR_TRACE(LENGTH_ONLY_E); - } +int wolfSSL_set_write_fd(WOLFSSL* ssl, int fd) +{ + WOLFSSL_ENTER("wolfSSL_set_write_fd"); - if (totalLen > *outputLen) { - *outputLen = totalLen; - return INPUT_SIZE_E; + if (ssl == NULL) { + return BAD_FUNC_ARG; } - /* total size -2 for size itself */ - c16toa(totalLen - 2, outputStart); + ssl->wfd = fd; /* not used directly to allow IO callbacks */ + ssl->IOCB_WriteCtx = &ssl->wfd; - *outputLen = totalLen; + #ifdef WOLFSSL_DTLS + ssl->buffers.dtlsCtx.connected = 0; + if (ssl->options.dtls) { + ssl->IOCB_WriteCtx = &ssl->buffers.dtlsCtx; + ssl->buffers.dtlsCtx.wfd = fd; + } + #endif + WOLFSSL_LEAVE("wolfSSL_set_write_fd", WOLFSSL_SUCCESS); return WOLFSSL_SUCCESS; } -#endif /* WOLFSSL_TLS13 && HAVE_ECH */ - -#ifdef OPENSSL_EXTRA -static int wolfSSL_parse_cipher_list(WOLFSSL_CTX* ctx, WOLFSSL* ssl, - Suites* suites, const char* list); -#endif - -#if defined(WOLFSSL_RENESAS_TSIP_TLS) || defined(WOLFSSL_RENESAS_FSPSM_TLS) -#include -#endif - -/* prevent multiple mutex initializations */ - -/* note, initRefCount is not used for thread synchronization, only for - * bookkeeping while inits_count_mutex is held. - */ -static volatile WC_THREADSHARED int initRefCount = 0; - -/* init ref count mutex */ -static WC_THREADSHARED wolfSSL_Mutex inits_count_mutex - WOLFSSL_MUTEX_INITIALIZER_CLAUSE(inits_count_mutex); -#ifndef WOLFSSL_MUTEX_INITIALIZER -static WC_THREADSHARED volatile int inits_count_mutex_valid = 0; -#endif -#ifdef NO_TLS -static const WOLFSSL_METHOD gNoTlsMethod; -#endif -/* Create a new WOLFSSL_CTX struct and return the pointer to created struct. - WOLFSSL_METHOD pointer passed in is given to ctx to manage. - This function frees the passed in WOLFSSL_METHOD struct on failure and on - success is freed when ctx is freed. - */ -WOLFSSL_CTX* wolfSSL_CTX_new_ex(WOLFSSL_METHOD* method, void* heap) +/** + * Get the name of cipher at priority level passed in. + */ +char* wolfSSL_get_cipher_list(int priority) { - WOLFSSL_CTX* ctx = NULL; - - WOLFSSL_ENTER("wolfSSL_CTX_new_ex"); + const CipherSuiteInfo* ciphers = GetCipherNames(); - if (initRefCount == 0) { - /* user no longer forced to call Init themselves */ - int ret = wolfSSL_Init(); - if (ret != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_Init failed"); - WOLFSSL_LEAVE("wolfSSL_CTX_new_ex", 0); - XFREE(method, heap, DYNAMIC_TYPE_METHOD); - return NULL; - } + if (priority >= GetCipherNamesSize() || priority < 0) { + return 0; } -#ifndef NO_TLS - if (method == NULL) - return ctx; -#else - /* a blank TLS method */ - method = (WOLFSSL_METHOD*)&gNoTlsMethod; -#endif + return (char*)ciphers[priority].name; +} - ctx = (WOLFSSL_CTX*)XMALLOC(sizeof(WOLFSSL_CTX), heap, DYNAMIC_TYPE_CTX); - if (ctx) { - int ret; - ret = InitSSL_Ctx(ctx, method, heap); - #ifdef WOLFSSL_STATIC_MEMORY - if (heap != NULL) { - ctx->onHeapHint = 1; /* free the memory back to heap when done */ - } - #endif - if (ret < 0) { - WOLFSSL_MSG("Init CTX failed"); - wolfSSL_CTX_free(ctx); - ctx = NULL; - } -#if defined(OPENSSL_EXTRA) && defined(WOLFCRYPT_HAVE_SRP) \ - && !defined(NO_SHA256) && !defined(WC_NO_RNG) - else { - ctx->srp = (Srp*)XMALLOC(sizeof(Srp), heap, DYNAMIC_TYPE_SRP); - if (ctx->srp == NULL){ - WOLFSSL_MSG("Init CTX failed"); - wolfSSL_CTX_free(ctx); - return NULL; - } - XMEMSET(ctx->srp, 0, sizeof(Srp)); - } -#endif - } - else { - WOLFSSL_MSG("Alloc CTX failed, method freed"); - XFREE(method, heap, DYNAMIC_TYPE_METHOD); - } +/** + * Get the name of cipher at priority level passed in. + */ +char* wolfSSL_get_cipher_list_ex(WOLFSSL* ssl, int priority) +{ -#ifdef OPENSSL_COMPATIBLE_DEFAULTS - if (ctx) { - wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL); - wolfSSL_CTX_set_mode(ctx, WOLFSSL_MODE_AUTO_RETRY); - if (wolfSSL_CTX_set_min_proto_version(ctx, - (method->version.major == DTLS_MAJOR) ? - DTLS1_VERSION : SSL3_VERSION) != WOLFSSL_SUCCESS || -#ifdef HAVE_ANON - wolfSSL_CTX_allow_anon_cipher(ctx) != WOLFSSL_SUCCESS || -#endif - wolfSSL_CTX_set_group_messages(ctx) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("Setting OpenSSL CTX defaults failed"); - wolfSSL_CTX_free(ctx); - ctx = NULL; - } + if (ssl == NULL) { + return NULL; } -#endif - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - /* Load the crypto-policy ciphers if configured. */ - if (ctx && wolfSSL_crypto_policy_is_enabled()) { - const char * list = wolfSSL_crypto_policy_get_ciphers(); - int ret = 0; + else { + const char* cipher; - if (list != NULL && *list != '\0') { - if (AllocateCtxSuites(ctx) != 0) { - WOLFSSL_MSG("allocate ctx suites failed"); - wolfSSL_CTX_free(ctx); - ctx = NULL; + if ((cipher = wolfSSL_get_cipher_name_internal(ssl)) != NULL) { + if (priority == 0) { + return (char*)cipher; } else { - ret = wolfSSL_parse_cipher_list(ctx, NULL, ctx->suites, list); - if (ret != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("parse cipher list failed"); - wolfSSL_CTX_free(ctx); - ctx = NULL; - } + return NULL; } } + else { + return wolfSSL_get_cipher_list(priority); + } } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - WOLFSSL_LEAVE("wolfSSL_CTX_new_ex", 0); - return ctx; } -WOLFSSL_ABI -WOLFSSL_CTX* wolfSSL_CTX_new(WOLFSSL_METHOD* method) +int wolfSSL_get_ciphers(char* buf, int len) { -#ifdef WOLFSSL_HEAP_TEST - /* if testing the heap hint then set top level CTX to have test value */ - return wolfSSL_CTX_new_ex(method, (void*)WOLFSSL_HEAP_TEST); -#else - return wolfSSL_CTX_new_ex(method, NULL); -#endif -} + const CipherSuiteInfo* ciphers = GetCipherNames(); + int ciphersSz = GetCipherNamesSize(); + int i; -/* increases CTX reference count to track proper time to "free" */ -int wolfSSL_CTX_up_ref(WOLFSSL_CTX* ctx) -{ - int ret; - wolfSSL_RefWithMutexInc(&ctx->ref, &ret); -#ifdef WOLFSSL_REFCNT_ERROR_RETURN - return ((ret == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE); -#else - (void)ret; - return WOLFSSL_SUCCESS; -#endif -} - -WOLFSSL_ABI -void wolfSSL_CTX_free(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_free"); - if (ctx) { - FreeSSL_Ctx(ctx); - } + if (buf == NULL || len <= 0) + return BAD_FUNC_ARG; - WOLFSSL_LEAVE("wolfSSL_CTX_free", 0); -} + /* Add each member to the buffer delimited by a : */ + for (i = 0; i < ciphersSz; i++) { + int cipherNameSz = (int)XSTRLEN(ciphers[i].name); + if (cipherNameSz + 1 < len) { + XSTRNCPY(buf, ciphers[i].name, (size_t)len); + buf += cipherNameSz; + if (i < ciphersSz - 1) + *buf++ = ':'; + *buf = 0; -#ifdef HAVE_ENCRYPT_THEN_MAC -/** - * Sets whether Encrypt-Then-MAC extension can be negotiated against context. - * The default value: enabled. - * - * ctx SSL/TLS context. - * set Whether to allow or not: 1 is allow and 0 is disallow. - * returns WOLFSSL_SUCCESS - */ -int wolfSSL_CTX_AllowEncryptThenMac(WOLFSSL_CTX *ctx, int set) -{ - ctx->disallowEncThenMac = !set; + len -= cipherNameSz + 1; + } + else + return BUFFER_E; + } return WOLFSSL_SUCCESS; } -/** - * Sets whether Encrypt-Then-MAC extension can be negotiated against context. - * The default value comes from context. - * - * ctx SSL/TLS context. - * set Whether to allow or not: 1 is allow and 0 is disallow. - * returns WOLFSSL_SUCCESS - */ -int wolfSSL_AllowEncryptThenMac(WOLFSSL *ssl, int set) -{ - ssl->options.disallowEncThenMac = !set; - return WOLFSSL_SUCCESS; -} -#endif -#ifdef SINGLE_THREADED -/* no locking in single threaded mode, allow a CTX level rng to be shared with - * WOLFSSL objects, WOLFSSL_SUCCESS on ok */ -int wolfSSL_CTX_new_rng(WOLFSSL_CTX* ctx) +#ifndef NO_ERROR_STRINGS +/* places a list of all supported cipher suites in TLS_* format into "buf" + * return WOLFSSL_SUCCESS on success */ +int wolfSSL_get_ciphers_iana(char* buf, int len) { - WC_RNG* rng; - int ret; + const CipherSuiteInfo* ciphers = GetCipherNames(); + int ciphersSz = GetCipherNamesSize(); + int i; + int cipherNameSz; - if (ctx == NULL) { + if (buf == NULL || len <= 0) return BAD_FUNC_ARG; - } - rng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), ctx->heap, DYNAMIC_TYPE_RNG); - if (rng == NULL) { - return MEMORY_E; - } - -#ifndef HAVE_FIPS - ret = wc_InitRng_ex(rng, ctx->heap, ctx->devId); -#else - ret = wc_InitRng(rng); + /* Add each member to the buffer delimited by a : */ + for (i = 0; i < ciphersSz; i++) { +#ifndef NO_CIPHER_SUITE_ALIASES + if (ciphers[i].flags & WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS) + continue; #endif - if (ret != 0) { - XFREE(rng, ctx->heap, DYNAMIC_TYPE_RNG); - return ret; - } + cipherNameSz = (int)XSTRLEN(ciphers[i].name_iana); + if (cipherNameSz + 1 < len) { + XSTRNCPY(buf, ciphers[i].name_iana, (size_t)len); + buf += cipherNameSz; - ctx->rng = rng; + if (i < ciphersSz - 1) + *buf++ = ':'; + *buf = 0; + + len -= cipherNameSz + 1; + } + else + return BUFFER_E; + } return WOLFSSL_SUCCESS; } -#endif +#endif /* NO_ERROR_STRINGS */ -WOLFSSL_ABI -WOLFSSL* wolfSSL_new(WOLFSSL_CTX* ctx) +const char* wolfSSL_get_shared_ciphers(WOLFSSL* ssl, char* buf, int len) { - WOLFSSL* ssl = NULL; - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_new"); + const char* cipher; - if (ctx == NULL) { - WOLFSSL_MSG("wolfSSL_new ctx is null"); + if (ssl == NULL) return NULL; - } - ssl = (WOLFSSL*) XMALLOC(sizeof(WOLFSSL), ctx->heap, DYNAMIC_TYPE_SSL); + cipher = wolfSSL_get_cipher_name_iana(ssl); + len = (int)min((word32)len, (word32)(XSTRLEN(cipher) + 1)); + XMEMCPY(buf, cipher, (size_t)len); + return buf; +} - if (ssl == NULL) { - WOLFSSL_MSG_EX("ssl xmalloc failed to allocate %d bytes", - (int)sizeof(WOLFSSL)); +int wolfSSL_get_fd(const WOLFSSL* ssl) +{ + int fd = -1; + WOLFSSL_ENTER("wolfSSL_get_fd"); + if (ssl) { + fd = ssl->rfd; } - else { - ret = InitSSL(ssl, ctx, 0); - if (ret < 0) { - WOLFSSL_MSG_EX("wolfSSL_new failed during InitSSL. err = %d", ret); - FreeSSL(ssl, ctx->heap); - ssl = NULL; - } - else if (ret == 0) { - WOLFSSL_MSG("wolfSSL_new InitSSL success"); - } - else { - /* Only success (0) or negative values should ever be seen. */ - WOLFSSL_MSG_EX("WARNING: wolfSSL_new unexpected InitSSL return" - " value = %d", ret); - } /* InitSSL check */ - } /* ssl XMALLOC success */ + WOLFSSL_LEAVE("wolfSSL_get_fd", fd); + return fd; +} - WOLFSSL_LEAVE("wolfSSL_new InitSSL =", ret); - (void)ret; +int wolfSSL_get_wfd(const WOLFSSL* ssl) +{ + int fd = -1; + WOLFSSL_ENTER("wolfSSL_get_fd"); + if (ssl) { + fd = ssl->wfd; + } + WOLFSSL_LEAVE("wolfSSL_get_fd", fd); + return fd; +} - return ssl; + +int wolfSSL_dtls(WOLFSSL* ssl) +{ + int dtlsOpt = 0; + if (ssl) + dtlsOpt = ssl->options.dtls; + return dtlsOpt; } +#ifdef WOLFSSL_WOLFSENTRY_HOOKS -WOLFSSL_ABI -void wolfSSL_free(WOLFSSL* ssl) +int wolfSSL_CTX_set_AcceptFilter( + WOLFSSL_CTX *ctx, + NetworkFilterCallback_t AcceptFilter, + void *AcceptFilter_arg) { - WOLFSSL_ENTER("wolfSSL_free"); + if (ctx == NULL) + return BAD_FUNC_ARG; + ctx->AcceptFilter = AcceptFilter; + ctx->AcceptFilter_arg = AcceptFilter_arg; + return 0; +} - if (ssl) { - WOLFSSL_MSG_EX("Free SSL: %p", (wc_ptr_t)ssl); - FreeSSL(ssl, ssl->ctx->heap); - } - else { - WOLFSSL_MSG("Free SSL: wolfSSL_free already null"); - } - WOLFSSL_LEAVE("wolfSSL_free", 0); +int wolfSSL_set_AcceptFilter( + WOLFSSL *ssl, + NetworkFilterCallback_t AcceptFilter, + void *AcceptFilter_arg) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + ssl->AcceptFilter = AcceptFilter; + ssl->AcceptFilter_arg = AcceptFilter_arg; + return 0; } +int wolfSSL_CTX_set_ConnectFilter( + WOLFSSL_CTX *ctx, + NetworkFilterCallback_t ConnectFilter, + void *ConnectFilter_arg) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + ctx->ConnectFilter = ConnectFilter; + ctx->ConnectFilter_arg = ConnectFilter_arg; + return 0; +} -int wolfSSL_is_server(WOLFSSL* ssl) +int wolfSSL_set_ConnectFilter( + WOLFSSL *ssl, + NetworkFilterCallback_t ConnectFilter, + void *ConnectFilter_arg) { if (ssl == NULL) return BAD_FUNC_ARG; - return ssl->options.side == WOLFSSL_SERVER_END; + ssl->ConnectFilter = ConnectFilter; + ssl->ConnectFilter_arg = ConnectFilter_arg; + return 0; } -#ifdef HAVE_WRITE_DUP +#endif /* WOLFSSL_WOLFSENTRY_HOOKS */ -/* - * Release resources around WriteDup object - * - * ssl WOLFSSL object - * - * no return, destruction so make best attempt -*/ -void FreeWriteDup(WOLFSSL* ssl) +#ifndef WOLFSSL_LEANPSK +#if defined(WOLFSSL_DTLS) && defined(XINET_PTON) && \ + !defined(WOLFSSL_NO_SOCK) && defined(HAVE_SOCKADDR) +void* wolfSSL_dtls_create_peer(int port, char* ip) { - int doFree = 0; - - WOLFSSL_ENTER("FreeWriteDup"); + SOCKADDR_IN *addr; + addr = (SOCKADDR_IN*)XMALLOC(sizeof(*addr), NULL, + DYNAMIC_TYPE_SOCKADDR); + if (addr == NULL) { + return NULL; + } - if (ssl->dupWrite) { - if (wc_LockMutex(&ssl->dupWrite->dupMutex) == 0) { - ssl->dupWrite->dupCount--; - if (ssl->dupWrite->dupCount == 0) { - doFree = 1; - } else { - WOLFSSL_MSG("WriteDup count not zero, no full free"); - } - wc_UnLockMutex(&ssl->dupWrite->dupMutex); - } + addr->sin_family = AF_INET; + addr->sin_port = XHTONS((word16)port); + if (XINET_PTON(AF_INET, ip, &addr->sin_addr) < 1) { + XFREE(addr, NULL, DYNAMIC_TYPE_SOCKADDR); + return NULL; } - if (doFree) { - WOLFSSL_MSG("Doing WriteDup full free, count to zero"); - wc_FreeMutex(&ssl->dupWrite->dupMutex); - XFREE(ssl->dupWrite, ssl->heap, DYNAMIC_TYPE_WRITEDUP); - } + return addr; } - -/* - * duplicate existing ssl members into dup needed for writing - * - * dup write only WOLFSSL - * ssl existing WOLFSSL - * - * 0 on success -*/ -static int DupSSL(WOLFSSL* dup, WOLFSSL* ssl) +int wolfSSL_dtls_free_peer(void* addr) { - word16 tmp_weOwnRng; - - /* shared dupWrite setup */ - ssl->dupWrite = (WriteDup*)XMALLOC(sizeof(WriteDup), ssl->heap, - DYNAMIC_TYPE_WRITEDUP); - if (ssl->dupWrite == NULL) { - return MEMORY_E; - } - XMEMSET(ssl->dupWrite, 0, sizeof(WriteDup)); - - if (wc_InitMutex(&ssl->dupWrite->dupMutex) != 0) { - XFREE(ssl->dupWrite, ssl->heap, DYNAMIC_TYPE_WRITEDUP); - ssl->dupWrite = NULL; - return BAD_MUTEX_E; - } - ssl->dupWrite->dupCount = 2; /* both sides have a count to start */ - dup->dupWrite = ssl->dupWrite; /* each side uses */ - - tmp_weOwnRng = dup->options.weOwnRng; - - /* copy write parts over to dup writer */ - XMEMCPY(&dup->specs, &ssl->specs, sizeof(CipherSpecs)); - XMEMCPY(&dup->options, &ssl->options, sizeof(Options)); - XMEMCPY(&dup->keys, &ssl->keys, sizeof(Keys)); - XMEMCPY(&dup->encrypt, &ssl->encrypt, sizeof(Ciphers)); - XMEMCPY(&dup->version, &ssl->version, sizeof(ProtocolVersion)); - XMEMCPY(&dup->chVersion, &ssl->chVersion, sizeof(ProtocolVersion)); - -#ifdef HAVE_ONE_TIME_AUTH -#ifdef HAVE_POLY1305 - if (ssl->auth.setup && ssl->auth.poly1305 != NULL) { - dup->auth.poly1305 = (Poly1305*)XMALLOC(sizeof(Poly1305), dup->heap, - DYNAMIC_TYPE_CIPHER); - if (dup->auth.poly1305 == NULL) - return MEMORY_E; - dup->auth.setup = 1; - } -#endif -#endif - - /* dup side now owns encrypt/write ciphers */ - XMEMSET(&ssl->encrypt, 0, sizeof(Ciphers)); - - dup->IOCB_WriteCtx = ssl->IOCB_WriteCtx; - dup->CBIOSend = ssl->CBIOSend; -#ifdef OPENSSL_EXTRA - dup->cbioFlag = ssl->cbioFlag; -#endif - dup->wfd = ssl->wfd; - dup->wflags = ssl->wflags; -#ifndef WOLFSSL_AEAD_ONLY - dup->hmac = ssl->hmac; -#endif -#ifdef HAVE_TRUNCATED_HMAC - dup->truncated_hmac = ssl->truncated_hmac; -#endif - - /* Restore rng option */ - dup->options.weOwnRng = tmp_weOwnRng; - - /* unique side dup setup */ - dup->dupSide = WRITE_DUP_SIDE; - ssl->dupSide = READ_DUP_SIDE; - - return 0; + XFREE(addr, NULL, DYNAMIC_TYPE_SOCKADDR); + return WOLFSSL_SUCCESS; } +#endif - -/* - * duplicate a WOLFSSL object post handshake for writing only - * turn existing object into read only. Allows concurrent access from two - * different threads. - * - * ssl existing WOLFSSL object - * - * return dup'd WOLFSSL object on success -*/ -WOLFSSL* wolfSSL_write_dup(WOLFSSL* ssl) +#ifdef WOLFSSL_DTLS +static int SockAddrSet(WOLFSSL_SOCKADDR* sockAddr, void* peer, + unsigned int peerSz, void* heap) { - WOLFSSL* dup = NULL; - int ret = 0; - - (void)ret; - WOLFSSL_ENTER("wolfSSL_write_dup"); - - if (ssl == NULL) { - return ssl; - } - - if (ssl->options.handShakeDone == 0) { - WOLFSSL_MSG("wolfSSL_write_dup called before handshake complete"); - return NULL; - } - - if (ssl->dupWrite) { - WOLFSSL_MSG("wolfSSL_write_dup already called once"); - return NULL; + if (peer == NULL || peerSz == 0) { + if (sockAddr->sa != NULL) + XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); + sockAddr->sa = NULL; + sockAddr->sz = 0; + sockAddr->bufSz = 0; + return WOLFSSL_SUCCESS; } - dup = (WOLFSSL*) XMALLOC(sizeof(WOLFSSL), ssl->ctx->heap, DYNAMIC_TYPE_SSL); - if (dup) { - if ( (ret = InitSSL(dup, ssl->ctx, 1)) < 0) { - FreeSSL(dup, ssl->ctx->heap); - dup = NULL; - } else if ( (ret = DupSSL(dup, ssl)) < 0) { - FreeSSL(dup, ssl->ctx->heap); - dup = NULL; + if (peerSz > sockAddr->bufSz) { + if (sockAddr->sa != NULL) + XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); + sockAddr->sa = + (void*)XMALLOC(peerSz, heap, DYNAMIC_TYPE_SOCKADDR); + if (sockAddr->sa == NULL) { + sockAddr->sz = 0; + sockAddr->bufSz = 0; + return WOLFSSL_FAILURE; } + sockAddr->bufSz = peerSz; } - - WOLFSSL_LEAVE("wolfSSL_write_dup", ret); - - return dup; + XMEMCPY(sockAddr->sa, peer, peerSz); + sockAddr->sz = peerSz; + return WOLFSSL_SUCCESS; } +#endif - -/* - * Notify write dup side of fatal error or close notify - * - * ssl WOLFSSL object - * err Notify err - * - * 0 on success -*/ -int NotifyWriteSide(WOLFSSL* ssl, int err) +int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) { +#ifdef WOLFSSL_DTLS int ret; - WOLFSSL_ENTER("NotifyWriteSide"); - - ret = wc_LockMutex(&ssl->dupWrite->dupMutex); - if (ret == 0) { - ssl->dupWrite->dupErr = err; - ret = wc_UnLockMutex(&ssl->dupWrite->dupMutex); - } - + if (ssl == NULL) + return WOLFSSL_FAILURE; +#ifdef WOLFSSL_RW_THREADED + if (wc_LockRwLock_Wr(&ssl->buffers.dtlsCtx.peerLock) != 0) + return WOLFSSL_FAILURE; +#endif + ret = SockAddrSet(&ssl->buffers.dtlsCtx.peer, peer, peerSz, ssl->heap); + if (ret == WOLFSSL_SUCCESS && !(peer == NULL || peerSz == 0)) + ssl->buffers.dtlsCtx.userSet = 1; + else + ssl->buffers.dtlsCtx.userSet = 0; +#ifdef WOLFSSL_RW_THREADED + if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) + ret = WOLFSSL_FAILURE; +#endif return ret; -} - - -#endif /* HAVE_WRITE_DUP */ - - -#ifdef HAVE_POLY1305 -/* set if to use old poly 1 for yes 0 to use new poly */ -int wolfSSL_use_old_poly(WOLFSSL* ssl, int value) -{ +#else (void)ssl; - (void)value; - -#ifndef WOLFSSL_NO_TLS12 - WOLFSSL_ENTER("wolfSSL_use_old_poly"); - WOLFSSL_MSG("Warning SSL connection auto detects old/new and this function" - "is depreciated"); - ssl->options.oldPoly = (word16)value; - WOLFSSL_LEAVE("wolfSSL_use_old_poly", 0); + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; #endif - return 0; } -#endif - -WOLFSSL_ABI -int wolfSSL_set_fd(WOLFSSL* ssl, int fd) +#if defined(WOLFSSL_DTLS_CID) && !defined(WOLFSSL_NO_SOCK) +int wolfSSL_dtls_set_pending_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) { - int ret; - - WOLFSSL_ENTER("wolfSSL_set_fd"); - - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - ret = wolfSSL_set_read_fd(ssl, fd); - if (ret == WOLFSSL_SUCCESS) { - ret = wolfSSL_set_write_fd(ssl, fd); - } - - return ret; -} - #ifdef WOLFSSL_DTLS -int wolfSSL_set_dtls_fd_connected(WOLFSSL* ssl, int fd) -{ - int ret; - - WOLFSSL_ENTER("wolfSSL_set_dtls_fd_connected"); - - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - ret = wolfSSL_set_fd(ssl, fd); - if (ret == WOLFSSL_SUCCESS) - ssl->buffers.dtlsCtx.connected = 1; - - return ret; -} -#endif - - -int wolfSSL_set_read_fd(WOLFSSL* ssl, int fd) -{ - WOLFSSL_ENTER("wolfSSL_set_read_fd"); - - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - ssl->rfd = fd; /* not used directly to allow IO callbacks */ - ssl->IOCB_ReadCtx = &ssl->rfd; - - #ifdef WOLFSSL_DTLS - ssl->buffers.dtlsCtx.connected = 0; - if (ssl->options.dtls) { - ssl->IOCB_ReadCtx = &ssl->buffers.dtlsCtx; - ssl->buffers.dtlsCtx.rfd = fd; - } - #endif - - WOLFSSL_LEAVE("wolfSSL_set_read_fd", WOLFSSL_SUCCESS); - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_set_write_fd(WOLFSSL* ssl, int fd) -{ - WOLFSSL_ENTER("wolfSSL_set_write_fd"); - - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - ssl->wfd = fd; /* not used directly to allow IO callbacks */ - ssl->IOCB_WriteCtx = &ssl->wfd; - - #ifdef WOLFSSL_DTLS - ssl->buffers.dtlsCtx.connected = 0; - if (ssl->options.dtls) { - ssl->IOCB_WriteCtx = &ssl->buffers.dtlsCtx; - ssl->buffers.dtlsCtx.wfd = fd; - } - #endif - - WOLFSSL_LEAVE("wolfSSL_set_write_fd", WOLFSSL_SUCCESS); - return WOLFSSL_SUCCESS; -} - - -/** - * Get the name of cipher at priority level passed in. - */ -char* wolfSSL_get_cipher_list(int priority) -{ - const CipherSuiteInfo* ciphers = GetCipherNames(); - - if (priority >= GetCipherNamesSize() || priority < 0) { - return 0; - } - - return (char*)ciphers[priority].name; -} - - -/** - * Get the name of cipher at priority level passed in. - */ -char* wolfSSL_get_cipher_list_ex(WOLFSSL* ssl, int priority) -{ - - if (ssl == NULL) { - return NULL; - } - else { - const char* cipher; - - if ((cipher = wolfSSL_get_cipher_name_internal(ssl)) != NULL) { - if (priority == 0) { - return (char*)cipher; - } - else { - return NULL; - } - } - else { - return wolfSSL_get_cipher_list(priority); - } - } -} - - -int wolfSSL_get_ciphers(char* buf, int len) -{ - const CipherSuiteInfo* ciphers = GetCipherNames(); - int ciphersSz = GetCipherNamesSize(); - int i; - - if (buf == NULL || len <= 0) - return BAD_FUNC_ARG; - - /* Add each member to the buffer delimited by a : */ - for (i = 0; i < ciphersSz; i++) { - int cipherNameSz = (int)XSTRLEN(ciphers[i].name); - if (cipherNameSz + 1 < len) { - XSTRNCPY(buf, ciphers[i].name, (size_t)len); - buf += cipherNameSz; - - if (i < ciphersSz - 1) - *buf++ = ':'; - *buf = 0; - - len -= cipherNameSz + 1; - } - else - return BUFFER_E; - } - return WOLFSSL_SUCCESS; -} - - -#ifndef NO_ERROR_STRINGS -/* places a list of all supported cipher suites in TLS_* format into "buf" - * return WOLFSSL_SUCCESS on success */ -int wolfSSL_get_ciphers_iana(char* buf, int len) -{ - const CipherSuiteInfo* ciphers = GetCipherNames(); - int ciphersSz = GetCipherNamesSize(); - int i; - int cipherNameSz; - - if (buf == NULL || len <= 0) - return BAD_FUNC_ARG; - - /* Add each member to the buffer delimited by a : */ - for (i = 0; i < ciphersSz; i++) { -#ifndef NO_CIPHER_SUITE_ALIASES - if (ciphers[i].flags & WOLFSSL_CIPHER_SUITE_FLAG_NAMEALIAS) - continue; -#endif - cipherNameSz = (int)XSTRLEN(ciphers[i].name_iana); - if (cipherNameSz + 1 < len) { - XSTRNCPY(buf, ciphers[i].name_iana, (size_t)len); - buf += cipherNameSz; - - if (i < ciphersSz - 1) - *buf++ = ':'; - *buf = 0; - - len -= cipherNameSz + 1; - } - else - return BUFFER_E; - } - return WOLFSSL_SUCCESS; -} -#endif /* NO_ERROR_STRINGS */ - - -const char* wolfSSL_get_shared_ciphers(WOLFSSL* ssl, char* buf, int len) -{ - const char* cipher; - - if (ssl == NULL) - return NULL; - - cipher = wolfSSL_get_cipher_name_iana(ssl); - len = (int)min((word32)len, (word32)(XSTRLEN(cipher) + 1)); - XMEMCPY(buf, cipher, (size_t)len); - return buf; -} - -int wolfSSL_get_fd(const WOLFSSL* ssl) -{ - int fd = -1; - WOLFSSL_ENTER("wolfSSL_get_fd"); - if (ssl) { - fd = ssl->rfd; - } - WOLFSSL_LEAVE("wolfSSL_get_fd", fd); - return fd; -} - -int wolfSSL_get_wfd(const WOLFSSL* ssl) -{ - int fd = -1; - WOLFSSL_ENTER("wolfSSL_get_fd"); - if (ssl) { - fd = ssl->wfd; - } - WOLFSSL_LEAVE("wolfSSL_get_fd", fd); - return fd; -} - - -int wolfSSL_dtls(WOLFSSL* ssl) -{ - int dtlsOpt = 0; - if (ssl) - dtlsOpt = ssl->options.dtls; - return dtlsOpt; -} - -#if !defined(NO_CERTS) -/* Set whether mutual authentication is required for connections. - * Server side only. - * - * ctx The SSL/TLS CTX object. - * req 1 to indicate required and 0 when not. - * returns BAD_FUNC_ARG when ctx is NULL, SIDE_ERROR when not a server and - * 0 on success. - */ -int wolfSSL_CTX_mutual_auth(WOLFSSL_CTX* ctx, int req) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - if (ctx->method->side != WOLFSSL_SERVER_END) - return SIDE_ERROR; - - ctx->mutualAuth = (byte)req; - - return 0; -} - -/* Set whether mutual authentication is required for the connection. - * Server side only. - * - * ssl The SSL/TLS object. - * req 1 to indicate required and 0 when not. - * returns BAD_FUNC_ARG when ssl is NULL and - * SIDE_ERROR when not a server and 0 on success. - */ -int wolfSSL_mutual_auth(WOLFSSL* ssl, int req) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - if (ssl->options.side != WOLFSSL_SERVER_END) - return SIDE_ERROR; - - ssl->options.mutualAuth = (word16)req; - - return 0; -} -#endif /* NO_CERTS */ - -#ifdef WOLFSSL_WOLFSENTRY_HOOKS - -int wolfSSL_CTX_set_AcceptFilter( - WOLFSSL_CTX *ctx, - NetworkFilterCallback_t AcceptFilter, - void *AcceptFilter_arg) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - ctx->AcceptFilter = AcceptFilter; - ctx->AcceptFilter_arg = AcceptFilter_arg; - return 0; -} - -int wolfSSL_set_AcceptFilter( - WOLFSSL *ssl, - NetworkFilterCallback_t AcceptFilter, - void *AcceptFilter_arg) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - ssl->AcceptFilter = AcceptFilter; - ssl->AcceptFilter_arg = AcceptFilter_arg; - return 0; -} - -int wolfSSL_CTX_set_ConnectFilter( - WOLFSSL_CTX *ctx, - NetworkFilterCallback_t ConnectFilter, - void *ConnectFilter_arg) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - ctx->ConnectFilter = ConnectFilter; - ctx->ConnectFilter_arg = ConnectFilter_arg; - return 0; -} - -int wolfSSL_set_ConnectFilter( - WOLFSSL *ssl, - NetworkFilterCallback_t ConnectFilter, - void *ConnectFilter_arg) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - ssl->ConnectFilter = ConnectFilter; - ssl->ConnectFilter_arg = ConnectFilter_arg; - return 0; -} - -#endif /* WOLFSSL_WOLFSENTRY_HOOKS */ - -#ifndef WOLFSSL_LEANPSK -#if defined(WOLFSSL_DTLS) && defined(XINET_PTON) && \ - !defined(WOLFSSL_NO_SOCK) && defined(HAVE_SOCKADDR) -void* wolfSSL_dtls_create_peer(int port, char* ip) -{ - SOCKADDR_IN *addr; - addr = (SOCKADDR_IN*)XMALLOC(sizeof(*addr), NULL, - DYNAMIC_TYPE_SOCKADDR); - if (addr == NULL) { - return NULL; - } - - addr->sin_family = AF_INET; - addr->sin_port = XHTONS((word16)port); - if (XINET_PTON(AF_INET, ip, &addr->sin_addr) < 1) { - XFREE(addr, NULL, DYNAMIC_TYPE_SOCKADDR); - return NULL; - } - - return addr; -} - -int wolfSSL_dtls_free_peer(void* addr) -{ - XFREE(addr, NULL, DYNAMIC_TYPE_SOCKADDR); - return WOLFSSL_SUCCESS; -} -#endif - -#ifdef WOLFSSL_DTLS -static int SockAddrSet(WOLFSSL_SOCKADDR* sockAddr, void* peer, - unsigned int peerSz, void* heap) -{ - if (peer == NULL || peerSz == 0) { - if (sockAddr->sa != NULL) - XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); - sockAddr->sa = NULL; - sockAddr->sz = 0; - sockAddr->bufSz = 0; - return WOLFSSL_SUCCESS; - } - - if (peerSz > sockAddr->bufSz) { - if (sockAddr->sa != NULL) - XFREE(sockAddr->sa, heap, DYNAMIC_TYPE_SOCKADDR); - sockAddr->sa = - (void*)XMALLOC(peerSz, heap, DYNAMIC_TYPE_SOCKADDR); - if (sockAddr->sa == NULL) { - sockAddr->sz = 0; - sockAddr->bufSz = 0; - return WOLFSSL_FAILURE; - } - sockAddr->bufSz = peerSz; - } - XMEMCPY(sockAddr->sa, peer, peerSz); - sockAddr->sz = peerSz; - return WOLFSSL_SUCCESS; -} -#endif - -int wolfSSL_dtls_set_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) -{ -#ifdef WOLFSSL_DTLS - int ret; - - if (ssl == NULL) - return WOLFSSL_FAILURE; -#ifdef WOLFSSL_RW_THREADED - if (wc_LockRwLock_Wr(&ssl->buffers.dtlsCtx.peerLock) != 0) - return WOLFSSL_FAILURE; -#endif - ret = SockAddrSet(&ssl->buffers.dtlsCtx.peer, peer, peerSz, ssl->heap); - if (ret == WOLFSSL_SUCCESS && !(peer == NULL || peerSz == 0)) - ssl->buffers.dtlsCtx.userSet = 1; - else - ssl->buffers.dtlsCtx.userSet = 0; -#ifdef WOLFSSL_RW_THREADED - if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) - ret = WOLFSSL_FAILURE; -#endif - return ret; -#else - (void)ssl; - (void)peer; - (void)peerSz; - return WOLFSSL_NOT_IMPLEMENTED; -#endif -} - -#if defined(WOLFSSL_DTLS_CID) && !defined(WOLFSSL_NO_SOCK) -int wolfSSL_dtls_set_pending_peer(WOLFSSL* ssl, void* peer, unsigned int peerSz) -{ -#ifdef WOLFSSL_DTLS - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - - if (ssl == NULL) - return WOLFSSL_FAILURE; -#ifdef WOLFSSL_RW_THREADED - if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0) - return WOLFSSL_FAILURE; -#endif - if (ssl->buffers.dtlsCtx.peer.sa != NULL && - ssl->buffers.dtlsCtx.peer.sz == peerSz && - sockAddrEqual((SOCKADDR_S*)ssl->buffers.dtlsCtx.peer.sa, - (XSOCKLENT)ssl->buffers.dtlsCtx.peer.sz, (SOCKADDR_S*)peer, - (XSOCKLENT)peerSz)) { - /* Already the current peer. */ - if (ssl->buffers.dtlsCtx.pendingPeer.sa != NULL) { - /* Clear any other pendingPeer */ - XFREE(ssl->buffers.dtlsCtx.pendingPeer.sa, ssl->heap, - DYNAMIC_TYPE_SOCKADDR); - ssl->buffers.dtlsCtx.pendingPeer.sa = NULL; - ssl->buffers.dtlsCtx.pendingPeer.sz = 0; - ssl->buffers.dtlsCtx.pendingPeer.bufSz = 0; - } - ret = WOLFSSL_SUCCESS; - } - else { - ret = SockAddrSet(&ssl->buffers.dtlsCtx.pendingPeer, peer, peerSz, - ssl->heap); - } - if (ret == WOLFSSL_SUCCESS) - ssl->buffers.dtlsCtx.processingPendingRecord = 0; -#ifdef WOLFSSL_RW_THREADED - if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) - ret = WOLFSSL_FAILURE; -#endif - return ret; -#else - (void)ssl; - (void)peer; - (void)peerSz; - return WOLFSSL_NOT_IMPLEMENTED; -#endif -} -#endif /* WOLFSSL_DTLS_CID && !WOLFSSL_NO_SOCK */ - -int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz) -{ -#ifdef WOLFSSL_DTLS - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - if (ssl == NULL) - return WOLFSSL_FAILURE; -#ifdef WOLFSSL_RW_THREADED - if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0) - return WOLFSSL_FAILURE; -#endif - if (peer != NULL && peerSz != NULL - && *peerSz >= ssl->buffers.dtlsCtx.peer.sz - && ssl->buffers.dtlsCtx.peer.sa != NULL) { - *peerSz = ssl->buffers.dtlsCtx.peer.sz; - XMEMCPY(peer, ssl->buffers.dtlsCtx.peer.sa, *peerSz); - ret = WOLFSSL_SUCCESS; - } -#ifdef WOLFSSL_RW_THREADED - if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) - ret = WOLFSSL_FAILURE; -#endif - return ret; -#else - (void)ssl; - (void)peer; - (void)peerSz; - return WOLFSSL_NOT_IMPLEMENTED; -#endif -} - -int wolfSSL_dtls_get0_peer(WOLFSSL* ssl, const void** peer, - unsigned int* peerSz) -{ -#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_RW_THREADED) - if (ssl == NULL) - return WOLFSSL_FAILURE; - - if (peer == NULL || peerSz == NULL) - return WOLFSSL_FAILURE; - - *peer = ssl->buffers.dtlsCtx.peer.sa; - *peerSz = ssl->buffers.dtlsCtx.peer.sz; - return WOLFSSL_SUCCESS; -#else - (void)ssl; - (void)peer; - (void)peerSz; - return WOLFSSL_NOT_IMPLEMENTED; -#endif -} - - -#if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) - -int wolfSSL_CTX_dtls_set_sctp(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_dtls_set_sctp"); - - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->dtlsSctp = 1; - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_dtls_set_sctp(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_dtls_set_sctp"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->options.dtlsSctp = 1; - return WOLFSSL_SUCCESS; -} - -#endif /* WOLFSSL_DTLS && WOLFSSL_SCTP */ - -#if (defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU)) && \ - defined(WOLFSSL_DTLS) - -int wolfSSL_CTX_dtls_set_mtu(WOLFSSL_CTX* ctx, word16 newMtu) -{ - if (ctx == NULL || newMtu > MAX_RECORD_SIZE) - return BAD_FUNC_ARG; - - ctx->dtlsMtuSz = newMtu; - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_dtls_set_mtu(WOLFSSL* ssl, word16 newMtu) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - if (newMtu > MAX_RECORD_SIZE) { - ssl->error = BAD_FUNC_ARG; - return WOLFSSL_FAILURE; - } - - ssl->dtlsMtuSz = newMtu; - return WOLFSSL_SUCCESS; -} - -#ifdef OPENSSL_EXTRA -/* Maps to compatibility API SSL_set_mtu and is same as wolfSSL_dtls_set_mtu, - * but expects only success or failure returns. */ -int wolfSSL_set_mtu_compat(WOLFSSL* ssl, unsigned short mtu) -{ - if (wolfSSL_dtls_set_mtu(ssl, mtu) == WOLFSSL_SUCCESS) - return WOLFSSL_SUCCESS; - else - return WOLFSSL_FAILURE; -} -#endif /* OPENSSL_EXTRA */ - -#endif /* WOLFSSL_DTLS && (WOLFSSL_SCTP || WOLFSSL_DTLS_MTU) */ - -#ifdef WOLFSSL_SRTP - -static const WOLFSSL_SRTP_PROTECTION_PROFILE gSrtpProfiles[] = { - /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 80-bits - * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ - {"SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, - (((128 + 112) * 2) / 8) }, - /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 32-bits - * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ - {"SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32, - (((128 + 112) * 2) / 8) }, - /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 80-bits */ - {"SRTP_NULL_SHA1_80", SRTP_NULL_SHA1_80, ((112 * 2) / 8)}, - /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 32-bits */ - {"SRTP_NULL_SHA1_32", SRTP_NULL_SHA1_32, ((112 * 2) / 8)}, - /* AES GCM 128, Salt: 96-bits, Auth GCM Tag 128-bits - * (master_key:128bits + master_salt:96bits) * 2 = 448 bits (56) */ - {"SRTP_AEAD_AES_128_GCM", SRTP_AEAD_AES_128_GCM, (((128 + 96) * 2) / 8) }, - /* AES GCM 256, Salt: 96-bits, Auth GCM Tag 128-bits - * (master_key:256bits + master_salt:96bits) * 2 = 704 bits (88) */ - {"SRTP_AEAD_AES_256_GCM", SRTP_AEAD_AES_256_GCM, (((256 + 96) * 2) / 8) }, -}; - -static const WOLFSSL_SRTP_PROTECTION_PROFILE* DtlsSrtpFindProfile( - const char* profile_str, word32 profile_str_len, unsigned long id) -{ - int i; - const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; - for (i=0; - i<(int)(sizeof(gSrtpProfiles)/sizeof(WOLFSSL_SRTP_PROTECTION_PROFILE)); - i++) { - if (profile_str != NULL) { - word32 srtp_profile_len = (word32)XSTRLEN(gSrtpProfiles[i].name); - if (srtp_profile_len == profile_str_len && - XMEMCMP(gSrtpProfiles[i].name, profile_str, profile_str_len) - == 0) { - profile = &gSrtpProfiles[i]; - break; - } - } - else if (id != 0 && gSrtpProfiles[i].id == id) { - profile = &gSrtpProfiles[i]; - break; - } - } - return profile; -} - -/* profile_str: accepts ":" colon separated list of SRTP profiles */ -static int DtlsSrtpSelProfiles(word16* id, const char* profile_str) -{ - const WOLFSSL_SRTP_PROTECTION_PROFILE* profile; - const char *current, *next = NULL; - word32 length = 0, current_length; - - *id = 0; /* reset destination ID's */ - - if (profile_str == NULL) { - return WOLFSSL_FAILURE; - } - - /* loop on end of line or colon ":" */ - next = profile_str; - length = (word32)XSTRLEN(profile_str); - do { - current = next; - next = XSTRSTR(current, ":"); - if (next) { - current_length = (word32)(next - current); - ++next; /* ++ needed to skip ':' */ - } else { - current_length = (word32)XSTRLEN(current); - } - if (current_length < length) - length = current_length; - profile = DtlsSrtpFindProfile(current, current_length, 0); - if (profile != NULL) { - *id |= (1 << profile->id); /* selected bit based on ID */ - } - } while (next != NULL); - return WOLFSSL_SUCCESS; -} - -/** - * @brief Set the SRTP protection profiles for DTLS. - * - * @param ctx Pointer to the WOLFSSL_CTX structure representing the SSL/TLS - * context. - * @param profile_str A colon-separated string of SRTP profile names. - * @return 0 on success to match OpenSSL - * @return 1 on error to match OpenSSL - */ -int wolfSSL_CTX_set_tlsext_use_srtp(WOLFSSL_CTX* ctx, const char* profile_str) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - if (ctx != NULL) { - ret = DtlsSrtpSelProfiles(&ctx->dtlsSrtpProfiles, profile_str); - } - - if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { - ret = 1; - } else { - ret = 0; - } - - return ret; -} - -/** - * @brief Set the SRTP protection profiles for DTLS. - * - * @param ssl Pointer to the WOLFSSL structure representing the SSL/TLS - * session. - * @param profile_str A colon-separated string of SRTP profile names. - * @return 0 on success to match OpenSSL - * @return 1 on error to match OpenSSL - */ -int wolfSSL_set_tlsext_use_srtp(WOLFSSL* ssl, const char* profile_str) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - if (ssl != NULL) { - ret = DtlsSrtpSelProfiles(&ssl->dtlsSrtpProfiles, profile_str); - } - - if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { - ret = 1; - } else { - ret = 0; - } - - return ret; -} - -const WOLFSSL_SRTP_PROTECTION_PROFILE* wolfSSL_get_selected_srtp_profile( - WOLFSSL* ssl) -{ - const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; - if (ssl) { - profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); - } - return profile; -} -#ifndef NO_WOLFSSL_STUB -WOLF_STACK_OF(WOLFSSL_SRTP_PROTECTION_PROFILE)* wolfSSL_get_srtp_profiles( - WOLFSSL* ssl) -{ - /* Not yet implemented - should return list of available SRTP profiles - * ssl->dtlsSrtpProfiles */ - (void)ssl; - return NULL; -} -#endif - -#define DTLS_SRTP_KEYING_MATERIAL_LABEL "EXTRACTOR-dtls_srtp" - -int wolfSSL_export_dtls_srtp_keying_material(WOLFSSL* ssl, - unsigned char* out, size_t* olen) -{ - const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; - - if (ssl == NULL || olen == NULL) { - return BAD_FUNC_ARG; - } - - profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); - if (profile == NULL) { - WOLFSSL_MSG("Not using DTLS SRTP"); - return EXT_MISSING; - } - if (out == NULL) { - *olen = (size_t)profile->kdfBits; - return WC_NO_ERR_TRACE(LENGTH_ONLY_E); - } - - if (*olen < (size_t)profile->kdfBits) { - return BUFFER_E; - } - - return wolfSSL_export_keying_material(ssl, out, (size_t)profile->kdfBits, - DTLS_SRTP_KEYING_MATERIAL_LABEL, - XSTR_SIZEOF(DTLS_SRTP_KEYING_MATERIAL_LABEL), NULL, 0, 0); -} - -#endif /* WOLFSSL_SRTP */ - - -#ifdef WOLFSSL_DTLS_DROP_STATS - -int wolfSSL_dtls_get_drop_stats(WOLFSSL* ssl, - word32* macDropCount, word32* replayDropCount) -{ - int ret; - - WOLFSSL_ENTER("wolfSSL_dtls_get_drop_stats"); - - if (ssl == NULL) - ret = BAD_FUNC_ARG; - else { - ret = WOLFSSL_SUCCESS; - if (macDropCount != NULL) - *macDropCount = ssl->macDropCount; - if (replayDropCount != NULL) - *replayDropCount = ssl->replayDropCount; - } - - WOLFSSL_LEAVE("wolfSSL_dtls_get_drop_stats", ret); - return ret; -} - -#endif /* WOLFSSL_DTLS_DROP_STATS */ - - -#if defined(WOLFSSL_MULTICAST) - -int wolfSSL_CTX_mcast_set_member_id(WOLFSSL_CTX* ctx, word16 id) -{ - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_CTX_mcast_set_member_id"); - - if (ctx == NULL || id > WOLFSSL_MAX_8BIT) - ret = BAD_FUNC_ARG; - - if (ret == 0) { - ctx->haveEMS = 0; - ctx->haveMcast = 1; - ctx->mcastID = (byte)id; -#ifndef WOLFSSL_USER_IO - ctx->CBIORecv = EmbedReceiveFromMcast; -#endif /* WOLFSSL_USER_IO */ - - ret = WOLFSSL_SUCCESS; - } - WOLFSSL_LEAVE("wolfSSL_CTX_mcast_set_member_id", ret); - return ret; -} - -int wolfSSL_mcast_get_max_peers(void) -{ - return WOLFSSL_MULTICAST_PEERS; -} - -#ifdef WOLFSSL_DTLS -static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first, - word32 second, word32 high) -{ - word32 newCur = 0; - - if (cur < first) - newCur = first; - else if (cur < second) - newCur = second; - else if (cur < high) - newCur = high; - - return newCur; -} -#endif /* WOLFSSL_DTLS */ - - -int wolfSSL_set_secret(WOLFSSL* ssl, word16 epoch, - const byte* preMasterSecret, word32 preMasterSz, - const byte* clientRandom, const byte* serverRandom, - const byte* suite) -{ - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_set_secret"); - - if (ssl == NULL || preMasterSecret == NULL || - preMasterSz == 0 || preMasterSz > ENCRYPT_LEN || - clientRandom == NULL || serverRandom == NULL || suite == NULL) { - - ret = BAD_FUNC_ARG; - } - - if (ret == 0 && ssl->arrays->preMasterSecret == NULL) { - ssl->arrays->preMasterSz = ENCRYPT_LEN; - ssl->arrays->preMasterSecret = (byte*)XMALLOC(ENCRYPT_LEN, ssl->heap, - DYNAMIC_TYPE_SECRET); - if (ssl->arrays->preMasterSecret == NULL) { - ret = MEMORY_E; - } - } - - if (ret == 0) { - XMEMCPY(ssl->arrays->preMasterSecret, preMasterSecret, preMasterSz); - XMEMSET(ssl->arrays->preMasterSecret + preMasterSz, 0, - ENCRYPT_LEN - preMasterSz); - ssl->arrays->preMasterSz = preMasterSz; - XMEMCPY(ssl->arrays->clientRandom, clientRandom, RAN_LEN); - XMEMCPY(ssl->arrays->serverRandom, serverRandom, RAN_LEN); - ssl->options.cipherSuite0 = suite[0]; - ssl->options.cipherSuite = suite[1]; - - ret = SetCipherSpecs(ssl); - } - - if (ret == 0) - ret = MakeTlsMasterSecret(ssl); - - if (ret == 0) { - ssl->keys.encryptionOn = 1; - ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE); - } - - if (ret == 0) { - if (ssl->options.dtls) { - #ifdef WOLFSSL_DTLS - WOLFSSL_DTLS_PEERSEQ* peerSeq; - int i; - - ssl->keys.dtls_epoch = epoch; - for (i = 0, peerSeq = ssl->keys.peerSeq; - i < WOLFSSL_DTLS_PEERSEQ_SZ; - i++, peerSeq++) { - - peerSeq->nextEpoch = epoch; - peerSeq->prevSeq_lo = peerSeq->nextSeq_lo; - peerSeq->prevSeq_hi = peerSeq->nextSeq_hi; - peerSeq->nextSeq_lo = 0; - peerSeq->nextSeq_hi = 0; - XMEMCPY(peerSeq->prevWindow, peerSeq->window, DTLS_SEQ_SZ); - XMEMSET(peerSeq->window, 0, DTLS_SEQ_SZ); - peerSeq->highwaterMark = UpdateHighwaterMark(0, - ssl->ctx->mcastFirstSeq, - ssl->ctx->mcastSecondSeq, - ssl->ctx->mcastMaxSeq); - } - #else - (void)epoch; - #endif - } - FreeHandshakeResources(ssl); - ret = WOLFSSL_SUCCESS; - } - else { - if (ssl) - ssl->error = ret; - ret = WOLFSSL_FATAL_ERROR; - } - WOLFSSL_LEAVE("wolfSSL_set_secret", ret); - return ret; -} - - -#ifdef WOLFSSL_DTLS - -int wolfSSL_mcast_peer_add(WOLFSSL* ssl, word16 peerId, int sub) -{ - WOLFSSL_DTLS_PEERSEQ* p = NULL; - int ret = WOLFSSL_SUCCESS; - int i; - - WOLFSSL_ENTER("wolfSSL_mcast_peer_add"); - if (ssl == NULL || peerId > WOLFSSL_MAX_8BIT) - return BAD_FUNC_ARG; - - if (!sub) { - /* Make sure it isn't already present, while keeping the first - * open spot. */ - for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { - if (ssl->keys.peerSeq[i].peerId == INVALID_PEER_ID) - p = &ssl->keys.peerSeq[i]; - if (ssl->keys.peerSeq[i].peerId == peerId) { - WOLFSSL_MSG("Peer ID already in multicast peer list."); - p = NULL; - } - } - - if (p != NULL) { - XMEMSET(p, 0, sizeof(WOLFSSL_DTLS_PEERSEQ)); - p->peerId = peerId; - p->highwaterMark = UpdateHighwaterMark(0, - ssl->ctx->mcastFirstSeq, - ssl->ctx->mcastSecondSeq, - ssl->ctx->mcastMaxSeq); - } - else { - WOLFSSL_MSG("No room in peer list."); - ret = WOLFSSL_FATAL_ERROR; - } - } - else { - for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { - if (ssl->keys.peerSeq[i].peerId == peerId) - p = &ssl->keys.peerSeq[i]; - } - - if (p != NULL) { - p->peerId = INVALID_PEER_ID; - } - else { - WOLFSSL_MSG("Peer not found in list."); - } - } - - WOLFSSL_LEAVE("wolfSSL_mcast_peer_add", ret); - return ret; -} - - -/* If peerId is in the list of peers and its last sequence number is non-zero, - * return 1, otherwise return 0. */ -int wolfSSL_mcast_peer_known(WOLFSSL* ssl, unsigned short peerId) -{ - int known = 0; - int i; - - WOLFSSL_ENTER("wolfSSL_mcast_peer_known"); - - if (ssl == NULL || peerId > WOLFSSL_MAX_8BIT) { - return BAD_FUNC_ARG; - } - - for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { - if (ssl->keys.peerSeq[i].peerId == peerId) { - if (ssl->keys.peerSeq[i].nextSeq_hi || - ssl->keys.peerSeq[i].nextSeq_lo) { - - known = 1; - } - break; - } - } - - WOLFSSL_LEAVE("wolfSSL_mcast_peer_known", known); - return known; -} - - -int wolfSSL_CTX_mcast_set_highwater_cb(WOLFSSL_CTX* ctx, word32 maxSeq, - word32 first, word32 second, - CallbackMcastHighwater cb) -{ - if (ctx == NULL || (second && first > second) || - first > maxSeq || second > maxSeq || cb == NULL) { - - return BAD_FUNC_ARG; - } - - ctx->mcastHwCb = cb; - ctx->mcastFirstSeq = first; - ctx->mcastSecondSeq = second; - ctx->mcastMaxSeq = maxSeq; - - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_mcast_set_highwater_ctx(WOLFSSL* ssl, void* ctx) -{ - if (ssl == NULL || ctx == NULL) - return BAD_FUNC_ARG; - - ssl->mcastHwCbCtx = ctx; - - return WOLFSSL_SUCCESS; -} - -#endif /* WOLFSSL_DTLS */ - -#endif /* WOLFSSL_MULTICAST */ - - -#endif /* WOLFSSL_LEANPSK */ - -#ifndef NO_TLS -/* return underlying connect or accept, WOLFSSL_SUCCESS on ok */ -int wolfSSL_negotiate(WOLFSSL* ssl) -{ - int err = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); - - WOLFSSL_ENTER("wolfSSL_negotiate"); - - if (ssl == NULL) - return WOLFSSL_FATAL_ERROR; - -#ifndef NO_WOLFSSL_SERVER - if (ssl->options.side == WOLFSSL_SERVER_END) { -#ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version)) - err = wolfSSL_accept_TLSv13(ssl); - else -#endif - err = wolfSSL_accept(ssl); - } -#endif - -#ifndef NO_WOLFSSL_CLIENT - if (ssl->options.side == WOLFSSL_CLIENT_END) { -#ifdef WOLFSSL_TLS13 - if (IsAtLeastTLSv1_3(ssl->version)) - err = wolfSSL_connect_TLSv13(ssl); - else -#endif - err = wolfSSL_connect(ssl); - } -#endif - - (void)ssl; - - WOLFSSL_LEAVE("wolfSSL_negotiate", err); - - return err; -} -#endif /* !NO_TLS */ - -WOLFSSL_ABI -WC_RNG* wolfSSL_GetRNG(WOLFSSL* ssl) -{ - if (ssl) { - return ssl->rng; - } - - return NULL; -} - - -#ifndef WOLFSSL_LEANPSK -/* object size based on build */ -int wolfSSL_GetObjectSize(void) -{ -#ifdef SHOW_SIZES - printf("sizeof suites = %lu\n", (unsigned long)sizeof(Suites)); - printf("sizeof ciphers(2) = %lu\n", (unsigned long)sizeof(Ciphers)); -#ifndef NO_RC4 - printf("\tsizeof arc4 = %lu\n", (unsigned long)sizeof(Arc4)); -#endif - printf("\tsizeof aes = %lu\n", (unsigned long)sizeof(Aes)); -#ifndef NO_DES3 - printf("\tsizeof des3 = %lu\n", (unsigned long)sizeof(Des3)); -#endif -#ifdef HAVE_CHACHA - printf("\tsizeof chacha = %lu\n", (unsigned long)sizeof(ChaCha)); -#endif -#ifdef WOLFSSL_SM4 - printf("\tsizeof sm4 = %lu\n", (unsigned long)sizeof(Sm4)); -#endif - printf("sizeof cipher specs = %lu\n", (unsigned long) - sizeof(CipherSpecs)); - printf("sizeof keys = %lu\n", (unsigned long)sizeof(Keys)); - printf("sizeof Hashes(2) = %lu\n", (unsigned long)sizeof(Hashes)); -#ifndef NO_MD5 - printf("\tsizeof MD5 = %lu\n", (unsigned long)sizeof(wc_Md5)); -#endif -#ifndef NO_SHA - printf("\tsizeof SHA = %lu\n", (unsigned long)sizeof(wc_Sha)); -#endif -#ifdef WOLFSSL_SHA224 - printf("\tsizeof SHA224 = %lu\n", (unsigned long)sizeof(wc_Sha224)); -#endif -#ifndef NO_SHA256 - printf("\tsizeof SHA256 = %lu\n", (unsigned long)sizeof(wc_Sha256)); -#endif -#ifdef WOLFSSL_SHA384 - printf("\tsizeof SHA384 = %lu\n", (unsigned long)sizeof(wc_Sha384)); -#endif -#ifdef WOLFSSL_SHA384 - printf("\tsizeof SHA512 = %lu\n", (unsigned long)sizeof(wc_Sha512)); -#endif -#ifdef WOLFSSL_SM3 - printf("\tsizeof sm3 = %lu\n", (unsigned long)sizeof(Sm3)); -#endif - printf("sizeof Buffers = %lu\n", (unsigned long)sizeof(Buffers)); - printf("sizeof Options = %lu\n", (unsigned long)sizeof(Options)); - printf("sizeof Arrays = %lu\n", (unsigned long)sizeof(Arrays)); -#ifndef NO_RSA - printf("sizeof RsaKey = %lu\n", (unsigned long)sizeof(RsaKey)); -#endif -#ifdef HAVE_ECC - printf("sizeof ecc_key = %lu\n", (unsigned long)sizeof(ecc_key)); -#endif - printf("sizeof WOLFSSL_CIPHER = %lu\n", (unsigned long) - sizeof(WOLFSSL_CIPHER)); - printf("sizeof WOLFSSL_SESSION = %lu\n", (unsigned long) - sizeof(WOLFSSL_SESSION)); - printf("sizeof WOLFSSL = %lu\n", (unsigned long)sizeof(WOLFSSL)); - printf("sizeof WOLFSSL_CTX = %lu\n", (unsigned long) - sizeof(WOLFSSL_CTX)); -#endif - - return sizeof(WOLFSSL); -} - -int wolfSSL_CTX_GetObjectSize(void) -{ - return sizeof(WOLFSSL_CTX); -} - -int wolfSSL_METHOD_GetObjectSize(void) -{ - return sizeof(WOLFSSL_METHOD); -} -#endif - - -#ifdef WOLFSSL_STATIC_MEMORY - -int wolfSSL_CTX_load_static_memory(WOLFSSL_CTX** ctx, - wolfSSL_method_func method, unsigned char* buf, unsigned int sz, int flag, - int maxSz) -{ - WOLFSSL_HEAP_HINT* hint = NULL; - - if (ctx == NULL || buf == NULL) { - return BAD_FUNC_ARG; - } - - if (*ctx == NULL && method == NULL) { - return BAD_FUNC_ARG; - } - - /* If there is a heap already, capture it in hint. */ - if (*ctx && (*ctx)->heap != NULL) { - hint = (*ctx)->heap; - } - - if (wc_LoadStaticMemory(&hint, buf, sz, flag, maxSz)) { - WOLFSSL_MSG("Error loading static memory"); - return WOLFSSL_FAILURE; - } - - if (*ctx) { - if ((*ctx)->heap == NULL) { - (*ctx)->heap = (void*)hint; - } - } - else { - /* create ctx if needed */ - *ctx = wolfSSL_CTX_new_ex(method(hint), hint); - if (*ctx == NULL) { - WOLFSSL_MSG("Error creating ctx"); - return WOLFSSL_FAILURE; - } - } - - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_is_static_memory(WOLFSSL* ssl, WOLFSSL_MEM_CONN_STATS* mem_stats) -{ - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - WOLFSSL_ENTER("wolfSSL_is_static_memory"); - -#ifndef WOLFSSL_STATIC_MEMORY_LEAN - /* fill out statistics if wanted and WOLFMEM_TRACK_STATS flag */ - if (mem_stats != NULL && ssl->heap != NULL) { - WOLFSSL_HEAP_HINT* hint = ((WOLFSSL_HEAP_HINT*)(ssl->heap)); - WOLFSSL_HEAP* heap = hint->memory; - if (heap->flag & WOLFMEM_TRACK_STATS && hint->stats != NULL) { - XMEMCPY(mem_stats, hint->stats, sizeof(WOLFSSL_MEM_CONN_STATS)); - } - } -#endif - - (void)mem_stats; - return (ssl->heap) ? 1 : 0; -} - - -int wolfSSL_CTX_is_static_memory(WOLFSSL_CTX* ctx, WOLFSSL_MEM_STATS* mem_stats) -{ - if (ctx == NULL) { - return BAD_FUNC_ARG; - } - WOLFSSL_ENTER("wolfSSL_CTX_is_static_memory"); - -#ifndef WOLFSSL_STATIC_MEMORY_LEAN - /* fill out statistics if wanted */ - if (mem_stats != NULL && ctx->heap != NULL) { - WOLFSSL_HEAP* heap = ((WOLFSSL_HEAP_HINT*)(ctx->heap))->memory; - if (wolfSSL_GetMemStats(heap, mem_stats) != 1) { - return MEMORY_E; - } - } -#endif - - (void)mem_stats; - return (ctx->heap) ? 1 : 0; -} - -#endif /* WOLFSSL_STATIC_MEMORY */ - -#ifndef NO_TLS -/* return max record layer size plaintext input size */ -int wolfSSL_GetMaxOutputSize(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_GetMaxOutputSize"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - if (ssl->options.handShakeState != HANDSHAKE_DONE) { - WOLFSSL_MSG("Handshake not complete yet"); - return BAD_FUNC_ARG; - } - - return min(OUTPUT_RECORD_SIZE, wolfssl_local_GetMaxPlaintextSize(ssl)); -} - - -/* return record layer size of plaintext input size */ -int wolfSSL_GetOutputSize(WOLFSSL* ssl, int inSz) -{ - int maxSize; - - WOLFSSL_ENTER("wolfSSL_GetOutputSize"); - - if (inSz < 0) - return BAD_FUNC_ARG; - - maxSize = wolfSSL_GetMaxOutputSize(ssl); - if (maxSize < 0) - return maxSize; /* error */ - if (inSz > maxSize) - return INPUT_SIZE_E; - - return wolfssl_local_GetRecordSize(ssl, inSz, 1); -} - - -#ifdef HAVE_ECC -int wolfSSL_CTX_SetMinEccKey_Sz(WOLFSSL_CTX* ctx, short keySz) -{ - short keySzBytes; - - WOLFSSL_ENTER("wolfSSL_CTX_SetMinEccKey_Sz"); - if (ctx == NULL || keySz < 0) { - WOLFSSL_MSG("Key size must be positive value or ctx was null"); - return BAD_FUNC_ARG; - } - - if (keySz % 8 == 0) { - keySzBytes = keySz / 8; - } - else { - keySzBytes = (keySz / 8) + 1; - } - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ctx->minEccKeySz > (keySzBytes)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ctx->minEccKeySz = keySzBytes; -#ifndef NO_CERTS - ctx->cm->minEccKeySz = keySzBytes; -#endif - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_SetMinEccKey_Sz(WOLFSSL* ssl, short keySz) -{ - short keySzBytes; - - WOLFSSL_ENTER("wolfSSL_SetMinEccKey_Sz"); - if (ssl == NULL || keySz < 0) { - WOLFSSL_MSG("Key size must be positive value or ctx was null"); - return BAD_FUNC_ARG; - } - - if (keySz % 8 == 0) { - keySzBytes = keySz / 8; - } - else { - keySzBytes = (keySz / 8) + 1; - } - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ssl->options.minEccKeySz > (keySzBytes)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ssl->options.minEccKeySz = keySzBytes; - return WOLFSSL_SUCCESS; -} - -#endif /* HAVE_ECC */ - -#ifndef NO_RSA -int wolfSSL_CTX_SetMinRsaKey_Sz(WOLFSSL_CTX* ctx, short keySz) -{ - if (ctx == NULL || keySz < 0 || keySz % 8 != 0) { - WOLFSSL_MSG("Key size must be divisible by 8 or ctx was null"); - return BAD_FUNC_ARG; - } - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ctx->minRsaKeySz > (keySz / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ctx->minRsaKeySz = keySz / 8; - ctx->cm->minRsaKeySz = keySz / 8; - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_SetMinRsaKey_Sz(WOLFSSL* ssl, short keySz) -{ - if (ssl == NULL || keySz < 0 || keySz % 8 != 0) { - WOLFSSL_MSG("Key size must be divisible by 8 or ssl was null"); - return BAD_FUNC_ARG; - } - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ssl->options.minRsaKeySz > (keySz / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ssl->options.minRsaKeySz = keySz / 8; - return WOLFSSL_SUCCESS; -} -#endif /* !NO_RSA */ - -#ifndef NO_DH - -#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ - !defined(HAVE_SELFTEST) -/* Enables or disables the session's DH key prime test. */ -int wolfSSL_SetEnableDhKeyTest(WOLFSSL* ssl, int enable) -{ - WOLFSSL_ENTER("wolfSSL_SetEnableDhKeyTest"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - if (!enable) - ssl->options.dhDoKeyTest = 0; - else - ssl->options.dhDoKeyTest = 1; - - WOLFSSL_LEAVE("wolfSSL_SetEnableDhKeyTest", WOLFSSL_SUCCESS); - return WOLFSSL_SUCCESS; -} -#endif - -int wolfSSL_CTX_SetMinDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz_bits) -{ - if (ctx == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) - return BAD_FUNC_ARG; - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ctx->minDhKeySz > (keySz_bits / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ctx->minDhKeySz = keySz_bits / 8; - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_SetMinDhKey_Sz(WOLFSSL* ssl, word16 keySz_bits) -{ - if (ssl == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) - return BAD_FUNC_ARG; - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ssl->options.minDhKeySz > (keySz_bits / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ssl->options.minDhKeySz = keySz_bits / 8; - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_CTX_SetMaxDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz_bits) -{ - if (ctx == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) - return BAD_FUNC_ARG; - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ctx->minDhKeySz > (keySz_bits / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ctx->maxDhKeySz = keySz_bits / 8; - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_SetMaxDhKey_Sz(WOLFSSL* ssl, word16 keySz_bits) -{ - if (ssl == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) - return BAD_FUNC_ARG; - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - if (ssl->options.minDhKeySz > (keySz_bits / 8)) { - return CRYPTO_POLICY_FORBIDDEN; - } - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - - ssl->options.maxDhKeySz = keySz_bits / 8; - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_GetDhKey_Sz(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - return (ssl->options.dhKeySz * 8); -} - -#endif /* !NO_DH */ - - -static int wolfSSL_write_internal(WOLFSSL* ssl, const void* data, size_t sz) -{ - int ret; - - WOLFSSL_ENTER("wolfSSL_write"); - - if (ssl == NULL || data == NULL) - return BAD_FUNC_ARG; - -#ifdef WOLFSSL_QUIC - if (WOLFSSL_IS_QUIC(ssl)) { - WOLFSSL_MSG("SSL_write() on QUIC not allowed"); - return BAD_FUNC_ARG; - } -#endif - -#ifdef HAVE_WRITE_DUP - { /* local variable scope */ - int dupErr = 0; /* local copy */ - - ret = 0; - - if (ssl->dupWrite && ssl->dupSide == READ_DUP_SIDE) { - WOLFSSL_MSG("Read dup side cannot write"); - return WRITE_DUP_WRITE_E; - } - if (ssl->dupWrite) { - if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0) { - return BAD_MUTEX_E; - } - dupErr = ssl->dupWrite->dupErr; - ret = wc_UnLockMutex(&ssl->dupWrite->dupMutex); - } - - if (ret != 0) { - ssl->error = ret; /* high priority fatal error */ - return WOLFSSL_FATAL_ERROR; - } - if (dupErr != 0) { - WOLFSSL_MSG("Write dup error from other side"); - ssl->error = dupErr; - return WOLFSSL_FATAL_ERROR; - } - } -#endif - -#ifdef HAVE_ERRNO_H - errno = 0; -#endif - - #ifdef OPENSSL_EXTRA - if (ssl->CBIS != NULL) { - ssl->CBIS(ssl, WOLFSSL_CB_WRITE, WOLFSSL_SUCCESS); - ssl->cbmode = WOLFSSL_CB_WRITE; - } - #endif - ret = SendData(ssl, data, sz); - - WOLFSSL_LEAVE("wolfSSL_write", ret); - - if (ret < 0) - return WOLFSSL_FATAL_ERROR; - else - return ret; -} - -WOLFSSL_ABI -int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) -{ - WOLFSSL_ENTER("wolfSSL_write"); - - if (sz < 0) - return BAD_FUNC_ARG; - - return wolfSSL_write_internal(ssl, data, (size_t)sz); -} - -int wolfSSL_inject(WOLFSSL* ssl, const void* data, int sz) -{ - int maxLength; - int usedLength; - - WOLFSSL_ENTER("wolfSSL_inject"); - - if (ssl == NULL || data == NULL || sz <= 0) - return BAD_FUNC_ARG; - - usedLength = (int)(ssl->buffers.inputBuffer.length - - ssl->buffers.inputBuffer.idx); - maxLength = (int)(ssl->buffers.inputBuffer.bufferSize - - (word32)usedLength); - - if (sz > maxLength) { - /* Need to make space */ - int ret; - if (ssl->buffers.clearOutputBuffer.length > 0) { - /* clearOutputBuffer points into so reallocating inputBuffer will - * invalidate clearOutputBuffer and lose app data */ - WOLFSSL_MSG("Can't inject while there is application data to read"); - return APP_DATA_READY; - } - ret = GrowInputBuffer(ssl, sz, usedLength); - if (ret < 0) - return ret; - } - - XMEMCPY(ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, - data, sz); - ssl->buffers.inputBuffer.length += sz; - - return WOLFSSL_SUCCESS; -} - - -int wolfSSL_write_ex(WOLFSSL* ssl, const void* data, size_t sz, size_t* wr) -{ - int ret; - - if (wr != NULL) { - *wr = 0; - } - - ret = wolfSSL_write_internal(ssl, data, sz); - if (ret >= 0) { - if (wr != NULL) { - *wr = (size_t)ret; - } - - /* handle partial write cases, if not set then a partial write is - * considered a failure case, or if set and ret is 0 then is a fail */ - if (ret == 0 && ssl->options.partialWrite) { - ret = 0; - } - else if ((size_t)ret < sz && !ssl->options.partialWrite) { - ret = 0; - } - else { - /* wrote out all application data, or wrote out 1 byte or more with - * partial write flag set */ - ret = 1; - } - } - else { - ret = 0; - } - - return ret; -} - - -static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, size_t sz, int peek) -{ - int ret; - - WOLFSSL_ENTER("wolfSSL_read_internal"); - - if (ssl == NULL || data == NULL) - return BAD_FUNC_ARG; - -#ifdef WOLFSSL_QUIC - if (WOLFSSL_IS_QUIC(ssl)) { - WOLFSSL_MSG("SSL_read() on QUIC not allowed"); - return BAD_FUNC_ARG; - } -#endif -#if defined(WOLFSSL_ERROR_CODE_OPENSSL) && defined(OPENSSL_EXTRA) - /* This additional logic is meant to simulate following openSSL behavior: - * After bidirectional SSL_shutdown complete, SSL_read returns 0 and - * SSL_get_error_code returns SSL_ERROR_ZERO_RETURN. - * This behavior is used to know the disconnect of the underlying - * transport layer. - * - * In this logic, CBIORecv is called with a read size of 0 to check the - * transport layer status. It also returns WOLFSSL_FAILURE so that - * SSL_read does not return a positive number on failure. - */ - - /* make sure bidirectional TLS shutdown completes */ - if (ssl->error == WOLFSSL_ERROR_SYSCALL || ssl->options.shutdownDone) { - /* ask the underlying transport the connection is closed */ - if (ssl->CBIORecv(ssl, (char*)data, 0, ssl->IOCB_ReadCtx) - == WC_NO_ERR_TRACE(WOLFSSL_CBIO_ERR_CONN_CLOSE)) - { - ssl->options.isClosed = 1; - ssl->error = WOLFSSL_ERROR_ZERO_RETURN; - } - return WOLFSSL_FAILURE; - } -#endif - -#ifdef HAVE_WRITE_DUP - if (ssl->dupWrite && ssl->dupSide == WRITE_DUP_SIDE) { - WOLFSSL_MSG("Write dup side cannot read"); - return WRITE_DUP_READ_E; - } -#endif - -#ifdef HAVE_ERRNO_H - errno = 0; -#endif - - ret = ReceiveData(ssl, (byte*)data, sz, peek); - -#ifdef HAVE_WRITE_DUP - if (ssl->dupWrite) { - if (ssl->error != 0 && ssl->error != WC_NO_ERR_TRACE(WANT_READ) - #ifdef WOLFSSL_ASYNC_CRYPT - && ssl->error != WC_NO_ERR_TRACE(WC_PENDING_E) - #endif - ) { - int notifyErr; - - WOLFSSL_MSG("Notifying write side of fatal read error"); - notifyErr = NotifyWriteSide(ssl, ssl->error); - if (notifyErr < 0) { - ret = ssl->error = notifyErr; - } - } - } -#endif - - WOLFSSL_LEAVE("wolfSSL_read_internal", ret); - - if (ret < 0) - return WOLFSSL_FATAL_ERROR; - else - return ret; -} - - -int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz) -{ - WOLFSSL_ENTER("wolfSSL_peek"); - - if (sz < 0) - return BAD_FUNC_ARG; - - return wolfSSL_read_internal(ssl, data, (size_t)sz, TRUE); -} - - -WOLFSSL_ABI -int wolfSSL_read(WOLFSSL* ssl, void* data, int sz) -{ - WOLFSSL_ENTER("wolfSSL_read"); - - if (sz < 0) - return BAD_FUNC_ARG; - - #ifdef OPENSSL_EXTRA - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - if (ssl->CBIS != NULL) { - ssl->CBIS(ssl, WOLFSSL_CB_READ, WOLFSSL_SUCCESS); - ssl->cbmode = WOLFSSL_CB_READ; - } - #endif - return wolfSSL_read_internal(ssl, data, (size_t)sz, FALSE); -} - - -/* returns 0 on failure and 1 on read */ -int wolfSSL_read_ex(WOLFSSL* ssl, void* data, size_t sz, size_t* rd) -{ - int ret; - - #ifdef OPENSSL_EXTRA - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - if (ssl->CBIS != NULL) { - ssl->CBIS(ssl, WOLFSSL_CB_READ, WOLFSSL_SUCCESS); - ssl->cbmode = WOLFSSL_CB_READ; - } - #endif - ret = wolfSSL_read_internal(ssl, data, sz, FALSE); - - if (ret > 0 && rd != NULL) { - *rd = (size_t)ret; - } - - return ret > 0 ? 1 : 0; -} - -#ifdef WOLFSSL_MULTICAST - -int wolfSSL_mcast_read(WOLFSSL* ssl, word16* id, void* data, int sz) -{ - int ret = 0; - - WOLFSSL_ENTER("wolfSSL_mcast_read"); - - if ((ssl == NULL) || (sz < 0)) - return BAD_FUNC_ARG; - - ret = wolfSSL_read_internal(ssl, data, (size_t)sz, FALSE); - if (ssl->options.dtls && ssl->options.haveMcast && id != NULL) - *id = ssl->keys.curPeerId; - return ret; -} - -#endif /* WOLFSSL_MULTICAST */ -#endif /* !NO_TLS */ - -/* helpers to set the device id, WOLFSSL_SUCCESS on ok */ -WOLFSSL_ABI -int wolfSSL_SetDevId(WOLFSSL* ssl, int devId) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->devId = devId; - - return WOLFSSL_SUCCESS; -} - -WOLFSSL_ABI -int wolfSSL_CTX_SetDevId(WOLFSSL_CTX* ctx, int devId) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->devId = devId; - - return WOLFSSL_SUCCESS; -} - -/* helpers to get device id and heap */ -WOLFSSL_ABI -int wolfSSL_CTX_GetDevId(WOLFSSL_CTX* ctx, WOLFSSL* ssl) -{ - int devId = INVALID_DEVID; - if (ssl != NULL) - devId = ssl->devId; - if (ctx != NULL && devId == INVALID_DEVID) - devId = ctx->devId; - return devId; -} -void* wolfSSL_CTX_GetHeap(WOLFSSL_CTX* ctx, WOLFSSL* ssl) -{ - void* heap = NULL; - if (ctx != NULL) - heap = ctx->heap; - else if (ssl != NULL) - heap = ssl->heap; - return heap; -} - - -#ifndef NO_TLS -#ifdef HAVE_SNI - -WOLFSSL_ABI -int wolfSSL_UseSNI(WOLFSSL* ssl, byte type, const void* data, word16 size) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseSNI(&ssl->extensions, type, data, size, ssl->heap); -} - - -WOLFSSL_ABI -int wolfSSL_CTX_UseSNI(WOLFSSL_CTX* ctx, byte type, const void* data, - word16 size) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseSNI(&ctx->extensions, type, data, size, ctx->heap); -} - -#ifndef NO_WOLFSSL_SERVER - -void wolfSSL_SNI_SetOptions(WOLFSSL* ssl, byte type, byte options) -{ - if (ssl && ssl->extensions) - TLSX_SNI_SetOptions(ssl->extensions, type, options); -} - - -void wolfSSL_CTX_SNI_SetOptions(WOLFSSL_CTX* ctx, byte type, byte options) -{ - if (ctx && ctx->extensions) - TLSX_SNI_SetOptions(ctx->extensions, type, options); -} - - -byte wolfSSL_SNI_Status(WOLFSSL* ssl, byte type) -{ - return TLSX_SNI_Status(ssl ? ssl->extensions : NULL, type); -} - - -word16 wolfSSL_SNI_GetRequest(WOLFSSL* ssl, byte type, void** data) -{ - if (data) - *data = NULL; - - if (ssl && ssl->extensions) - return TLSX_SNI_GetRequest(ssl->extensions, type, data, 0); - - return 0; -} - - -int wolfSSL_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, - byte type, byte* sni, word32* inOutSz) -{ - if (clientHello && helloSz > 0 && sni && inOutSz && *inOutSz > 0) - return TLSX_SNI_GetFromBuffer(clientHello, helloSz, type, sni, inOutSz); - - return BAD_FUNC_ARG; -} - -#endif /* !NO_WOLFSSL_SERVER */ - -#endif /* HAVE_SNI */ - - -#ifdef HAVE_TRUSTED_CA - -int wolfSSL_UseTrustedCA(WOLFSSL* ssl, byte type, - const byte* certId, word32 certIdSz) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - if (type == WOLFSSL_TRUSTED_CA_PRE_AGREED) { - if (certId != NULL || certIdSz != 0) - return BAD_FUNC_ARG; - } - else if (type == WOLFSSL_TRUSTED_CA_X509_NAME) { - if (certId == NULL || certIdSz == 0) - return BAD_FUNC_ARG; - } - #ifndef NO_SHA - else if (type == WOLFSSL_TRUSTED_CA_KEY_SHA1 || - type == WOLFSSL_TRUSTED_CA_CERT_SHA1) { - if (certId == NULL || certIdSz != WC_SHA_DIGEST_SIZE) - return BAD_FUNC_ARG; - } - #endif - else - return BAD_FUNC_ARG; - - return TLSX_UseTrustedCA(&ssl->extensions, - type, certId, certIdSz, ssl->heap); -} - -#endif /* HAVE_TRUSTED_CA */ - - -#ifdef HAVE_MAX_FRAGMENT -#ifndef NO_WOLFSSL_CLIENT - -int wolfSSL_UseMaxFragment(WOLFSSL* ssl, byte mfl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - -#ifdef WOLFSSL_ALLOW_MAX_FRAGMENT_ADJUST - /* The following is a non-standard way to reconfigure the max packet size - post-handshake for wolfSSL_write/wolfSSL_read */ - if (ssl->options.handShakeState == HANDSHAKE_DONE) { - switch (mfl) { - case WOLFSSL_MFL_2_8 : ssl->max_fragment = 256; break; - case WOLFSSL_MFL_2_9 : ssl->max_fragment = 512; break; - case WOLFSSL_MFL_2_10: ssl->max_fragment = 1024; break; - case WOLFSSL_MFL_2_11: ssl->max_fragment = 2048; break; - case WOLFSSL_MFL_2_12: ssl->max_fragment = 4096; break; - case WOLFSSL_MFL_2_13: ssl->max_fragment = 8192; break; - default: ssl->max_fragment = MAX_RECORD_SIZE; break; - } - return WOLFSSL_SUCCESS; - } -#endif /* WOLFSSL_MAX_FRAGMENT_ADJUST */ - - /* This call sets the max fragment TLS extension, which gets sent to server. - The server_hello response is what sets the `ssl->max_fragment` in - TLSX_MFL_Parse */ - return TLSX_UseMaxFragment(&ssl->extensions, mfl, ssl->heap); -} - - -int wolfSSL_CTX_UseMaxFragment(WOLFSSL_CTX* ctx, byte mfl) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseMaxFragment(&ctx->extensions, mfl, ctx->heap); -} - -#endif /* NO_WOLFSSL_CLIENT */ -#endif /* HAVE_MAX_FRAGMENT */ - -#ifdef HAVE_TRUNCATED_HMAC -#ifndef NO_WOLFSSL_CLIENT - -int wolfSSL_UseTruncatedHMAC(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap); -} - - -int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseTruncatedHMAC(&ctx->extensions, ctx->heap); -} - -#endif /* NO_WOLFSSL_CLIENT */ -#endif /* HAVE_TRUNCATED_HMAC */ - -#ifndef NO_WOLFSSL_CLIENT -#ifdef HAVE_CERTIFICATE_STATUS_REQUEST - -int wolfSSL_UseOCSPStapling(WOLFSSL* ssl, byte status_type, byte options) -{ - WOLFSSL_ENTER("wolfSSL_UseOCSPStapling"); - - if (ssl == NULL || ssl->options.side != WOLFSSL_CLIENT_END) - return BAD_FUNC_ARG; - - return TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type, - options, NULL, ssl->heap, ssl->devId); -} - - -int wolfSSL_CTX_UseOCSPStapling(WOLFSSL_CTX* ctx, byte status_type, - byte options) -{ - WOLFSSL_ENTER("wolfSSL_CTX_UseOCSPStapling"); - - if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END) - return BAD_FUNC_ARG; - - return TLSX_UseCertificateStatusRequest(&ctx->extensions, status_type, - options, NULL, ctx->heap, ctx->devId); -} - -#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ - -#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 - -int wolfSSL_UseOCSPStaplingV2(WOLFSSL* ssl, byte status_type, byte options) -{ - if (ssl == NULL || ssl->options.side != WOLFSSL_CLIENT_END) - return BAD_FUNC_ARG; - - return TLSX_UseCertificateStatusRequestV2(&ssl->extensions, status_type, - options, ssl->heap, ssl->devId); -} - - -int wolfSSL_CTX_UseOCSPStaplingV2(WOLFSSL_CTX* ctx, byte status_type, - byte options) -{ - if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END) - return BAD_FUNC_ARG; - - return TLSX_UseCertificateStatusRequestV2(&ctx->extensions, status_type, - options, ctx->heap, ctx->devId); -} - -#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ -#endif /* !NO_WOLFSSL_CLIENT */ - -/* Elliptic Curves */ -#if defined(HAVE_SUPPORTED_CURVES) - -static int isValidCurveGroup(word16 name) -{ - switch (name) { - case WOLFSSL_ECC_SECP160K1: - case WOLFSSL_ECC_SECP160R1: - case WOLFSSL_ECC_SECP160R2: - case WOLFSSL_ECC_SECP192K1: - case WOLFSSL_ECC_SECP192R1: - case WOLFSSL_ECC_SECP224K1: - case WOLFSSL_ECC_SECP224R1: - case WOLFSSL_ECC_SECP256K1: - case WOLFSSL_ECC_SECP256R1: - case WOLFSSL_ECC_SECP384R1: - case WOLFSSL_ECC_SECP521R1: - case WOLFSSL_ECC_BRAINPOOLP256R1: - case WOLFSSL_ECC_BRAINPOOLP384R1: - case WOLFSSL_ECC_BRAINPOOLP512R1: - case WOLFSSL_ECC_SM2P256V1: - case WOLFSSL_ECC_X25519: - case WOLFSSL_ECC_X448: - case WOLFSSL_ECC_BRAINPOOLP256R1TLS13: - case WOLFSSL_ECC_BRAINPOOLP384R1TLS13: - case WOLFSSL_ECC_BRAINPOOLP512R1TLS13: - - case WOLFSSL_FFDHE_2048: - case WOLFSSL_FFDHE_3072: - case WOLFSSL_FFDHE_4096: - case WOLFSSL_FFDHE_6144: - case WOLFSSL_FFDHE_8192: - -#ifdef WOLFSSL_HAVE_MLKEM -#ifndef WOLFSSL_NO_ML_KEM - case WOLFSSL_ML_KEM_512: - case WOLFSSL_ML_KEM_768: - case WOLFSSL_ML_KEM_1024: - #if defined(WOLFSSL_WC_MLKEM) || defined(HAVE_LIBOQS) - case WOLFSSL_SECP256R1MLKEM512: - case WOLFSSL_SECP384R1MLKEM768: - case WOLFSSL_SECP521R1MLKEM1024: - case WOLFSSL_SECP384R1MLKEM1024: - case WOLFSSL_X25519MLKEM512: - case WOLFSSL_X448MLKEM768: - case WOLFSSL_X25519MLKEM768: - case WOLFSSL_SECP256R1MLKEM768: - #endif -#endif /* !WOLFSSL_NO_ML_KEM */ -#ifdef WOLFSSL_MLKEM_KYBER - case WOLFSSL_KYBER_LEVEL1: - case WOLFSSL_KYBER_LEVEL3: - case WOLFSSL_KYBER_LEVEL5: - #if defined(WOLFSSL_WC_MLKEM) || defined(HAVE_LIBOQS) - case WOLFSSL_P256_KYBER_LEVEL1: - case WOLFSSL_P384_KYBER_LEVEL3: - case WOLFSSL_P521_KYBER_LEVEL5: - case WOLFSSL_X25519_KYBER_LEVEL1: - case WOLFSSL_X448_KYBER_LEVEL3: - case WOLFSSL_X25519_KYBER_LEVEL3: - case WOLFSSL_P256_KYBER_LEVEL3: - #endif -#endif /* WOLFSSL_MLKEM_KYBER */ -#endif - return 1; - - default: - return 0; - } -} - -int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name) -{ - if (ssl == NULL || !isValidCurveGroup(name)) - return BAD_FUNC_ARG; - - ssl->options.userCurves = 1; -#if defined(NO_TLS) - return WOLFSSL_FAILURE; -#else - return TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap); -#endif /* NO_TLS */ -} - - -int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name) -{ - if (ctx == NULL || !isValidCurveGroup(name)) - return BAD_FUNC_ARG; - - ctx->userCurves = 1; -#if defined(NO_TLS) - return WOLFSSL_FAILURE; -#else - return TLSX_UseSupportedCurve(&ctx->extensions, name, ctx->heap); -#endif /* NO_TLS */ -} - -#if defined(OPENSSL_EXTRA) -int wolfSSL_CTX_set1_groups(WOLFSSL_CTX* ctx, int* groups, - int count) -{ - int i; - int _groups[WOLFSSL_MAX_GROUP_COUNT]; - WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); - if (count == 0) { - WOLFSSL_MSG("Group count is zero"); - return WOLFSSL_FAILURE; - } - for (i = 0; i < count; i++) { - if (isValidCurveGroup((word16)groups[i])) { - _groups[i] = groups[i]; - } -#ifdef HAVE_ECC - else { - /* groups may be populated with curve NIDs */ - int oid = (int)nid2oid(groups[i], oidCurveType); - int name = (int)GetCurveByOID(oid); - if (name == 0) { - WOLFSSL_MSG("Invalid group name"); - return WOLFSSL_FAILURE; - } - _groups[i] = name; - } -#else - else { - WOLFSSL_MSG("Invalid group name"); - return WOLFSSL_FAILURE; - } -#endif - } - return wolfSSL_CTX_set_groups(ctx, _groups, count) == WOLFSSL_SUCCESS ? - WOLFSSL_SUCCESS : WOLFSSL_FAILURE; -} - -int wolfSSL_set1_groups(WOLFSSL* ssl, int* groups, int count) -{ - int i; - int _groups[WOLFSSL_MAX_GROUP_COUNT]; - WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); - if (count == 0) { - WOLFSSL_MSG("Group count is zero"); - return WOLFSSL_FAILURE; - } - for (i = 0; i < count; i++) { - if (isValidCurveGroup((word16)groups[i])) { - _groups[i] = groups[i]; - } -#ifdef HAVE_ECC - else { - /* groups may be populated with curve NIDs */ - int oid = (int)nid2oid(groups[i], oidCurveType); - int name = (int)GetCurveByOID(oid); - if (name == 0) { - WOLFSSL_MSG("Invalid group name"); - return WOLFSSL_FAILURE; - } - _groups[i] = name; - } -#else - else { - WOLFSSL_MSG("Invalid group name"); - return WOLFSSL_FAILURE; - } -#endif - } - return wolfSSL_set_groups(ssl, _groups, count) == WOLFSSL_SUCCESS ? - WOLFSSL_SUCCESS : WOLFSSL_FAILURE; -} -#endif /* OPENSSL_EXTRA */ -#endif /* HAVE_SUPPORTED_CURVES */ - -/* Application-Layer Protocol Negotiation */ -#ifdef HAVE_ALPN - -WOLFSSL_ABI -int wolfSSL_UseALPN(WOLFSSL* ssl, char *protocol_name_list, - word32 protocol_name_listSz, byte options) -{ - char *list, *ptr = NULL, **token; - word16 len; - int idx = 0; - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - - WOLFSSL_ENTER("wolfSSL_UseALPN"); - - if (ssl == NULL || protocol_name_list == NULL) - return BAD_FUNC_ARG; - - if (protocol_name_listSz > (WOLFSSL_MAX_ALPN_NUMBER * - WOLFSSL_MAX_ALPN_PROTO_NAME_LEN + - WOLFSSL_MAX_ALPN_NUMBER)) { - WOLFSSL_MSG("Invalid arguments, protocol name list too long"); - return BAD_FUNC_ARG; - } - - if (!(options & WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) && - !(options & WOLFSSL_ALPN_FAILED_ON_MISMATCH)) { - WOLFSSL_MSG("Invalid arguments, options not supported"); - return BAD_FUNC_ARG; - } - - - list = (char *)XMALLOC(protocol_name_listSz+1, ssl->heap, - DYNAMIC_TYPE_ALPN); - if (list == NULL) { - WOLFSSL_MSG("Memory failure"); - return MEMORY_ERROR; - } - - token = (char **)XMALLOC(sizeof(char *) * (WOLFSSL_MAX_ALPN_NUMBER+1), - ssl->heap, DYNAMIC_TYPE_ALPN); - if (token == NULL) { - XFREE(list, ssl->heap, DYNAMIC_TYPE_ALPN); - WOLFSSL_MSG("Memory failure"); - return MEMORY_ERROR; - } - XMEMSET(token, 0, sizeof(char *) * (WOLFSSL_MAX_ALPN_NUMBER+1)); - - XSTRNCPY(list, protocol_name_list, protocol_name_listSz); - list[protocol_name_listSz] = '\0'; - - /* read all protocol name from the list */ - token[idx] = XSTRTOK(list, ",", &ptr); - while (idx < WOLFSSL_MAX_ALPN_NUMBER && token[idx] != NULL) - token[++idx] = XSTRTOK(NULL, ",", &ptr); - - /* add protocol name list in the TLS extension in reverse order */ - while ((idx--) > 0) { - len = (word16)XSTRLEN(token[idx]); - - ret = TLSX_UseALPN(&ssl->extensions, token[idx], len, options, - ssl->heap); - if (ret != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("TLSX_UseALPN failure"); - break; - } - } - - XFREE(token, ssl->heap, DYNAMIC_TYPE_ALPN); - XFREE(list, ssl->heap, DYNAMIC_TYPE_ALPN); - - return ret; -} - -int wolfSSL_ALPN_GetProtocol(WOLFSSL* ssl, char **protocol_name, word16 *size) -{ - return TLSX_ALPN_GetRequest(ssl ? ssl->extensions : NULL, - (void **)protocol_name, size); -} - -int wolfSSL_ALPN_GetPeerProtocol(WOLFSSL* ssl, char **list, word16 *listSz) -{ - int i, len; - char *p; - byte *s; - - if (ssl == NULL || list == NULL || listSz == NULL) - return BAD_FUNC_ARG; - - if (ssl->alpn_peer_requested == NULL - || ssl->alpn_peer_requested_length == 0) - return BUFFER_ERROR; - - /* ssl->alpn_peer_requested are the original bytes sent in a ClientHello, - * formatted as (len-byte chars+)+. To turn n protocols into a - * comma-separated C string, one needs (n-1) commas and a final 0 byte - * which has the same length as the original. - * The returned length is the strlen() of the C string, so -1 of that. */ - *listSz = ssl->alpn_peer_requested_length-1; - *list = p = (char *)XMALLOC(ssl->alpn_peer_requested_length, ssl->heap, - DYNAMIC_TYPE_TLSX); - if (p == NULL) - return MEMORY_ERROR; - - for (i = 0, s = ssl->alpn_peer_requested; - i < ssl->alpn_peer_requested_length; - p += len, i += len) - { - if (i) - *p++ = ','; - len = s[i++]; - /* guard against bad length bytes. */ - if (i + len > ssl->alpn_peer_requested_length) { - XFREE(*list, ssl->heap, DYNAMIC_TYPE_TLSX); - *list = NULL; - return WOLFSSL_FAILURE; - } - XMEMCPY(p, s + i, (size_t)len); - } - *p = 0; - - return WOLFSSL_SUCCESS; -} - - -/* used to free memory allocated by wolfSSL_ALPN_GetPeerProtocol */ -int wolfSSL_ALPN_FreePeerProtocol(WOLFSSL* ssl, char **list) -{ - if (ssl == NULL) { - return BAD_FUNC_ARG; - } - - XFREE(*list, ssl->heap, DYNAMIC_TYPE_TLSX); - *list = NULL; - - return WOLFSSL_SUCCESS; -} - -#endif /* HAVE_ALPN */ - -/* Secure Renegotiation */ -#ifdef HAVE_SERVER_RENEGOTIATION_INFO - -/* user is forcing ability to use secure renegotiation, we discourage it */ -int wolfSSL_UseSecureRenegotiation(WOLFSSL* ssl) -{ - int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG); -#if defined(NO_TLS) - (void)ssl; -#else - if (ssl) - ret = TLSX_UseSecureRenegotiation(&ssl->extensions, ssl->heap); - else - ret = BAD_FUNC_ARG; - - if (ret == WOLFSSL_SUCCESS) { - TLSX* extension = TLSX_Find(ssl->extensions, TLSX_RENEGOTIATION_INFO); - - if (extension) - ssl->secure_renegotiation = (SecureRenegotiation*)extension->data; - } -#endif /* !NO_TLS */ - return ret; -} - -int wolfSSL_CTX_UseSecureRenegotiation(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->useSecureReneg = 1; - return WOLFSSL_SUCCESS; -} - -#ifdef HAVE_SECURE_RENEGOTIATION -/* do a secure renegotiation handshake, user forced, we discourage */ -static int _Rehandshake(WOLFSSL* ssl) -{ - int ret; - - if (ssl == NULL) - return BAD_FUNC_ARG; - - if (IsAtLeastTLSv1_3(ssl->version)) { - WOLFSSL_MSG("Secure Renegotiation not supported in TLS 1.3"); - return SECURE_RENEGOTIATION_E; - } - - if (ssl->secure_renegotiation == NULL) { - WOLFSSL_MSG("Secure Renegotiation not forced on by user"); - return SECURE_RENEGOTIATION_E; - } - - if (ssl->secure_renegotiation->enabled == 0) { - WOLFSSL_MSG("Secure Renegotiation not enabled at extension level"); - return SECURE_RENEGOTIATION_E; - } - -#ifdef WOLFSSL_DTLS - if (ssl->options.dtls && ssl->keys.dtls_epoch == 0xFFFF) { - WOLFSSL_MSG("Secure Renegotiation not allowed. Epoch would wrap"); - return SECURE_RENEGOTIATION_E; - } -#endif - - /* If the client started the renegotiation, the server will already - * have processed the client's hello. */ - if (ssl->options.side != WOLFSSL_SERVER_END || - ssl->options.acceptState != ACCEPT_FIRST_REPLY_DONE) { - - if (ssl->options.handShakeState != HANDSHAKE_DONE) { - if (!ssl->options.handShakeDone) { - WOLFSSL_MSG("Can't renegotiate until initial " - "handshake complete"); - return SECURE_RENEGOTIATION_E; - } - else { - WOLFSSL_MSG("Renegotiation already started. " - "Moving it forward."); - ret = wolfSSL_negotiate(ssl); - if (ret == WOLFSSL_SUCCESS) - ssl->secure_rene_count++; - return ret; - } - } - - /* reset handshake states */ - ssl->options.sendVerify = 0; - ssl->options.serverState = NULL_STATE; - ssl->options.clientState = NULL_STATE; - ssl->options.connectState = CONNECT_BEGIN; - ssl->options.acceptState = ACCEPT_BEGIN_RENEG; - ssl->options.handShakeState = NULL_STATE; - ssl->options.processReply = 0; /* TODO, move states in internal.h */ - - XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived)); - - ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED; - -#if !defined(NO_WOLFSSL_SERVER) && !defined(WOLFSSL_NO_TLS12) - if (ssl->options.side == WOLFSSL_SERVER_END) { - ret = SendHelloRequest(ssl); - if (ret != 0) { - ssl->error = ret; - return WOLFSSL_FATAL_ERROR; - } - } -#endif /* !NO_WOLFSSL_SERVER && !WOLFSSL_NO_TLS12 */ - - ret = InitHandshakeHashes(ssl); - if (ret != 0) { - ssl->error = ret; - return WOLFSSL_FATAL_ERROR; - } - } - ret = wolfSSL_negotiate(ssl); - if (ret == WOLFSSL_SUCCESS) - ssl->secure_rene_count++; - return ret; -} - - -/* do a secure renegotiation handshake, user forced, we discourage */ -int wolfSSL_Rehandshake(WOLFSSL* ssl) -{ - int ret; - WOLFSSL_ENTER("wolfSSL_Rehandshake"); - - if (ssl == NULL) - return WOLFSSL_FAILURE; - -#ifdef HAVE_SESSION_TICKET - ret = WOLFSSL_SUCCESS; -#endif - - if (ssl->options.side == WOLFSSL_SERVER_END) { - /* Reset option to send certificate verify. */ - ssl->options.sendVerify = 0; - /* Reset resuming flag to do full secure handshake. */ - ssl->options.resuming = 0; - } - else { - /* Reset resuming flag to do full secure handshake. */ - ssl->options.resuming = 0; - #if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_CLIENT) - /* Clearing the ticket. */ - ret = wolfSSL_UseSessionTicket(ssl); - #endif - } - /* CLIENT/SERVER: Reset peer authentication for full secure handshake. */ - ssl->options.peerAuthGood = 0; - -#ifdef HAVE_SESSION_TICKET - if (ret == WOLFSSL_SUCCESS) -#endif - ret = _Rehandshake(ssl); - - return ret; -} - - -#ifndef NO_WOLFSSL_CLIENT - -/* do a secure resumption handshake, user forced, we discourage */ -int wolfSSL_SecureResume(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_SecureResume"); + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); if (ssl == NULL) - return BAD_FUNC_ARG; - - if (ssl->options.side == WOLFSSL_SERVER_END) { - ssl->error = SIDE_ERROR; - return WOLFSSL_FATAL_ERROR; - } - - return _Rehandshake(ssl); -} - -#endif /* NO_WOLFSSL_CLIENT */ - -#endif /* HAVE_SECURE_RENEGOTIATION */ - -long wolfSSL_SSL_get_secure_renegotiation_support(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_SSL_get_secure_renegotiation_support"); - - if (!ssl || !ssl->secure_renegotiation) return WOLFSSL_FAILURE; - return ssl->secure_renegotiation->enabled; -} - -#endif /* HAVE_SECURE_RENEGOTIATION_INFO */ - -#if !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \ - defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK) -WOLFSSL_API int wolfSSL_get_scr_check_enabled(const WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_get_scr_check_enabled"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - return ssl->scr_check_enabled; -} - -WOLFSSL_API int wolfSSL_set_scr_check_enabled(WOLFSSL* ssl, byte enabled) -{ - WOLFSSL_ENTER("wolfSSL_set_scr_check_enabled"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->scr_check_enabled = !!enabled; - return WOLFSSL_SUCCESS; -} -#endif - -#if defined(HAVE_SESSION_TICKET) -/* Session Ticket */ - -#if !defined(NO_WOLFSSL_SERVER) -int wolfSSL_CTX_NoTicketTLSv12(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->noTicketTls12 = 1; - - return WOLFSSL_SUCCESS; -} - -int wolfSSL_NoTicketTLSv12(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->options.noTicketTls12 = 1; - - return WOLFSSL_SUCCESS; -} - -/* WOLFSSL_SUCCESS on ok */ -int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx, SessionTicketEncCb cb) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->ticketEncCb = cb; - - return WOLFSSL_SUCCESS; -} - -/* set hint interval, WOLFSSL_SUCCESS on ok */ -int wolfSSL_CTX_set_TicketHint(WOLFSSL_CTX* ctx, int hint) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->ticketHint = hint; - - return WOLFSSL_SUCCESS; -} - -/* set user context, WOLFSSL_SUCCESS on ok */ -int wolfSSL_CTX_set_TicketEncCtx(WOLFSSL_CTX* ctx, void* userCtx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - ctx->ticketEncCtx = userCtx; - - return WOLFSSL_SUCCESS; -} - -/* get user context - returns userCtx on success, NULL on failure */ -void* wolfSSL_CTX_get_TicketEncCtx(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return NULL; - - return ctx->ticketEncCtx; -} - -#ifdef WOLFSSL_TLS13 -/* set the maximum number of tickets to send - * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on fail - */ -int wolfSSL_CTX_set_num_tickets(WOLFSSL_CTX* ctx, size_t mxTickets) -{ - if (ctx == NULL) +#ifdef WOLFSSL_RW_THREADED + if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0) return WOLFSSL_FAILURE; - - ctx->maxTicketTls13 = (unsigned int)mxTickets; - return WOLFSSL_SUCCESS; -} - -/* get the maximum number of tickets to send - * return number of tickets set to be sent - */ -size_t wolfSSL_CTX_get_num_tickets(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return 0; - - return (size_t)ctx->maxTicketTls13; -} -#endif /* WOLFSSL_TLS13 */ -#endif /* !NO_WOLFSSL_SERVER */ - -#if !defined(NO_WOLFSSL_CLIENT) -int wolfSSL_UseSessionTicket(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap); -} - -int wolfSSL_CTX_UseSessionTicket(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseSessionTicket(&ctx->extensions, NULL, ctx->heap); -} - -int wolfSSL_get_SessionTicket(WOLFSSL* ssl, byte* buf, word32* bufSz) -{ - if (ssl == NULL || bufSz == NULL) - return BAD_FUNC_ARG; - - if (*bufSz == 0 && buf == NULL) { - *bufSz = ssl->session->ticketLen; - return LENGTH_ONLY_E; - } - - if (buf == NULL) - return BAD_FUNC_ARG; - - if (ssl->session->ticketLen <= *bufSz) { - XMEMCPY(buf, ssl->session->ticket, ssl->session->ticketLen); - *bufSz = ssl->session->ticketLen; - } - else - *bufSz = 0; - - return WOLFSSL_SUCCESS; -} - -int wolfSSL_set_SessionTicket(WOLFSSL* ssl, const byte* buf, - word32 bufSz) -{ - if (ssl == NULL || (buf == NULL && bufSz > 0)) - return BAD_FUNC_ARG; - - if (bufSz > 0) { - /* Ticket will fit into static ticket */ - if (bufSz <= SESSION_TICKET_LEN) { - if (ssl->session->ticketLenAlloc > 0) { - XFREE(ssl->session->ticket, ssl->session->heap, - DYNAMIC_TYPE_SESSION_TICK); - ssl->session->ticketLenAlloc = 0; - ssl->session->ticket = ssl->session->staticTicket; - } - } - else { /* Ticket requires dynamic ticket storage */ - /* is dyn buffer big enough */ - if (ssl->session->ticketLen < bufSz) { - if (ssl->session->ticketLenAlloc > 0) { - XFREE(ssl->session->ticket, ssl->session->heap, - DYNAMIC_TYPE_SESSION_TICK); - } - ssl->session->ticket = (byte*)XMALLOC(bufSz, ssl->session->heap, - DYNAMIC_TYPE_SESSION_TICK); - if(ssl->session->ticket == NULL) { - ssl->session->ticket = ssl->session->staticTicket; - ssl->session->ticketLenAlloc = 0; - return MEMORY_ERROR; - } - ssl->session->ticketLenAlloc = (word16)bufSz; - } +#endif + if (ssl->buffers.dtlsCtx.peer.sa != NULL && + ssl->buffers.dtlsCtx.peer.sz == peerSz && + sockAddrEqual((SOCKADDR_S*)ssl->buffers.dtlsCtx.peer.sa, + (XSOCKLENT)ssl->buffers.dtlsCtx.peer.sz, (SOCKADDR_S*)peer, + (XSOCKLENT)peerSz)) { + /* Already the current peer. */ + if (ssl->buffers.dtlsCtx.pendingPeer.sa != NULL) { + /* Clear any other pendingPeer */ + XFREE(ssl->buffers.dtlsCtx.pendingPeer.sa, ssl->heap, + DYNAMIC_TYPE_SOCKADDR); + ssl->buffers.dtlsCtx.pendingPeer.sa = NULL; + ssl->buffers.dtlsCtx.pendingPeer.sz = 0; + ssl->buffers.dtlsCtx.pendingPeer.bufSz = 0; } - XMEMCPY(ssl->session->ticket, buf, bufSz); + ret = WOLFSSL_SUCCESS; } - ssl->session->ticketLen = (word16)bufSz; - - return WOLFSSL_SUCCESS; + else { + ret = SockAddrSet(&ssl->buffers.dtlsCtx.pendingPeer, peer, peerSz, + ssl->heap); + } + if (ret == WOLFSSL_SUCCESS) + ssl->buffers.dtlsCtx.processingPendingRecord = 0; +#ifdef WOLFSSL_RW_THREADED + if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) + ret = WOLFSSL_FAILURE; +#endif + return ret; +#else + (void)ssl; + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; +#endif } +#endif /* WOLFSSL_DTLS_CID && !WOLFSSL_NO_SOCK */ +int wolfSSL_dtls_get_peer(WOLFSSL* ssl, void* peer, unsigned int* peerSz) +{ +#ifdef WOLFSSL_DTLS + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + if (ssl == NULL) + return WOLFSSL_FAILURE; +#ifdef WOLFSSL_RW_THREADED + if (wc_LockRwLock_Rd(&ssl->buffers.dtlsCtx.peerLock) != 0) + return WOLFSSL_FAILURE; +#endif + if (peer != NULL && peerSz != NULL + && *peerSz >= ssl->buffers.dtlsCtx.peer.sz + && ssl->buffers.dtlsCtx.peer.sa != NULL) { + *peerSz = ssl->buffers.dtlsCtx.peer.sz; + XMEMCPY(peer, ssl->buffers.dtlsCtx.peer.sa, *peerSz); + ret = WOLFSSL_SUCCESS; + } +#ifdef WOLFSSL_RW_THREADED + if (wc_UnLockRwLock(&ssl->buffers.dtlsCtx.peerLock) != 0) + ret = WOLFSSL_FAILURE; +#endif + return ret; +#else + (void)ssl; + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; +#endif +} -int wolfSSL_set_SessionTicket_cb(WOLFSSL* ssl, - CallbackSessionTicket cb, void* ctx) +int wolfSSL_dtls_get0_peer(WOLFSSL* ssl, const void** peer, + unsigned int* peerSz) { +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_RW_THREADED) if (ssl == NULL) - return BAD_FUNC_ARG; + return WOLFSSL_FAILURE; - ssl->session_ticket_cb = cb; - ssl->session_ticket_ctx = ctx; + if (peer == NULL || peerSz == NULL) + return WOLFSSL_FAILURE; + *peer = ssl->buffers.dtlsCtx.peer.sa; + *peerSz = ssl->buffers.dtlsCtx.peer.sz; return WOLFSSL_SUCCESS; +#else + (void)ssl; + (void)peer; + (void)peerSz; + return WOLFSSL_NOT_IMPLEMENTED; +#endif } -#endif /* !NO_WOLFSSL_CLIENT */ - -#endif /* HAVE_SESSION_TICKET */ -#ifdef HAVE_EXTENDED_MASTER -#ifndef NO_WOLFSSL_CLIENT +#if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) -int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx) +int wolfSSL_CTX_dtls_set_sctp(WOLFSSL_CTX* ctx) { + WOLFSSL_ENTER("wolfSSL_CTX_dtls_set_sctp"); + if (ctx == NULL) return BAD_FUNC_ARG; - ctx->haveEMS = 0; - + ctx->dtlsSctp = 1; return WOLFSSL_SUCCESS; } -int wolfSSL_DisableExtendedMasterSecret(WOLFSSL* ssl) +int wolfSSL_dtls_set_sctp(WOLFSSL* ssl) { + WOLFSSL_ENTER("wolfSSL_dtls_set_sctp"); + if (ssl == NULL) return BAD_FUNC_ARG; - ssl->options.haveEMS = 0; - + ssl->options.dtlsSctp = 1; return WOLFSSL_SUCCESS; } -#endif -#endif - +#endif /* WOLFSSL_DTLS && WOLFSSL_SCTP */ -#ifndef WOLFSSL_LEANPSK +#if (defined(WOLFSSL_SCTP) || defined(WOLFSSL_DTLS_MTU)) && \ + defined(WOLFSSL_DTLS) -int wolfSSL_send(WOLFSSL* ssl, const void* data, int sz, int flags) +int wolfSSL_CTX_dtls_set_mtu(WOLFSSL_CTX* ctx, word16 newMtu) { - int ret; - int oldFlags; - - WOLFSSL_ENTER("wolfSSL_send"); - - if (ssl == NULL || data == NULL || sz < 0) + if (ctx == NULL || newMtu > MAX_RECORD_SIZE) return BAD_FUNC_ARG; - oldFlags = ssl->wflags; - - ssl->wflags = flags; - ret = wolfSSL_write(ssl, data, sz); - ssl->wflags = oldFlags; - - WOLFSSL_LEAVE("wolfSSL_send", ret); - - return ret; + ctx->dtlsMtuSz = newMtu; + return WOLFSSL_SUCCESS; } -int wolfSSL_recv(WOLFSSL* ssl, void* data, int sz, int flags) +int wolfSSL_dtls_set_mtu(WOLFSSL* ssl, word16 newMtu) { - int ret; - int oldFlags; - - WOLFSSL_ENTER("wolfSSL_recv"); - - if (ssl == NULL || data == NULL || sz < 0) + if (ssl == NULL) return BAD_FUNC_ARG; - oldFlags = ssl->rflags; - - ssl->rflags = flags; - ret = wolfSSL_read(ssl, data, sz); - ssl->rflags = oldFlags; - - WOLFSSL_LEAVE("wolfSSL_recv", ret); - - return ret; -} -#endif - -int wolfSSL_SendUserCanceled(WOLFSSL* ssl) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - WOLFSSL_ENTER("wolfSSL_recv"); - - if (ssl != NULL) { - ssl->error = SendAlert(ssl, alert_warning, user_canceled); - if (ssl->error < 0) { - WOLFSSL_ERROR(ssl->error); - } - else { - ret = wolfSSL_shutdown(ssl); - } + if (newMtu > MAX_RECORD_SIZE) { + ssl->error = BAD_FUNC_ARG; + return WOLFSSL_FAILURE; } - WOLFSSL_LEAVE("wolfSSL_SendUserCanceled", ret); - - return ret; + ssl->dtlsMtuSz = newMtu; + return WOLFSSL_SUCCESS; } -/* WOLFSSL_SUCCESS on ok */ -WOLFSSL_ABI -int wolfSSL_shutdown(WOLFSSL* ssl) +#ifdef OPENSSL_EXTRA +/* Maps to compatibility API SSL_set_mtu and is same as wolfSSL_dtls_set_mtu, + * but expects only success or failure returns. */ +int wolfSSL_set_mtu_compat(WOLFSSL* ssl, unsigned short mtu) { - int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); - WOLFSSL_ENTER("wolfSSL_shutdown"); - - if (ssl == NULL) - return WOLFSSL_FATAL_ERROR; - - if (ssl->options.quietShutdown) { - WOLFSSL_MSG("quiet shutdown, no close notify sent"); - ret = WOLFSSL_SUCCESS; - } - else { - - /* Try to flush the buffer first, it might contain the alert */ - if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE) && - ssl->buffers.outputBuffer.length > 0) { - ret = SendBuffered(ssl); - if (ret != 0) { - ssl->error = ret; - /* for error tracing */ - if (ret != WC_NO_ERR_TRACE(WANT_WRITE)) - WOLFSSL_ERROR(ret); - ret = WOLFSSL_FATAL_ERROR; - WOLFSSL_LEAVE("wolfSSL_shutdown", ret); - return ret; - } - - ssl->error = WOLFSSL_ERROR_NONE; - /* we succeeded in sending the alert now */ - if (ssl->options.sentNotify) { - /* just after we send the alert, if we didn't receive the alert - * from the other peer yet, return WOLFSSL_STHUDOWN_NOT_DONE */ - if (!ssl->options.closeNotify) { - ret = WOLFSSL_SHUTDOWN_NOT_DONE; - WOLFSSL_LEAVE("wolfSSL_shutdown", ret); - return ret; - } - else { - ssl->options.shutdownDone = 1; - ret = WOLFSSL_SUCCESS; - } - } - } - - /* try to send close notify, not an error if can't */ - if (!ssl->options.isClosed && !ssl->options.connReset && - !ssl->options.sentNotify) { - ssl->error = SendAlert(ssl, alert_warning, close_notify); - - /* the alert is now sent or sitting in the buffer, - * where will be sent eventually */ - if (ssl->error == 0 || ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) - ssl->options.sentNotify = 1; + if (wolfSSL_dtls_set_mtu(ssl, mtu) == WOLFSSL_SUCCESS) + return WOLFSSL_SUCCESS; + else + return WOLFSSL_FAILURE; +} +#endif /* OPENSSL_EXTRA */ - if (ssl->error < 0) { - WOLFSSL_ERROR(ssl->error); - return WOLFSSL_FATAL_ERROR; - } +#endif /* WOLFSSL_DTLS && (WOLFSSL_SCTP || WOLFSSL_DTLS_MTU) */ - if (ssl->options.closeNotify) { - ret = WOLFSSL_SUCCESS; - ssl->options.shutdownDone = 1; - } - else { - ret = WOLFSSL_SHUTDOWN_NOT_DONE; - WOLFSSL_LEAVE("wolfSSL_shutdown", ret); - return ret; - } - } +#ifdef WOLFSSL_SRTP -#ifdef WOLFSSL_SHUTDOWNONCE - if (ssl->options.isClosed || ssl->options.connReset) { - /* Shutdown has already occurred. - * Caller is free to ignore this error. */ - return SSL_SHUTDOWN_ALREADY_DONE_E; - } -#endif +static const WOLFSSL_SRTP_PROTECTION_PROFILE gSrtpProfiles[] = { + /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 80-bits + * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ + {"SRTP_AES128_CM_SHA1_80", SRTP_AES128_CM_SHA1_80, + (((128 + 112) * 2) / 8) }, + /* AES CCM 128, Salt:112-bits, Auth HMAC-SHA1 Tag: 32-bits + * (master_key:128bits + master_salt:112bits) * 2 = 480 bits (60) */ + {"SRTP_AES128_CM_SHA1_32", SRTP_AES128_CM_SHA1_32, + (((128 + 112) * 2) / 8) }, + /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 80-bits */ + {"SRTP_NULL_SHA1_80", SRTP_NULL_SHA1_80, ((112 * 2) / 8)}, + /* NULL Cipher, Salt:112-bits, Auth HMAC-SHA1 Tag 32-bits */ + {"SRTP_NULL_SHA1_32", SRTP_NULL_SHA1_32, ((112 * 2) / 8)}, + /* AES GCM 128, Salt: 96-bits, Auth GCM Tag 128-bits + * (master_key:128bits + master_salt:96bits) * 2 = 448 bits (56) */ + {"SRTP_AEAD_AES_128_GCM", SRTP_AEAD_AES_128_GCM, (((128 + 96) * 2) / 8) }, + /* AES GCM 256, Salt: 96-bits, Auth GCM Tag 128-bits + * (master_key:256bits + master_salt:96bits) * 2 = 704 bits (88) */ + {"SRTP_AEAD_AES_256_GCM", SRTP_AEAD_AES_256_GCM, (((256 + 96) * 2) / 8) }, +}; - /* wolfSSL_shutdown called again for bidirectional shutdown */ - if (ssl->options.sentNotify && !ssl->options.closeNotify) { - ret = ProcessReply(ssl); - if ((ret == WC_NO_ERR_TRACE(ZERO_RETURN)) || - (ret == WC_NO_ERR_TRACE(SOCKET_ERROR_E))) { - /* simulate OpenSSL behavior */ - ssl->options.shutdownDone = 1; - /* Clear error */ - ssl->error = WOLFSSL_ERROR_NONE; - ret = WOLFSSL_SUCCESS; - } - else if (ret == WC_NO_ERR_TRACE(MEMORY_E)) { - ret = WOLFSSL_FATAL_ERROR; - } - else if (ret == WC_NO_ERR_TRACE(WANT_READ)) { - ssl->error = ret; - ret = WOLFSSL_FATAL_ERROR; - } - else if (ssl->error == WOLFSSL_ERROR_NONE) { - ret = WOLFSSL_SHUTDOWN_NOT_DONE; - } - else { - WOLFSSL_ERROR(ssl->error); - ret = WOLFSSL_FATAL_ERROR; +static const WOLFSSL_SRTP_PROTECTION_PROFILE* DtlsSrtpFindProfile( + const char* profile_str, word32 profile_str_len, unsigned long id) +{ + int i; + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; + for (i=0; + i<(int)(sizeof(gSrtpProfiles)/sizeof(WOLFSSL_SRTP_PROTECTION_PROFILE)); + i++) { + if (profile_str != NULL) { + word32 srtp_profile_len = (word32)XSTRLEN(gSrtpProfiles[i].name); + if (srtp_profile_len == profile_str_len && + XMEMCMP(gSrtpProfiles[i].name, profile_str, profile_str_len) + == 0) { + profile = &gSrtpProfiles[i]; + break; } } - } - -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) - /* reset WOLFSSL structure state for possible reuse */ - if (ret == WOLFSSL_SUCCESS) { - if (wolfSSL_clear(ssl) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("could not clear WOLFSSL"); - ret = WOLFSSL_FATAL_ERROR; + else if (id != 0 && gSrtpProfiles[i].id == id) { + profile = &gSrtpProfiles[i]; + break; } } -#endif - - WOLFSSL_LEAVE("wolfSSL_shutdown", ret); - - return ret; + return profile; } -#endif /* !NO_TLS */ -/* get current error state value */ -int wolfSSL_state(WOLFSSL* ssl) +/* profile_str: accepts ":" colon separated list of SRTP profiles */ +static int DtlsSrtpSelProfiles(word16* id, const char* profile_str) { - if (ssl == NULL) { - return BAD_FUNC_ARG; + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile; + const char *current, *next = NULL; + word32 length = 0, current_length; + + *id = 0; /* reset destination ID's */ + + if (profile_str == NULL) { + return WOLFSSL_FAILURE; } - return ssl->error; + /* loop on end of line or colon ":" */ + next = profile_str; + length = (word32)XSTRLEN(profile_str); + do { + current = next; + next = XSTRSTR(current, ":"); + if (next) { + current_length = (word32)(next - current); + ++next; /* ++ needed to skip ':' */ + } else { + current_length = (word32)XSTRLEN(current); + } + if (current_length < length) + length = current_length; + profile = DtlsSrtpFindProfile(current, current_length, 0); + if (profile != NULL) { + *id |= (1 << profile->id); /* selected bit based on ID */ + } + } while (next != NULL); + return WOLFSSL_SUCCESS; } - -WOLFSSL_ABI -int wolfSSL_get_error(WOLFSSL* ssl, int ret) +/** + * @brief Set the SRTP protection profiles for DTLS. + * + * @param ctx Pointer to the WOLFSSL_CTX structure representing the SSL/TLS + * context. + * @param profile_str A colon-separated string of SRTP profile names. + * @return 0 on success to match OpenSSL + * @return 1 on error to match OpenSSL + */ +int wolfSSL_CTX_set_tlsext_use_srtp(WOLFSSL_CTX* ctx, const char* profile_str) { - WOLFSSL_ENTER("wolfSSL_get_error"); - - if (ret > 0) - return WOLFSSL_ERROR_NONE; - if (ssl == NULL) - return BAD_FUNC_ARG; + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + if (ctx != NULL) { + ret = DtlsSrtpSelProfiles(&ctx->dtlsSrtpProfiles, profile_str); + } - WOLFSSL_LEAVE("wolfSSL_get_error", ssl->error); + if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { + ret = 1; + } else { + ret = 0; + } - /* make sure converted types are handled in SetErrorString() too */ - if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) - return WOLFSSL_ERROR_WANT_READ; /* convert to OpenSSL type */ - else if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) - return WOLFSSL_ERROR_WANT_WRITE; /* convert to OpenSSL type */ - else if (ssl->error == WC_NO_ERR_TRACE(ZERO_RETURN) || - ssl->options.shutdownDone) - return WOLFSSL_ERROR_ZERO_RETURN; /* convert to OpenSSL type */ -#ifdef OPENSSL_EXTRA - else if (ssl->error == WC_NO_ERR_TRACE(MATCH_SUITE_ERROR)) - return WOLFSSL_ERROR_SYSCALL; /* convert to OpenSSL type */ - else if (ssl->error == WC_NO_ERR_TRACE(SOCKET_PEER_CLOSED_E)) - return WOLFSSL_ERROR_SYSCALL; /* convert to OpenSSL type */ -#endif - return ssl->error; + return ret; } - -/* retrieve alert history, WOLFSSL_SUCCESS on ok */ -int wolfSSL_get_alert_history(WOLFSSL* ssl, WOLFSSL_ALERT_HISTORY *h) +/** + * @brief Set the SRTP protection profiles for DTLS. + * + * @param ssl Pointer to the WOLFSSL structure representing the SSL/TLS + * session. + * @param profile_str A colon-separated string of SRTP profile names. + * @return 0 on success to match OpenSSL + * @return 1 on error to match OpenSSL + */ +int wolfSSL_set_tlsext_use_srtp(WOLFSSL* ssl, const char* profile_str) { - if (ssl && h) { - *h = ssl->alert_history; + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + if (ssl != NULL) { + ret = DtlsSrtpSelProfiles(&ssl->dtlsSrtpProfiles, profile_str); } - return WOLFSSL_SUCCESS; + + if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { + ret = 1; + } else { + ret = 0; + } + + return ret; } -#ifdef OPENSSL_EXTRA -/* returns SSL_WRITING, SSL_READING or SSL_NOTHING */ -int wolfSSL_want(WOLFSSL* ssl) +const WOLFSSL_SRTP_PROTECTION_PROFILE* wolfSSL_get_selected_srtp_profile( + WOLFSSL* ssl) { - int rw_state = WOLFSSL_NOTHING; + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; if (ssl) { - if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) - rw_state = WOLFSSL_READING; - else if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) - rw_state = WOLFSSL_WRITING; + profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); } - return rw_state; + return profile; } -#endif - -/* return TRUE if current error is want read */ -int wolfSSL_want_read(WOLFSSL* ssl) +#ifndef NO_WOLFSSL_STUB +WOLF_STACK_OF(WOLFSSL_SRTP_PROTECTION_PROFILE)* wolfSSL_get_srtp_profiles( + WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_want_read"); - if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) - return 1; - - return 0; + /* Not yet implemented - should return list of available SRTP profiles + * ssl->dtlsSrtpProfiles */ + (void)ssl; + return NULL; } +#endif -/* return TRUE if current error is want write */ -int wolfSSL_want_write(WOLFSSL* ssl) +#define DTLS_SRTP_KEYING_MATERIAL_LABEL "EXTRACTOR-dtls_srtp" + +int wolfSSL_export_dtls_srtp_keying_material(WOLFSSL* ssl, + unsigned char* out, size_t* olen) { - WOLFSSL_ENTER("wolfSSL_want_write"); - if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) - return 1; + const WOLFSSL_SRTP_PROTECTION_PROFILE* profile = NULL; - return 0; -} + if (ssl == NULL || olen == NULL) { + return BAD_FUNC_ARG; + } -char* wolfSSL_ERR_error_string(unsigned long errNumber, char* data) -{ - WOLFSSL_ENTER("wolfSSL_ERR_error_string"); - if (data) { - SetErrorString((int)errNumber, data); - return data; + profile = DtlsSrtpFindProfile(NULL, 0, ssl->dtlsSrtpId); + if (profile == NULL) { + WOLFSSL_MSG("Not using DTLS SRTP"); + return EXT_MISSING; } - else { - static char tmp[WOLFSSL_MAX_ERROR_SZ] = {0}; - SetErrorString((int)errNumber, tmp); - return tmp; + if (out == NULL) { + *olen = (size_t)profile->kdfBits; + return WC_NO_ERR_TRACE(LENGTH_ONLY_E); + } + + if (*olen < (size_t)profile->kdfBits) { + return BUFFER_E; } + + return wolfSSL_export_keying_material(ssl, out, (size_t)profile->kdfBits, + DTLS_SRTP_KEYING_MATERIAL_LABEL, + XSTR_SIZEOF(DTLS_SRTP_KEYING_MATERIAL_LABEL), NULL, 0, 0); } +#endif /* WOLFSSL_SRTP */ + -void wolfSSL_ERR_error_string_n(unsigned long e, char* buf, unsigned long len) +#ifdef WOLFSSL_DTLS_DROP_STATS + +int wolfSSL_dtls_get_drop_stats(WOLFSSL* ssl, + word32* macDropCount, word32* replayDropCount) { - WOLFSSL_ENTER("wolfSSL_ERR_error_string_n"); - if (len >= WOLFSSL_MAX_ERROR_SZ) - wolfSSL_ERR_error_string(e, buf); - else { - WOLFSSL_MSG("Error buffer too short, truncating"); - if (len) { - char tmp[WOLFSSL_MAX_ERROR_SZ]; - wolfSSL_ERR_error_string(e, tmp); - XMEMCPY(buf, tmp, len-1); - buf[len-1] = '\0'; - } + int ret; + + WOLFSSL_ENTER("wolfSSL_dtls_get_drop_stats"); + + if (ssl == NULL) + ret = BAD_FUNC_ARG; + else { + ret = WOLFSSL_SUCCESS; + if (macDropCount != NULL) + *macDropCount = ssl->macDropCount; + if (replayDropCount != NULL) + *replayDropCount = ssl->replayDropCount; } + + WOLFSSL_LEAVE("wolfSSL_dtls_get_drop_stats", ret); + return ret; } +#endif /* WOLFSSL_DTLS_DROP_STATS */ -/* don't free temporary arrays at end of handshake */ -void wolfSSL_KeepArrays(WOLFSSL* ssl) -{ - if (ssl) - ssl->options.saveArrays = 1; -} +#if defined(WOLFSSL_MULTICAST) -/* user doesn't need temporary arrays anymore, Free */ -void wolfSSL_FreeArrays(WOLFSSL* ssl) +int wolfSSL_CTX_mcast_set_member_id(WOLFSSL_CTX* ctx, word16 id) { - if (ssl && ssl->options.handShakeState == HANDSHAKE_DONE) { - ssl->options.saveArrays = 0; - FreeArrays(ssl, 1); + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_mcast_set_member_id"); + + if (ctx == NULL || id > WOLFSSL_MAX_8BIT) + ret = BAD_FUNC_ARG; + + if (ret == 0) { + ctx->haveEMS = 0; + ctx->haveMcast = 1; + ctx->mcastID = (byte)id; +#ifndef WOLFSSL_USER_IO + ctx->CBIORecv = EmbedReceiveFromMcast; +#endif /* WOLFSSL_USER_IO */ + + ret = WOLFSSL_SUCCESS; } + WOLFSSL_LEAVE("wolfSSL_CTX_mcast_set_member_id", ret); + return ret; } -/* Set option to indicate that the resources are not to be freed after - * handshake. - * - * ssl The SSL/TLS object. - * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. - */ -int wolfSSL_KeepHandshakeResources(WOLFSSL* ssl) +int wolfSSL_mcast_get_max_peers(void) { - if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->options.keepResources = 1; - - return 0; + return WOLFSSL_MULTICAST_PEERS; } -/* Free the handshake resources after handshake. - * - * ssl The SSL/TLS object. - * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. - */ -int wolfSSL_FreeHandshakeResources(WOLFSSL* ssl) +#ifdef WOLFSSL_DTLS +static WC_INLINE word32 UpdateHighwaterMark(word32 cur, word32 first, + word32 second, word32 high) { - if (ssl == NULL) - return BAD_FUNC_ARG; + word32 newCur = 0; - FreeHandshakeResources(ssl); + if (cur < first) + newCur = first; + else if (cur < second) + newCur = second; + else if (cur < high) + newCur = high; - return 0; + return newCur; } +#endif /* WOLFSSL_DTLS */ -/* Use the client's order of preference when matching cipher suites. - * - * ssl The SSL/TLS context object. - * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. - */ -int wolfSSL_CTX_UseClientSuites(WOLFSSL_CTX* ctx) + +int wolfSSL_set_secret(WOLFSSL* ssl, word16 epoch, + const byte* preMasterSecret, word32 preMasterSz, + const byte* clientRandom, const byte* serverRandom, + const byte* suite) { - if (ctx == NULL) - return BAD_FUNC_ARG; + int ret = 0; - ctx->useClientOrder = 1; + WOLFSSL_ENTER("wolfSSL_set_secret"); - return 0; -} + if (ssl == NULL || preMasterSecret == NULL || + preMasterSz == 0 || preMasterSz > ENCRYPT_LEN || + clientRandom == NULL || serverRandom == NULL || suite == NULL) { -/* Use the client's order of preference when matching cipher suites. - * - * ssl The SSL/TLS object. - * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. - */ -int wolfSSL_UseClientSuites(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; + ret = BAD_FUNC_ARG; + } - ssl->options.useClientOrder = 1; + if (ret == 0 && ssl->arrays->preMasterSecret == NULL) { + ssl->arrays->preMasterSz = ENCRYPT_LEN; + ssl->arrays->preMasterSecret = (byte*)XMALLOC(ENCRYPT_LEN, ssl->heap, + DYNAMIC_TYPE_SECRET); + if (ssl->arrays->preMasterSecret == NULL) { + ret = MEMORY_E; + } + } - return 0; + if (ret == 0) { + XMEMCPY(ssl->arrays->preMasterSecret, preMasterSecret, preMasterSz); + XMEMSET(ssl->arrays->preMasterSecret + preMasterSz, 0, + ENCRYPT_LEN - preMasterSz); + ssl->arrays->preMasterSz = preMasterSz; + XMEMCPY(ssl->arrays->clientRandom, clientRandom, RAN_LEN); + XMEMCPY(ssl->arrays->serverRandom, serverRandom, RAN_LEN); + ssl->options.cipherSuite0 = suite[0]; + ssl->options.cipherSuite = suite[1]; + + ret = SetCipherSpecs(ssl); + } + + if (ret == 0) + ret = MakeTlsMasterSecret(ssl); + + if (ret == 0) { + ssl->keys.encryptionOn = 1; + ret = SetKeysSide(ssl, ENCRYPT_AND_DECRYPT_SIDE); + } + + if (ret == 0) { + if (ssl->options.dtls) { + #ifdef WOLFSSL_DTLS + WOLFSSL_DTLS_PEERSEQ* peerSeq; + int i; + + ssl->keys.dtls_epoch = epoch; + for (i = 0, peerSeq = ssl->keys.peerSeq; + i < WOLFSSL_DTLS_PEERSEQ_SZ; + i++, peerSeq++) { + + peerSeq->nextEpoch = epoch; + peerSeq->prevSeq_lo = peerSeq->nextSeq_lo; + peerSeq->prevSeq_hi = peerSeq->nextSeq_hi; + peerSeq->nextSeq_lo = 0; + peerSeq->nextSeq_hi = 0; + XMEMCPY(peerSeq->prevWindow, peerSeq->window, DTLS_SEQ_SZ); + XMEMSET(peerSeq->window, 0, DTLS_SEQ_SZ); + peerSeq->highwaterMark = UpdateHighwaterMark(0, + ssl->ctx->mcastFirstSeq, + ssl->ctx->mcastSecondSeq, + ssl->ctx->mcastMaxSeq); + } + #else + (void)epoch; + #endif + } + FreeHandshakeResources(ssl); + ret = WOLFSSL_SUCCESS; + } + else { + if (ssl) + ssl->error = ret; + ret = WOLFSSL_FATAL_ERROR; + } + WOLFSSL_LEAVE("wolfSSL_set_secret", ret); + return ret; } + #ifdef WOLFSSL_DTLS -const byte* wolfSSL_GetDtlsMacSecret(WOLFSSL* ssl, int verify, int epochOrder) + +int wolfSSL_mcast_peer_add(WOLFSSL* ssl, word16 peerId, int sub) { -#ifndef WOLFSSL_AEAD_ONLY - Keys* keys = NULL; + WOLFSSL_DTLS_PEERSEQ* p = NULL; + int ret = WOLFSSL_SUCCESS; + int i; - (void)epochOrder; + WOLFSSL_ENTER("wolfSSL_mcast_peer_add"); + if (ssl == NULL || peerId > WOLFSSL_MAX_8BIT) + return BAD_FUNC_ARG; - if (ssl == NULL) - return NULL; + if (!sub) { + /* Make sure it isn't already present, while keeping the first + * open spot. */ + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { + if (ssl->keys.peerSeq[i].peerId == INVALID_PEER_ID) + p = &ssl->keys.peerSeq[i]; + if (ssl->keys.peerSeq[i].peerId == peerId) { + WOLFSSL_MSG("Peer ID already in multicast peer list."); + p = NULL; + } + } -#ifdef HAVE_SECURE_RENEGOTIATION - switch (epochOrder) { - case PEER_ORDER: - if (IsDtlsMsgSCRKeys(ssl)) - keys = &ssl->secure_renegotiation->tmp_keys; - else - keys = &ssl->keys; - break; - case PREV_ORDER: - keys = &ssl->keys; - break; - case CUR_ORDER: - if (DtlsUseSCRKeys(ssl)) - keys = &ssl->secure_renegotiation->tmp_keys; - else - keys = &ssl->keys; - break; - default: - WOLFSSL_MSG("Unknown epoch order"); - return NULL; + if (p != NULL) { + XMEMSET(p, 0, sizeof(WOLFSSL_DTLS_PEERSEQ)); + p->peerId = peerId; + p->highwaterMark = UpdateHighwaterMark(0, + ssl->ctx->mcastFirstSeq, + ssl->ctx->mcastSecondSeq, + ssl->ctx->mcastMaxSeq); + } + else { + WOLFSSL_MSG("No room in peer list."); + ret = WOLFSSL_FATAL_ERROR; + } } -#else - keys = &ssl->keys; -#endif - - if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) || - (ssl->options.side == WOLFSSL_SERVER_END && verify) ) - return keys->client_write_MAC_secret; - else - return keys->server_write_MAC_secret; -#else - (void)ssl; - (void)verify; - (void)epochOrder; + else { + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { + if (ssl->keys.peerSeq[i].peerId == peerId) + p = &ssl->keys.peerSeq[i]; + } - return NULL; -#endif + if (p != NULL) { + p->peerId = INVALID_PEER_ID; + } + else { + WOLFSSL_MSG("Peer not found in list."); + } + } + + WOLFSSL_LEAVE("wolfSSL_mcast_peer_add", ret); + return ret; } -#endif /* WOLFSSL_DTLS */ -const byte* wolfSSL_GetMacSecret(WOLFSSL* ssl, int verify) -{ -#ifndef WOLFSSL_AEAD_ONLY - if (ssl == NULL) - return NULL; - if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) || - (ssl->options.side == WOLFSSL_SERVER_END && verify) ) - return ssl->keys.client_write_MAC_secret; - else - return ssl->keys.server_write_MAC_secret; -#else - (void)ssl; - (void)verify; +/* If peerId is in the list of peers and its last sequence number is non-zero, + * return 1, otherwise return 0. */ +int wolfSSL_mcast_peer_known(WOLFSSL* ssl, unsigned short peerId) +{ + int known = 0; + int i; - return NULL; -#endif -} + WOLFSSL_ENTER("wolfSSL_mcast_peer_known"); -int wolfSSL_GetSide(WOLFSSL* ssl) -{ - if (ssl) - return ssl->options.side; + if (ssl == NULL || peerId > WOLFSSL_MAX_8BIT) { + return BAD_FUNC_ARG; + } - return BAD_FUNC_ARG; -} + for (i = 0; i < WOLFSSL_DTLS_PEERSEQ_SZ; i++) { + if (ssl->keys.peerSeq[i].peerId == peerId) { + if (ssl->keys.peerSeq[i].nextSeq_hi || + ssl->keys.peerSeq[i].nextSeq_lo) { -#ifdef ATOMIC_USER + known = 1; + } + break; + } + } -void wolfSSL_CTX_SetMacEncryptCb(WOLFSSL_CTX* ctx, CallbackMacEncrypt cb) -{ - if (ctx) - ctx->MacEncryptCb = cb; + WOLFSSL_LEAVE("wolfSSL_mcast_peer_known", known); + return known; } -void wolfSSL_SetMacEncryptCtx(WOLFSSL* ssl, void *ctx) +int wolfSSL_CTX_mcast_set_highwater_cb(WOLFSSL_CTX* ctx, word32 maxSeq, + word32 first, word32 second, + CallbackMcastHighwater cb) { - if (ssl) - ssl->MacEncryptCtx = ctx; -} + if (ctx == NULL || (second && first > second) || + first > maxSeq || second > maxSeq || cb == NULL) { + return BAD_FUNC_ARG; + } -void* wolfSSL_GetMacEncryptCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->MacEncryptCtx; + ctx->mcastHwCb = cb; + ctx->mcastFirstSeq = first; + ctx->mcastSecondSeq = second; + ctx->mcastMaxSeq = maxSeq; - return NULL; + return WOLFSSL_SUCCESS; } -void wolfSSL_CTX_SetDecryptVerifyCb(WOLFSSL_CTX* ctx, CallbackDecryptVerify cb) +int wolfSSL_mcast_set_highwater_ctx(WOLFSSL* ssl, void* ctx) { - if (ctx) - ctx->DecryptVerifyCb = cb; -} + if (ssl == NULL || ctx == NULL) + return BAD_FUNC_ARG; + ssl->mcastHwCbCtx = ctx; -void wolfSSL_SetDecryptVerifyCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->DecryptVerifyCtx = ctx; + return WOLFSSL_SUCCESS; } +#endif /* WOLFSSL_DTLS */ -void* wolfSSL_GetDecryptVerifyCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->DecryptVerifyCtx; +#endif /* WOLFSSL_MULTICAST */ - return NULL; -} -#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) -/** - * Set the callback, against the context, that encrypts then MACs. - * - * ctx SSL/TLS context. - * cb Callback function to use with Encrypt-Then-MAC. - */ -void wolfSSL_CTX_SetEncryptMacCb(WOLFSSL_CTX* ctx, CallbackEncryptMac cb) -{ - if (ctx) - ctx->EncryptMacCb = cb; -} +#endif /* WOLFSSL_LEANPSK */ -/** - * Set the context to use with callback that encrypts then MACs. - * - * ssl SSL/TLS object. - * ctx Callback function's context. - */ -void wolfSSL_SetEncryptMacCtx(WOLFSSL* ssl, void *ctx) +#ifndef NO_TLS +/* return underlying connect or accept, WOLFSSL_SUCCESS on ok */ +int wolfSSL_negotiate(WOLFSSL* ssl) { - if (ssl) - ssl->EncryptMacCtx = ctx; -} + int err = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); -/** - * Get the context being used with callback that encrypts then MACs. - * - * ssl SSL/TLS object. - * returns callback function's context or NULL if SSL/TLS object is NULL. - */ -void* wolfSSL_GetEncryptMacCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->EncryptMacCtx; + WOLFSSL_ENTER("wolfSSL_negotiate"); - return NULL; -} + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; +#ifndef NO_WOLFSSL_SERVER + if (ssl->options.side == WOLFSSL_SERVER_END) { +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + err = wolfSSL_accept_TLSv13(ssl); + else +#endif + err = wolfSSL_accept(ssl); + } +#endif -/** - * Set the callback, against the context, that MAC verifies then decrypts. - * - * ctx SSL/TLS context. - * cb Callback function to use with Encrypt-Then-MAC. - */ -void wolfSSL_CTX_SetVerifyDecryptCb(WOLFSSL_CTX* ctx, CallbackVerifyDecrypt cb) -{ - if (ctx) - ctx->VerifyDecryptCb = cb; +#ifndef NO_WOLFSSL_CLIENT + if (ssl->options.side == WOLFSSL_CLIENT_END) { +#ifdef WOLFSSL_TLS13 + if (IsAtLeastTLSv1_3(ssl->version)) + err = wolfSSL_connect_TLSv13(ssl); + else +#endif + err = wolfSSL_connect(ssl); + } +#endif + + (void)ssl; + + WOLFSSL_LEAVE("wolfSSL_negotiate", err); + + return err; } +#endif /* !NO_TLS */ -/** - * Set the context to use with callback that MAC verifies then decrypts. - * - * ssl SSL/TLS object. - * ctx Callback function's context. - */ -void wolfSSL_SetVerifyDecryptCtx(WOLFSSL* ssl, void *ctx) +WOLFSSL_ABI +WC_RNG* wolfSSL_GetRNG(WOLFSSL* ssl) { - if (ssl) - ssl->VerifyDecryptCtx = ctx; + if (ssl) { + return ssl->rng; + } + + return NULL; } -/** - * Get the context being used with callback that MAC verifies then decrypts. - * - * ssl SSL/TLS object. - * returns callback function's context or NULL if SSL/TLS object is NULL. - */ -void* wolfSSL_GetVerifyDecryptCtx(WOLFSSL* ssl) + +#ifndef WOLFSSL_LEANPSK +/* object size based on build */ +int wolfSSL_GetObjectSize(void) { - if (ssl) - return ssl->VerifyDecryptCtx; +#ifdef SHOW_SIZES + printf("sizeof suites = %lu\n", (unsigned long)sizeof(Suites)); + printf("sizeof ciphers(2) = %lu\n", (unsigned long)sizeof(Ciphers)); +#ifndef NO_RC4 + printf("\tsizeof arc4 = %lu\n", (unsigned long)sizeof(Arc4)); +#endif + printf("\tsizeof aes = %lu\n", (unsigned long)sizeof(Aes)); +#ifndef NO_DES3 + printf("\tsizeof des3 = %lu\n", (unsigned long)sizeof(Des3)); +#endif +#ifdef HAVE_CHACHA + printf("\tsizeof chacha = %lu\n", (unsigned long)sizeof(ChaCha)); +#endif +#ifdef WOLFSSL_SM4 + printf("\tsizeof sm4 = %lu\n", (unsigned long)sizeof(Sm4)); +#endif + printf("sizeof cipher specs = %lu\n", (unsigned long) + sizeof(CipherSpecs)); + printf("sizeof keys = %lu\n", (unsigned long)sizeof(Keys)); + printf("sizeof Hashes(2) = %lu\n", (unsigned long)sizeof(Hashes)); +#ifndef NO_MD5 + printf("\tsizeof MD5 = %lu\n", (unsigned long)sizeof(wc_Md5)); +#endif +#ifndef NO_SHA + printf("\tsizeof SHA = %lu\n", (unsigned long)sizeof(wc_Sha)); +#endif +#ifdef WOLFSSL_SHA224 + printf("\tsizeof SHA224 = %lu\n", (unsigned long)sizeof(wc_Sha224)); +#endif +#ifndef NO_SHA256 + printf("\tsizeof SHA256 = %lu\n", (unsigned long)sizeof(wc_Sha256)); +#endif +#ifdef WOLFSSL_SHA384 + printf("\tsizeof SHA384 = %lu\n", (unsigned long)sizeof(wc_Sha384)); +#endif +#ifdef WOLFSSL_SHA384 + printf("\tsizeof SHA512 = %lu\n", (unsigned long)sizeof(wc_Sha512)); +#endif +#ifdef WOLFSSL_SM3 + printf("\tsizeof sm3 = %lu\n", (unsigned long)sizeof(Sm3)); +#endif + printf("sizeof Buffers = %lu\n", (unsigned long)sizeof(Buffers)); + printf("sizeof Options = %lu\n", (unsigned long)sizeof(Options)); + printf("sizeof Arrays = %lu\n", (unsigned long)sizeof(Arrays)); +#ifndef NO_RSA + printf("sizeof RsaKey = %lu\n", (unsigned long)sizeof(RsaKey)); +#endif +#ifdef HAVE_ECC + printf("sizeof ecc_key = %lu\n", (unsigned long)sizeof(ecc_key)); +#endif + printf("sizeof WOLFSSL_CIPHER = %lu\n", (unsigned long) + sizeof(WOLFSSL_CIPHER)); + printf("sizeof WOLFSSL_SESSION = %lu\n", (unsigned long) + sizeof(WOLFSSL_SESSION)); + printf("sizeof WOLFSSL = %lu\n", (unsigned long)sizeof(WOLFSSL)); + printf("sizeof WOLFSSL_CTX = %lu\n", (unsigned long) + sizeof(WOLFSSL_CTX)); +#endif - return NULL; + return sizeof(WOLFSSL); } -#endif /* HAVE_ENCRYPT_THEN_MAC !WOLFSSL_AEAD_ONLY */ - - -const byte* wolfSSL_GetClientWriteKey(WOLFSSL* ssl) +int wolfSSL_CTX_GetObjectSize(void) { - if (ssl) - return ssl->keys.client_write_key; - - return NULL; + return sizeof(WOLFSSL_CTX); } - -const byte* wolfSSL_GetClientWriteIV(WOLFSSL* ssl) +int wolfSSL_METHOD_GetObjectSize(void) { - if (ssl) - return ssl->keys.client_write_IV; - - return NULL; + return sizeof(WOLFSSL_METHOD); } +#endif -const byte* wolfSSL_GetServerWriteKey(WOLFSSL* ssl) -{ - if (ssl) - return ssl->keys.server_write_key; - - return NULL; -} - +#ifdef WOLFSSL_STATIC_MEMORY -const byte* wolfSSL_GetServerWriteIV(WOLFSSL* ssl) +int wolfSSL_CTX_load_static_memory(WOLFSSL_CTX** ctx, + wolfSSL_method_func method, unsigned char* buf, unsigned int sz, int flag, + int maxSz) { - if (ssl) - return ssl->keys.server_write_IV; + WOLFSSL_HEAP_HINT* hint = NULL; - return NULL; -} + if (ctx == NULL || buf == NULL) { + return BAD_FUNC_ARG; + } -int wolfSSL_GetKeySize(WOLFSSL* ssl) -{ - if (ssl) - return ssl->specs.key_size; + if (*ctx == NULL && method == NULL) { + return BAD_FUNC_ARG; + } - return BAD_FUNC_ARG; -} + /* If there is a heap already, capture it in hint. */ + if (*ctx && (*ctx)->heap != NULL) { + hint = (*ctx)->heap; + } + if (wc_LoadStaticMemory(&hint, buf, sz, flag, maxSz)) { + WOLFSSL_MSG("Error loading static memory"); + return WOLFSSL_FAILURE; + } -int wolfSSL_GetIVSize(WOLFSSL* ssl) -{ - if (ssl) - return ssl->specs.iv_size; + if (*ctx) { + if ((*ctx)->heap == NULL) { + (*ctx)->heap = (void*)hint; + } + } + else { + /* create ctx if needed */ + *ctx = wolfSSL_CTX_new_ex(method(hint), hint); + if (*ctx == NULL) { + WOLFSSL_MSG("Error creating ctx"); + return WOLFSSL_FAILURE; + } + } - return BAD_FUNC_ARG; + return WOLFSSL_SUCCESS; } -int wolfSSL_GetBulkCipher(WOLFSSL* ssl) +int wolfSSL_is_static_memory(WOLFSSL* ssl, WOLFSSL_MEM_CONN_STATS* mem_stats) { - if (ssl) - return ssl->specs.bulk_cipher_algorithm; + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + WOLFSSL_ENTER("wolfSSL_is_static_memory"); - return BAD_FUNC_ARG; +#ifndef WOLFSSL_STATIC_MEMORY_LEAN + /* fill out statistics if wanted and WOLFMEM_TRACK_STATS flag */ + if (mem_stats != NULL && ssl->heap != NULL) { + WOLFSSL_HEAP_HINT* hint = ((WOLFSSL_HEAP_HINT*)(ssl->heap)); + WOLFSSL_HEAP* heap = hint->memory; + if (heap->flag & WOLFMEM_TRACK_STATS && hint->stats != NULL) { + XMEMCPY(mem_stats, hint->stats, sizeof(WOLFSSL_MEM_CONN_STATS)); + } + } +#endif + + (void)mem_stats; + return (ssl->heap) ? 1 : 0; } -int wolfSSL_GetCipherType(WOLFSSL* ssl) +int wolfSSL_CTX_is_static_memory(WOLFSSL_CTX* ctx, WOLFSSL_MEM_STATS* mem_stats) { - if (ssl == NULL) + if (ctx == NULL) { return BAD_FUNC_ARG; + } + WOLFSSL_ENTER("wolfSSL_CTX_is_static_memory"); -#ifndef WOLFSSL_AEAD_ONLY - if (ssl->specs.cipher_type == block) - return WOLFSSL_BLOCK_TYPE; - if (ssl->specs.cipher_type == stream) - return WOLFSSL_STREAM_TYPE; +#ifndef WOLFSSL_STATIC_MEMORY_LEAN + /* fill out statistics if wanted */ + if (mem_stats != NULL && ctx->heap != NULL) { + WOLFSSL_HEAP* heap = ((WOLFSSL_HEAP_HINT*)(ctx->heap))->memory; + if (wolfSSL_GetMemStats(heap, mem_stats) != 1) { + return MEMORY_E; + } + } #endif - if (ssl->specs.cipher_type == aead) - return WOLFSSL_AEAD_TYPE; - return WOLFSSL_FATAL_ERROR; + (void)mem_stats; + return (ctx->heap) ? 1 : 0; } +#endif /* WOLFSSL_STATIC_MEMORY */ -int wolfSSL_GetCipherBlockSize(WOLFSSL* ssl) +#ifndef NO_TLS +/* return max record layer size plaintext input size */ +int wolfSSL_GetMaxOutputSize(WOLFSSL* ssl) { + WOLFSSL_ENTER("wolfSSL_GetMaxOutputSize"); + if (ssl == NULL) return BAD_FUNC_ARG; - return ssl->specs.block_size; + if (ssl->options.handShakeState != HANDSHAKE_DONE) { + WOLFSSL_MSG("Handshake not complete yet"); + return BAD_FUNC_ARG; + } + + return min(OUTPUT_RECORD_SIZE, wolfssl_local_GetMaxPlaintextSize(ssl)); } -int wolfSSL_GetAeadMacSize(WOLFSSL* ssl) +/* return record layer size of plaintext input size */ +int wolfSSL_GetOutputSize(WOLFSSL* ssl, int inSz) { - if (ssl == NULL) + int maxSize; + + WOLFSSL_ENTER("wolfSSL_GetOutputSize"); + + if (inSz < 0) return BAD_FUNC_ARG; - return ssl->specs.aead_mac_size; + maxSize = wolfSSL_GetMaxOutputSize(ssl); + if (maxSize < 0) + return maxSize; /* error */ + if (inSz > maxSize) + return INPUT_SIZE_E; + + return wolfssl_local_GetRecordSize(ssl, inSz, 1); } -int wolfSSL_IsTLSv1_1(WOLFSSL* ssl) +#ifdef HAVE_ECC +int wolfSSL_CTX_SetMinEccKey_Sz(WOLFSSL_CTX* ctx, short keySz) { - if (ssl == NULL) + short keySzBytes; + + WOLFSSL_ENTER("wolfSSL_CTX_SetMinEccKey_Sz"); + if (ctx == NULL || keySz < 0) { + WOLFSSL_MSG("Key size must be positive value or ctx was null"); return BAD_FUNC_ARG; + } - if (ssl->options.tls1_1) - return 1; + if (keySz % 8 == 0) { + keySzBytes = keySz / 8; + } + else { + keySzBytes = (keySz / 8) + 1; + } - return 0; -} +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled) { + if (ctx->minEccKeySz > (keySzBytes)) { + return CRYPTO_POLICY_FORBIDDEN; + } + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + ctx->minEccKeySz = keySzBytes; +#ifndef NO_CERTS + ctx->cm->minEccKeySz = keySzBytes; +#endif + return WOLFSSL_SUCCESS; +} -int wolfSSL_GetHmacSize(WOLFSSL* ssl) +int wolfSSL_SetMinEccKey_Sz(WOLFSSL* ssl, short keySz) { - /* AEAD ciphers don't have HMAC keys */ - if (ssl) - return (ssl->specs.cipher_type != aead) ? ssl->specs.hash_size : 0; - - return BAD_FUNC_ARG; -} + short keySzBytes; -#ifdef WORD64_AVAILABLE -int wolfSSL_GetPeerSequenceNumber(WOLFSSL* ssl, word64 *seq) -{ - if ((ssl == NULL) || (seq == NULL)) + WOLFSSL_ENTER("wolfSSL_SetMinEccKey_Sz"); + if (ssl == NULL || keySz < 0) { + WOLFSSL_MSG("Key size must be positive value or ctx was null"); return BAD_FUNC_ARG; + } - *seq = ((word64)ssl->keys.peer_sequence_number_hi << 32) | - ssl->keys.peer_sequence_number_lo; - return !(*seq); + if (keySz % 8 == 0) { + keySzBytes = keySz / 8; + } + else { + keySzBytes = (keySz / 8) + 1; + } + +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled) { + if (ssl->options.minEccKeySz > (keySzBytes)) { + return CRYPTO_POLICY_FORBIDDEN; + } + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + + ssl->options.minEccKeySz = keySzBytes; + return WOLFSSL_SUCCESS; } -int wolfSSL_GetSequenceNumber(WOLFSSL* ssl, word64 *seq) +#endif /* HAVE_ECC */ + +#ifndef NO_RSA +int wolfSSL_CTX_SetMinRsaKey_Sz(WOLFSSL_CTX* ctx, short keySz) { - if ((ssl == NULL) || (seq == NULL)) + if (ctx == NULL || keySz < 0 || keySz % 8 != 0) { + WOLFSSL_MSG("Key size must be divisible by 8 or ctx was null"); return BAD_FUNC_ARG; + } + +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled) { + if (ctx->minRsaKeySz > (keySz / 8)) { + return CRYPTO_POLICY_FORBIDDEN; + } + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - *seq = ((word64)ssl->keys.sequence_number_hi << 32) | - ssl->keys.sequence_number_lo; - return !(*seq); + ctx->minRsaKeySz = keySz / 8; + ctx->cm->minRsaKeySz = keySz / 8; + return WOLFSSL_SUCCESS; } -#endif -#endif /* ATOMIC_USER */ -#ifndef NO_CERTS -WOLFSSL_CERT_MANAGER* wolfSSL_CTX_GetCertManager(WOLFSSL_CTX* ctx) +int wolfSSL_SetMinRsaKey_Sz(WOLFSSL* ssl, short keySz) { - WOLFSSL_CERT_MANAGER* cm = NULL; - if (ctx) - cm = ctx->cm; - return cm; -} -#endif /* NO_CERTS */ - -#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) \ - && defined(XFPRINTF) + if (ssl == NULL || keySz < 0 || keySz % 8 != 0) { + WOLFSSL_MSG("Key size must be divisible by 8 or ssl was null"); + return BAD_FUNC_ARG; + } -void wolfSSL_ERR_print_errors_fp(XFILE fp, int err) -{ - char data[WOLFSSL_MAX_ERROR_SZ + 1]; +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled) { + if (ssl->options.minRsaKeySz > (keySz / 8)) { + return CRYPTO_POLICY_FORBIDDEN; + } + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - WOLFSSL_ENTER("wolfSSL_ERR_print_errors_fp"); - SetErrorString(err, data); - if (XFPRINTF(fp, "%s", data) < 0) - WOLFSSL_MSG("fprintf failed in wolfSSL_ERR_print_errors_fp"); + ssl->options.minRsaKeySz = keySz / 8; + return WOLFSSL_SUCCESS; } +#endif /* !NO_RSA */ -#if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) -void wolfSSL_ERR_dump_errors_fp(XFILE fp) -{ - wc_ERR_print_errors_fp(fp); -} +#ifndef NO_DH -void wolfSSL_ERR_print_errors_cb (int (*cb)(const char *str, size_t len, - void *u), void *u) +#if !defined(WOLFSSL_OLD_PRIME_CHECK) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) +/* Enables or disables the session's DH key prime test. */ +int wolfSSL_SetEnableDhKeyTest(WOLFSSL* ssl, int enable) { - wc_ERR_print_errors_cb(cb, u); -} -#endif -#endif /* !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM && XFPRINTF */ + WOLFSSL_ENTER("wolfSSL_SetEnableDhKeyTest"); -/* - * TODO This ssl parameter needs to be changed to const once our ABI checker - * stops flagging qualifier additions as ABI breaking. - */ -WOLFSSL_ABI -int wolfSSL_pending(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_pending"); if (ssl == NULL) - return WOLFSSL_FAILURE; - - return (int)ssl->buffers.clearOutputBuffer.length; -} + return BAD_FUNC_ARG; -int wolfSSL_has_pending(const WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_has_pending"); - if (ssl == NULL) - return WOLFSSL_FAILURE; + if (!enable) + ssl->options.dhDoKeyTest = 0; + else + ssl->options.dhDoKeyTest = 1; - return ssl->buffers.clearOutputBuffer.length > 0; + WOLFSSL_LEAVE("wolfSSL_SetEnableDhKeyTest", WOLFSSL_SUCCESS); + return WOLFSSL_SUCCESS; } +#endif -#ifndef WOLFSSL_LEANPSK -/* turn on handshake group messages for context */ -int wolfSSL_CTX_set_group_messages(WOLFSSL_CTX* ctx) +int wolfSSL_CTX_SetMinDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz_bits) { - if (ctx == NULL) - return BAD_FUNC_ARG; + if (ctx == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) + return BAD_FUNC_ARG; - ctx->groupMessages = 1; +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled) { + if (ctx->minDhKeySz > (keySz_bits / 8)) { + return CRYPTO_POLICY_FORBIDDEN; + } + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + ctx->minDhKeySz = keySz_bits / 8; return WOLFSSL_SUCCESS; } -int wolfSSL_CTX_clear_group_messages(WOLFSSL_CTX* ctx) + +int wolfSSL_SetMinDhKey_Sz(WOLFSSL* ssl, word16 keySz_bits) { - if (ctx == NULL) - return BAD_FUNC_ARG; + if (ssl == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) + return BAD_FUNC_ARG; - ctx->groupMessages = 0; +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled) { + if (ssl->options.minDhKeySz > (keySz_bits / 8)) { + return CRYPTO_POLICY_FORBIDDEN; + } + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + ssl->options.minDhKeySz = keySz_bits / 8; return WOLFSSL_SUCCESS; } -#endif -#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) -/* connect enough to get peer cert chain */ -int wolfSSL_connect_cert(WOLFSSL* ssl) +int wolfSSL_CTX_SetMaxDhKey_Sz(WOLFSSL_CTX* ctx, word16 keySz_bits) { - int ret; - - if (ssl == NULL) - return WOLFSSL_FAILURE; + if (ctx == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) + return BAD_FUNC_ARG; - ssl->options.certOnly = 1; - ret = wolfSSL_connect(ssl); - ssl->options.certOnly = 0; +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled) { + if (ctx->minDhKeySz > (keySz_bits / 8)) { + return CRYPTO_POLICY_FORBIDDEN; + } + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - return ret; + ctx->maxDhKeySz = keySz_bits / 8; + return WOLFSSL_SUCCESS; } -#endif -#ifndef WOLFSSL_LEANPSK -/* turn on handshake group messages for ssl object */ -int wolfSSL_set_group_messages(WOLFSSL* ssl) +int wolfSSL_SetMaxDhKey_Sz(WOLFSSL* ssl, word16 keySz_bits) { - if (ssl == NULL) - return BAD_FUNC_ARG; + if (ssl == NULL || keySz_bits > 16000 || keySz_bits % 8 != 0) + return BAD_FUNC_ARG; - ssl->options.groupMessages = 1; +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled) { + if (ssl->options.minDhKeySz > (keySz_bits / 8)) { + return CRYPTO_POLICY_FORBIDDEN; + } + } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + ssl->options.maxDhKeySz = keySz_bits / 8; return WOLFSSL_SUCCESS; } -int wolfSSL_clear_group_messages(WOLFSSL* ssl) + +int wolfSSL_GetDhKey_Sz(WOLFSSL* ssl) { if (ssl == NULL) - return BAD_FUNC_ARG; - - ssl->options.groupMessages = 0; + return BAD_FUNC_ARG; - return WOLFSSL_SUCCESS; + return (ssl->options.dhKeySz * 8); } -/* make minVersion the internal equivalent SSL version */ -static int SetMinVersionHelper(byte* minVersion, int version) +#endif /* !NO_DH */ + + +static int wolfSSL_write_internal(WOLFSSL* ssl, const void* data, size_t sz) { - (void)minVersion; + int ret; - switch (version) { -#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) - case WOLFSSL_SSLV3: - *minVersion = SSLv3_MINOR; - break; + WOLFSSL_ENTER("wolfSSL_write"); + + if (ssl == NULL || data == NULL) + return BAD_FUNC_ARG; + +#ifdef WOLFSSL_QUIC + if (WOLFSSL_IS_QUIC(ssl)) { + WOLFSSL_MSG("SSL_write() on QUIC not allowed"); + return BAD_FUNC_ARG; + } #endif -#ifndef NO_TLS - #ifndef NO_OLD_TLS - #ifdef WOLFSSL_ALLOW_TLSV10 - case WOLFSSL_TLSV1: - *minVersion = TLSv1_MINOR; - break; - #endif +#ifdef HAVE_WRITE_DUP + { /* local variable scope */ + int dupErr = 0; /* local copy */ - case WOLFSSL_TLSV1_1: - *minVersion = TLSv1_1_MINOR; - break; - #endif - #ifndef WOLFSSL_NO_TLS12 - case WOLFSSL_TLSV1_2: - *minVersion = TLSv1_2_MINOR; - break; - #endif + ret = 0; + + if (ssl->dupWrite && ssl->dupSide == READ_DUP_SIDE) { + WOLFSSL_MSG("Read dup side cannot write"); + return WRITE_DUP_WRITE_E; + } + if (ssl->dupWrite) { + if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0) { + return BAD_MUTEX_E; + } + dupErr = ssl->dupWrite->dupErr; + ret = wc_UnLockMutex(&ssl->dupWrite->dupMutex); + } + + if (ret != 0) { + ssl->error = ret; /* high priority fatal error */ + return WOLFSSL_FATAL_ERROR; + } + if (dupErr != 0) { + WOLFSSL_MSG("Write dup error from other side"); + ssl->error = dupErr; + return WOLFSSL_FATAL_ERROR; + } + } #endif - #ifdef WOLFSSL_TLS13 - case WOLFSSL_TLSV1_3: - *minVersion = TLSv1_3_MINOR; - break; - #endif -#ifdef WOLFSSL_DTLS - case WOLFSSL_DTLSV1: - *minVersion = DTLS_MINOR; - break; - case WOLFSSL_DTLSV1_2: - *minVersion = DTLSv1_2_MINOR; - break; -#ifdef WOLFSSL_DTLS13 - case WOLFSSL_DTLSV1_3: - *minVersion = DTLSv1_3_MINOR; - break; -#endif /* WOLFSSL_DTLS13 */ -#endif /* WOLFSSL_DTLS */ +#ifdef HAVE_ERRNO_H + errno = 0; +#endif - default: - WOLFSSL_MSG("Bad function argument"); - return BAD_FUNC_ARG; + #ifdef OPENSSL_EXTRA + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, WOLFSSL_CB_WRITE, WOLFSSL_SUCCESS); + ssl->cbmode = WOLFSSL_CB_WRITE; } + #endif + ret = SendData(ssl, data, sz); - return WOLFSSL_SUCCESS; -} + WOLFSSL_LEAVE("wolfSSL_write", ret); + if (ret < 0) + return WOLFSSL_FATAL_ERROR; + else + return ret; +} -/* Set minimum downgrade version allowed, WOLFSSL_SUCCESS on ok */ WOLFSSL_ABI -int wolfSSL_CTX_SetMinVersion(WOLFSSL_CTX* ctx, int version) +int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz) { - WOLFSSL_ENTER("wolfSSL_CTX_SetMinVersion"); + WOLFSSL_ENTER("wolfSSL_write"); - if (ctx == NULL) { - WOLFSSL_MSG("Bad function argument"); + if (sz < 0) return BAD_FUNC_ARG; - } - -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - return CRYPTO_POLICY_FORBIDDEN; - } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - return SetMinVersionHelper(&ctx->minDowngrade, version); + return wolfSSL_write_internal(ssl, data, (size_t)sz); } - -/* Set minimum downgrade version allowed, WOLFSSL_SUCCESS on ok */ -int wolfSSL_SetMinVersion(WOLFSSL* ssl, int version) +int wolfSSL_inject(WOLFSSL* ssl, const void* data, int sz) { - WOLFSSL_ENTER("wolfSSL_SetMinVersion"); + int maxLength; + int usedLength; - if (ssl == NULL) { - WOLFSSL_MSG("Bad function argument"); + WOLFSSL_ENTER("wolfSSL_inject"); + + if (ssl == NULL || data == NULL || sz <= 0) return BAD_FUNC_ARG; - } -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - if (crypto_policy.enabled) { - return CRYPTO_POLICY_FORBIDDEN; + usedLength = (int)(ssl->buffers.inputBuffer.length - + ssl->buffers.inputBuffer.idx); + maxLength = (int)(ssl->buffers.inputBuffer.bufferSize - + (word32)usedLength); + + if (sz > maxLength) { + /* Need to make space */ + int ret; + if (ssl->buffers.clearOutputBuffer.length > 0) { + /* clearOutputBuffer points into so reallocating inputBuffer will + * invalidate clearOutputBuffer and lose app data */ + WOLFSSL_MSG("Can't inject while there is application data to read"); + return APP_DATA_READY; + } + ret = GrowInputBuffer(ssl, sz, usedLength); + if (ret < 0) + return ret; } -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - return SetMinVersionHelper(&ssl->options.minDowngrade, version); + XMEMCPY(ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, + data, sz); + ssl->buffers.inputBuffer.length += sz; + + return WOLFSSL_SUCCESS; } -/* Function to get version as WOLFSSL_ enum value for wolfSSL_SetVersion */ -int wolfSSL_GetVersion(const WOLFSSL* ssl) +int wolfSSL_write_ex(WOLFSSL* ssl, const void* data, size_t sz, size_t* wr) { - if (ssl == NULL) - return BAD_FUNC_ARG; + int ret; - if (ssl->version.major == SSLv3_MAJOR) { - switch (ssl->version.minor) { - case SSLv3_MINOR : - return WOLFSSL_SSLV3; - case TLSv1_MINOR : - return WOLFSSL_TLSV1; - case TLSv1_1_MINOR : - return WOLFSSL_TLSV1_1; - case TLSv1_2_MINOR : - return WOLFSSL_TLSV1_2; - case TLSv1_3_MINOR : - return WOLFSSL_TLSV1_3; - default: - break; - } + if (wr != NULL) { + *wr = 0; } -#ifdef WOLFSSL_DTLS - if (ssl->version.major == DTLS_MAJOR) { - switch (ssl->version.minor) { - case DTLS_MINOR : - return WOLFSSL_DTLSV1; - case DTLSv1_2_MINOR : - return WOLFSSL_DTLSV1_2; - case DTLSv1_3_MINOR : - return WOLFSSL_DTLSV1_3; - default: - break; + + ret = wolfSSL_write_internal(ssl, data, sz); + if (ret >= 0) { + if (wr != NULL) { + *wr = (size_t)ret; + } + + /* handle partial write cases, if not set then a partial write is + * considered a failure case, or if set and ret is 0 then is a fail */ + if (ret == 0 && ssl->options.partialWrite) { + ret = 0; + } + else if ((size_t)ret < sz && !ssl->options.partialWrite) { + ret = 0; + } + else { + /* wrote out all application data, or wrote out 1 byte or more with + * partial write flag set */ + ret = 1; } } -#endif /* WOLFSSL_DTLS */ + else { + ret = 0; + } - return VERSION_ERROR; + return ret; } -int wolfSSL_SetVersion(WOLFSSL* ssl, int version) + +static int wolfSSL_read_internal(WOLFSSL* ssl, void* data, size_t sz, int peek) { - word16 haveRSA = 1; - word16 havePSK = 0; - int keySz = 0; + int ret; - WOLFSSL_ENTER("wolfSSL_SetVersion"); + WOLFSSL_ENTER("wolfSSL_read_internal"); - if (ssl == NULL) { - WOLFSSL_MSG("Bad function argument"); + if (ssl == NULL || data == NULL) return BAD_FUNC_ARG; - } - switch (version) { -#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) - case WOLFSSL_SSLV3: - ssl->version = MakeSSLv3(); - break; +#ifdef WOLFSSL_QUIC + if (WOLFSSL_IS_QUIC(ssl)) { + WOLFSSL_MSG("SSL_read() on QUIC not allowed"); + return BAD_FUNC_ARG; + } #endif +#if defined(WOLFSSL_ERROR_CODE_OPENSSL) && defined(OPENSSL_EXTRA) + /* This additional logic is meant to simulate following openSSL behavior: + * After bidirectional SSL_shutdown complete, SSL_read returns 0 and + * SSL_get_error_code returns SSL_ERROR_ZERO_RETURN. + * This behavior is used to know the disconnect of the underlying + * transport layer. + * + * In this logic, CBIORecv is called with a read size of 0 to check the + * transport layer status. It also returns WOLFSSL_FAILURE so that + * SSL_read does not return a positive number on failure. + */ -#ifndef NO_TLS - #ifndef NO_OLD_TLS - #ifdef WOLFSSL_ALLOW_TLSV10 - case WOLFSSL_TLSV1: - ssl->version = MakeTLSv1(); - break; - #endif + /* make sure bidirectional TLS shutdown completes */ + if (ssl->error == WOLFSSL_ERROR_SYSCALL || ssl->options.shutdownDone) { + /* ask the underlying transport the connection is closed */ + if (ssl->CBIORecv(ssl, (char*)data, 0, ssl->IOCB_ReadCtx) + == WC_NO_ERR_TRACE(WOLFSSL_CBIO_ERR_CONN_CLOSE)) + { + ssl->options.isClosed = 1; + ssl->error = WOLFSSL_ERROR_ZERO_RETURN; + } + return WOLFSSL_FAILURE; + } +#endif - case WOLFSSL_TLSV1_1: - ssl->version = MakeTLSv1_1(); - break; - #endif - #ifndef WOLFSSL_NO_TLS12 - case WOLFSSL_TLSV1_2: - ssl->version = MakeTLSv1_2(); - break; - #endif +#ifdef HAVE_WRITE_DUP + if (ssl->dupWrite && ssl->dupSide == WRITE_DUP_SIDE) { + WOLFSSL_MSG("Write dup side cannot read"); + return WRITE_DUP_READ_E; + } +#endif - #ifdef WOLFSSL_TLS13 - case WOLFSSL_TLSV1_3: - ssl->version = MakeTLSv1_3(); - break; - #endif /* WOLFSSL_TLS13 */ +#ifdef HAVE_ERRNO_H + errno = 0; #endif - default: - WOLFSSL_MSG("Bad function argument"); - return BAD_FUNC_ARG; + ret = ReceiveData(ssl, (byte*)data, sz, peek); + +#ifdef HAVE_WRITE_DUP + if (ssl->dupWrite) { + if (ssl->error != 0 && ssl->error != WC_NO_ERR_TRACE(WANT_READ) + #ifdef WOLFSSL_ASYNC_CRYPT + && ssl->error != WC_NO_ERR_TRACE(WC_PENDING_E) + #endif + ) { + int notifyErr; + + WOLFSSL_MSG("Notifying write side of fatal read error"); + notifyErr = NotifyWriteSide(ssl, ssl->error); + if (notifyErr < 0) { + ret = ssl->error = notifyErr; + } + } } +#endif - ssl->options.downgrade = 0; + WOLFSSL_LEAVE("wolfSSL_read_internal", ret); - #ifdef NO_RSA - haveRSA = 0; - #endif - #ifndef NO_PSK - havePSK = ssl->options.havePSK; - #endif - #ifndef NO_CERTS - keySz = ssl->buffers.keySz; - #endif + if (ret < 0) + return WOLFSSL_FATAL_ERROR; + else + return ret; +} - if (AllocateSuites(ssl) != 0) - return WOLFSSL_FAILURE; - InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, - ssl->options.haveDH, ssl->options.haveECDSAsig, - ssl->options.haveECC, TRUE, ssl->options.haveStaticECC, - ssl->options.useAnon, TRUE, TRUE, TRUE, TRUE, ssl->options.side); - return WOLFSSL_SUCCESS; + +int wolfSSL_peek(WOLFSSL* ssl, void* data, int sz) +{ + WOLFSSL_ENTER("wolfSSL_peek"); + + if (sz < 0) + return BAD_FUNC_ARG; + + return wolfSSL_read_internal(ssl, data, (size_t)sz, TRUE); } -#endif /* !leanpsk */ -#ifndef NO_CERTS -/* hash is the SHA digest of name, just use first 32 bits as hash */ -static WC_INLINE word32 HashSigner(const byte* hash) +WOLFSSL_ABI +int wolfSSL_read(WOLFSSL* ssl, void* data, int sz) { - return MakeWordFromHash(hash) % CA_TABLE_SIZE; + WOLFSSL_ENTER("wolfSSL_read"); + + if (sz < 0) + return BAD_FUNC_ARG; + + #ifdef OPENSSL_EXTRA + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, WOLFSSL_CB_READ, WOLFSSL_SUCCESS); + ssl->cbmode = WOLFSSL_CB_READ; + } + #endif + return wolfSSL_read_internal(ssl, data, (size_t)sz, FALSE); } -/* does CA already exist on signer list */ -int AlreadySigner(WOLFSSL_CERT_MANAGER* cm, byte* hash) +/* returns 0 on failure and 1 on read */ +int wolfSSL_read_ex(WOLFSSL* ssl, void* data, size_t sz, size_t* rd) { - Signer* signers; - int ret = 0; - word32 row; + int ret; - if (cm == NULL || hash == NULL) { - return ret; + #ifdef OPENSSL_EXTRA + if (ssl == NULL) { + return BAD_FUNC_ARG; } - - row = HashSigner(hash); - - if (wc_LockMutex(&cm->caLock) != 0) { - return ret; + if (ssl->CBIS != NULL) { + ssl->CBIS(ssl, WOLFSSL_CB_READ, WOLFSSL_SUCCESS); + ssl->cbmode = WOLFSSL_CB_READ; } - signers = cm->caTable[row]; - while (signers) { - byte* subjectHash; - - #ifndef NO_SKID - subjectHash = signers->subjectKeyIdHash; - #else - subjectHash = signers->subjectNameHash; #endif + ret = wolfSSL_read_internal(ssl, data, sz, FALSE); - if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { - ret = 1; /* success */ - break; - } - signers = signers->next; + if (ret > 0 && rd != NULL) { + *rd = (size_t)ret; } - wc_UnLockMutex(&cm->caLock); - return ret; + return ret > 0 ? 1 : 0; } +#ifdef WOLFSSL_MULTICAST -#ifdef WOLFSSL_TRUST_PEER_CERT -/* hash is the SHA digest of name, just use first 32 bits as hash */ -static WC_INLINE word32 TrustedPeerHashSigner(const byte* hash) +int wolfSSL_mcast_read(WOLFSSL* ssl, word16* id, void* data, int sz) { - return MakeWordFromHash(hash) % TP_TABLE_SIZE; -} + int ret = 0; -/* does trusted peer already exist on signer list */ -int AlreadyTrustedPeer(WOLFSSL_CERT_MANAGER* cm, DecodedCert* cert) -{ - TrustedPeerCert* tp; - int ret = 0; - word32 row = TrustedPeerHashSigner(cert->subjectHash); - - if (wc_LockMutex(&cm->tpLock) != 0) - return ret; - tp = cm->tpTable[row]; - while (tp) { - if ((XMEMCMP(cert->subjectHash, tp->subjectNameHash, - SIGNER_DIGEST_SIZE) == 0) - #ifndef WOLFSSL_NO_ISSUERHASH_TDPEER - && (XMEMCMP(cert->issuerHash, tp->issuerHash, - SIGNER_DIGEST_SIZE) == 0) - #endif - ) - ret = 1; - #ifndef NO_SKID - if (cert->extSubjKeyIdSet) { - /* Compare SKID as well if available */ - if (ret == 1 && XMEMCMP(cert->extSubjKeyId, tp->subjectKeyIdHash, - SIGNER_DIGEST_SIZE) != 0) - ret = 0; - } - #endif - if (ret == 1) - break; - tp = tp->next; - } - wc_UnLockMutex(&cm->tpLock); + WOLFSSL_ENTER("wolfSSL_mcast_read"); + if ((ssl == NULL) || (sz < 0)) + return BAD_FUNC_ARG; + + ret = wolfSSL_read_internal(ssl, data, (size_t)sz, FALSE); + if (ssl->options.dtls && ssl->options.haveMcast && id != NULL) + *id = ssl->keys.curPeerId; return ret; } +#endif /* WOLFSSL_MULTICAST */ +#endif /* !NO_TLS */ -/* return Trusted Peer if found, otherwise NULL - type is what to match on - */ -TrustedPeerCert* GetTrustedPeer(void* vp, DecodedCert* cert) +/* helpers to set the device id, WOLFSSL_SUCCESS on ok */ +WOLFSSL_ABI +int wolfSSL_SetDevId(WOLFSSL* ssl, int devId) { - WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; - TrustedPeerCert* ret = NULL; - TrustedPeerCert* tp = NULL; - word32 row; - - if (cm == NULL || cert == NULL) - return NULL; - - row = TrustedPeerHashSigner(cert->subjectHash); - - if (wc_LockMutex(&cm->tpLock) != 0) - return ret; + if (ssl == NULL) + return BAD_FUNC_ARG; - tp = cm->tpTable[row]; - while (tp) { - if ((XMEMCMP(cert->subjectHash, tp->subjectNameHash, - SIGNER_DIGEST_SIZE) == 0) - #ifndef WOLFSSL_NO_ISSUERHASH_TDPEER - && (XMEMCMP(cert->issuerHash, tp->issuerHash, - SIGNER_DIGEST_SIZE) == 0) - #endif - ) - ret = tp; - #ifndef NO_SKID - if (cert->extSubjKeyIdSet) { - /* Compare SKID as well if available */ - if (ret != NULL && XMEMCMP(cert->extSubjKeyId, tp->subjectKeyIdHash, - SIGNER_DIGEST_SIZE) != 0) - ret = NULL; - } - #endif - if (ret != NULL) - break; - tp = tp->next; - } - wc_UnLockMutex(&cm->tpLock); + ssl->devId = devId; - return ret; + return WOLFSSL_SUCCESS; } - -int MatchTrustedPeer(TrustedPeerCert* tp, DecodedCert* cert) +WOLFSSL_ABI +int wolfSSL_CTX_SetDevId(WOLFSSL_CTX* ctx, int devId) { - if (tp == NULL || cert == NULL) + if (ctx == NULL) return BAD_FUNC_ARG; - /* subject key id or subject hash has been compared when searching - tpTable for the cert from function GetTrustedPeer */ - - /* compare signatures */ - if (tp->sigLen == cert->sigLength) { - if (XMEMCMP(tp->sig, cert->signature, cert->sigLength)) { - return WOLFSSL_FAILURE; - } - } - else { - return WOLFSSL_FAILURE; - } + ctx->devId = devId; return WOLFSSL_SUCCESS; } -#endif /* WOLFSSL_TRUST_PEER_CERT */ - -/* return CA if found, otherwise NULL */ -Signer* GetCA(void* vp, byte* hash) +/* helpers to get device id and heap */ +WOLFSSL_ABI +int wolfSSL_CTX_GetDevId(WOLFSSL_CTX* ctx, WOLFSSL* ssl) { - WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; - Signer* ret = NULL; - Signer* signers; - word32 row = 0; - - if (cm == NULL || hash == NULL) - return NULL; + int devId = INVALID_DEVID; + if (ssl != NULL) + devId = ssl->devId; + if (ctx != NULL && devId == INVALID_DEVID) + devId = ctx->devId; + return devId; +} +void* wolfSSL_CTX_GetHeap(WOLFSSL_CTX* ctx, WOLFSSL* ssl) +{ + void* heap = NULL; + if (ctx != NULL) + heap = ctx->heap; + else if (ssl != NULL) + heap = ssl->heap; + return heap; +} - row = HashSigner(hash); - if (wc_LockMutex(&cm->caLock) != 0) - return ret; +#ifndef NO_TLS +#ifdef HAVE_SNI - signers = cm->caTable[row]; - while (signers) { - byte* subjectHash; - #ifndef NO_SKID - subjectHash = signers->subjectKeyIdHash; - #else - subjectHash = signers->subjectNameHash; - #endif - if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { - ret = signers; - break; - } - signers = signers->next; - } - wc_UnLockMutex(&cm->caLock); +WOLFSSL_ABI +int wolfSSL_UseSNI(WOLFSSL* ssl, byte type, const void* data, word16 size) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; - return ret; + return TLSX_UseSNI(&ssl->extensions, type, data, size, ssl->heap); } -#if defined(HAVE_OCSP) -Signer* GetCAByKeyHash(void* vp, const byte* keyHash) + +WOLFSSL_ABI +int wolfSSL_CTX_UseSNI(WOLFSSL_CTX* ctx, byte type, const void* data, + word16 size) { - WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; - Signer* ret = NULL; - Signer* signers; - int row; + if (ctx == NULL) + return BAD_FUNC_ARG; - if (cm == NULL || keyHash == NULL) - return NULL; + return TLSX_UseSNI(&ctx->extensions, type, data, size, ctx->heap); +} - /* try lookup using keyHash as subjKeyID first */ - ret = GetCA(vp, (byte*)keyHash); - if (ret != NULL && XMEMCMP(ret->subjectKeyHash, keyHash, KEYID_SIZE) == 0) { - return ret; - } +#ifndef NO_WOLFSSL_SERVER - /* if we can't find the cert, we have to scan the full table */ - if (wc_LockMutex(&cm->caLock) != 0) - return NULL; +void wolfSSL_SNI_SetOptions(WOLFSSL* ssl, byte type, byte options) +{ + if (ssl && ssl->extensions) + TLSX_SNI_SetOptions(ssl->extensions, type, options); +} - /* Unfortunately we need to look through the entire table */ - for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) { - for (signers = cm->caTable[row]; signers != NULL; - signers = signers->next) { - if (XMEMCMP(signers->subjectKeyHash, keyHash, KEYID_SIZE) == 0) { - ret = signers; - break; - } - } - } - wc_UnLockMutex(&cm->caLock); - return ret; -} -#endif -#ifdef WOLFSSL_AKID_NAME -Signer* GetCAByAKID(void* vp, const byte* issuer, word32 issuerSz, - const byte* serial, word32 serialSz) +void wolfSSL_CTX_SNI_SetOptions(WOLFSSL_CTX* ctx, byte type, byte options) { - WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; - Signer* ret = NULL; - Signer* signers; - byte nameHash[SIGNER_DIGEST_SIZE]; - byte serialHash[SIGNER_DIGEST_SIZE]; - word32 row; + if (ctx && ctx->extensions) + TLSX_SNI_SetOptions(ctx->extensions, type, options); +} - if (cm == NULL || issuer == NULL || issuerSz == 0 || - serial == NULL || serialSz == 0) - return NULL; - if (CalcHashId(issuer, issuerSz, nameHash) != 0 || - CalcHashId(serial, serialSz, serialHash) != 0) - return NULL; +byte wolfSSL_SNI_Status(WOLFSSL* ssl, byte type) +{ + return TLSX_SNI_Status(ssl ? ssl->extensions : NULL, type); +} - if (wc_LockMutex(&cm->caLock) != 0) - return ret; - /* Unfortunately we need to look through the entire table */ - for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) { - for (signers = cm->caTable[row]; signers != NULL; - signers = signers->next) { - if (XMEMCMP(signers->issuerNameHash, nameHash, SIGNER_DIGEST_SIZE) - == 0 && XMEMCMP(signers->serialHash, serialHash, - SIGNER_DIGEST_SIZE) == 0) { - ret = signers; - break; - } - } - } +word16 wolfSSL_SNI_GetRequest(WOLFSSL* ssl, byte type, void** data) +{ + if (data) + *data = NULL; - wc_UnLockMutex(&cm->caLock); + if (ssl && ssl->extensions) + return TLSX_SNI_GetRequest(ssl->extensions, type, data, 0); - return ret; + return 0; } -#endif -#ifndef NO_SKID -/* return CA if found, otherwise NULL. Walk through hash table. */ -Signer* GetCAByName(void* vp, byte* hash) + +int wolfSSL_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz, + byte type, byte* sni, word32* inOutSz) { - WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; - Signer* ret = NULL; - Signer* signers; - word32 row; + if (clientHello && helloSz > 0 && sni && inOutSz && *inOutSz > 0) + return TLSX_SNI_GetFromBuffer(clientHello, helloSz, type, sni, inOutSz); - if (cm == NULL) - return NULL; + return BAD_FUNC_ARG; +} - if (wc_LockMutex(&cm->caLock) != 0) - return ret; +#endif /* !NO_WOLFSSL_SERVER */ - for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) { - signers = cm->caTable[row]; - while (signers && ret == NULL) { - if (XMEMCMP(hash, signers->subjectNameHash, - SIGNER_DIGEST_SIZE) == 0) { - ret = signers; - } - signers = signers->next; - } - } - wc_UnLockMutex(&cm->caLock); +#endif /* HAVE_SNI */ - return ret; -} -#endif +#ifdef HAVE_TRUSTED_CA -#ifdef WOLFSSL_TRUST_PEER_CERT -/* add a trusted peer cert to linked list */ -int AddTrustedPeer(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int verify) +int wolfSSL_UseTrustedCA(WOLFSSL* ssl, byte type, + const byte* certId, word32 certIdSz) { - int ret = 0; - int row = 0; - TrustedPeerCert* peerCert; - DecodedCert* cert; - DerBuffer* der = *pDer; - - WOLFSSL_MSG("Adding a Trusted Peer Cert"); + if (ssl == NULL) + return BAD_FUNC_ARG; - cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cm->heap, - DYNAMIC_TYPE_DCERT); - if (cert == NULL) { - FreeDer(&der); - return MEMORY_E; + if (type == WOLFSSL_TRUSTED_CA_PRE_AGREED) { + if (certId != NULL || certIdSz != 0) + return BAD_FUNC_ARG; } - - InitDecodedCert(cert, der->buffer, der->length, cm->heap); - if ((ret = ParseCert(cert, TRUSTED_PEER_TYPE, verify, cm)) != 0) { - FreeDecodedCert(cert); - XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); - FreeDer(&der); - return ret; + else if (type == WOLFSSL_TRUSTED_CA_X509_NAME) { + if (certId == NULL || certIdSz == 0) + return BAD_FUNC_ARG; + } + #ifndef NO_SHA + else if (type == WOLFSSL_TRUSTED_CA_KEY_SHA1 || + type == WOLFSSL_TRUSTED_CA_CERT_SHA1) { + if (certId == NULL || certIdSz != WC_SHA_DIGEST_SIZE) + return BAD_FUNC_ARG; } - WOLFSSL_MSG("\tParsed new trusted peer cert"); + #endif + else + return BAD_FUNC_ARG; - peerCert = (TrustedPeerCert*)XMALLOC(sizeof(TrustedPeerCert), cm->heap, - DYNAMIC_TYPE_CERT); - if (peerCert == NULL) { - FreeDecodedCert(cert); - XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); - FreeDer(&der); - return MEMORY_E; + return TLSX_UseTrustedCA(&ssl->extensions, + type, certId, certIdSz, ssl->heap); +} + +#endif /* HAVE_TRUSTED_CA */ + + +#ifdef HAVE_MAX_FRAGMENT +#ifndef NO_WOLFSSL_CLIENT + +int wolfSSL_UseMaxFragment(WOLFSSL* ssl, byte mfl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + +#ifdef WOLFSSL_ALLOW_MAX_FRAGMENT_ADJUST + /* The following is a non-standard way to reconfigure the max packet size + post-handshake for wolfSSL_write/wolfSSL_read */ + if (ssl->options.handShakeState == HANDSHAKE_DONE) { + switch (mfl) { + case WOLFSSL_MFL_2_8 : ssl->max_fragment = 256; break; + case WOLFSSL_MFL_2_9 : ssl->max_fragment = 512; break; + case WOLFSSL_MFL_2_10: ssl->max_fragment = 1024; break; + case WOLFSSL_MFL_2_11: ssl->max_fragment = 2048; break; + case WOLFSSL_MFL_2_12: ssl->max_fragment = 4096; break; + case WOLFSSL_MFL_2_13: ssl->max_fragment = 8192; break; + default: ssl->max_fragment = MAX_RECORD_SIZE; break; + } + return WOLFSSL_SUCCESS; } - XMEMSET(peerCert, 0, sizeof(TrustedPeerCert)); +#endif /* WOLFSSL_MAX_FRAGMENT_ADJUST */ - #ifndef IGNORE_NAME_CONSTRAINTS - if (peerCert->permittedNames) - FreeNameSubtrees(peerCert->permittedNames, cm->heap); - if (peerCert->excludedNames) - FreeNameSubtrees(peerCert->excludedNames, cm->heap); - #endif + /* This call sets the max fragment TLS extension, which gets sent to server. + The server_hello response is what sets the `ssl->max_fragment` in + TLSX_MFL_Parse */ + return TLSX_UseMaxFragment(&ssl->extensions, mfl, ssl->heap); +} - if (AlreadyTrustedPeer(cm, cert)) { - WOLFSSL_MSG("\tAlready have this CA, not adding again"); - FreeTrustedPeer(peerCert, cm->heap); - (void)ret; - } - else { - /* add trusted peer signature */ - peerCert->sigLen = cert->sigLength; - peerCert->sig = (byte *)XMALLOC(cert->sigLength, cm->heap, - DYNAMIC_TYPE_SIGNATURE); - if (peerCert->sig == NULL) { - FreeDecodedCert(cert); - XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); - FreeTrustedPeer(peerCert, cm->heap); - FreeDer(&der); - return MEMORY_E; - } - XMEMCPY(peerCert->sig, cert->signature, cert->sigLength); - /* add trusted peer name */ - peerCert->nameLen = cert->subjectCNLen; - peerCert->name = cert->subjectCN; - #ifndef IGNORE_NAME_CONSTRAINTS - peerCert->permittedNames = cert->permittedNames; - peerCert->excludedNames = cert->excludedNames; - #endif +int wolfSSL_CTX_UseMaxFragment(WOLFSSL_CTX* ctx, byte mfl) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; - /* add SKID when available and hash of name */ - #ifndef NO_SKID - XMEMCPY(peerCert->subjectKeyIdHash, cert->extSubjKeyId, - SIGNER_DIGEST_SIZE); - #endif - XMEMCPY(peerCert->subjectNameHash, cert->subjectHash, - SIGNER_DIGEST_SIZE); - #ifndef WOLFSSL_NO_ISSUERHASH_TDPEER - XMEMCPY(peerCert->issuerHash, cert->issuerHash, - SIGNER_DIGEST_SIZE); - #endif - /* If Key Usage not set, all uses valid. */ - peerCert->next = NULL; - cert->subjectCN = 0; - #ifndef IGNORE_NAME_CONSTRAINTS - cert->permittedNames = NULL; - cert->excludedNames = NULL; - #endif + return TLSX_UseMaxFragment(&ctx->extensions, mfl, ctx->heap); +} - row = (int)TrustedPeerHashSigner(peerCert->subjectNameHash); +#endif /* NO_WOLFSSL_CLIENT */ +#endif /* HAVE_MAX_FRAGMENT */ - if (wc_LockMutex(&cm->tpLock) == 0) { - peerCert->next = cm->tpTable[row]; - cm->tpTable[row] = peerCert; /* takes ownership */ - wc_UnLockMutex(&cm->tpLock); - } - else { - WOLFSSL_MSG("\tTrusted Peer Cert Mutex Lock failed"); - FreeDecodedCert(cert); - XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); - FreeTrustedPeer(peerCert, cm->heap); - FreeDer(&der); - return BAD_MUTEX_E; - } - } +#ifdef HAVE_TRUNCATED_HMAC +#ifndef NO_WOLFSSL_CLIENT - WOLFSSL_MSG("\tFreeing parsed trusted peer cert"); - FreeDecodedCert(cert); - XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); - WOLFSSL_MSG("\tFreeing der trusted peer cert"); - FreeDer(&der); - WOLFSSL_MSG("\t\tOK Freeing der trusted peer cert"); - WOLFSSL_LEAVE("AddTrustedPeer", ret); +int wolfSSL_UseTruncatedHMAC(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; - return WOLFSSL_SUCCESS; + return TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap); } -#endif /* WOLFSSL_TRUST_PEER_CERT */ -int AddSigner(WOLFSSL_CERT_MANAGER* cm, Signer *s) -{ - byte* subjectHash; - Signer* signers; - word32 row; - if (cm == NULL || s == NULL) +int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) return BAD_FUNC_ARG; -#ifndef NO_SKID - subjectHash = s->subjectKeyIdHash; -#else - subjectHash = s->subjectNameHash; -#endif + return TLSX_UseTruncatedHMAC(&ctx->extensions, ctx->heap); +} - if (AlreadySigner(cm, subjectHash)) { - FreeSigner(s, cm->heap); - return 0; - } +#endif /* NO_WOLFSSL_CLIENT */ +#endif /* HAVE_TRUNCATED_HMAC */ - row = HashSigner(subjectHash); +/* Elliptic Curves */ +#if defined(HAVE_SUPPORTED_CURVES) - if (wc_LockMutex(&cm->caLock) != 0) - return BAD_MUTEX_E; +static int isValidCurveGroup(word16 name) +{ + switch (name) { + case WOLFSSL_ECC_SECP160K1: + case WOLFSSL_ECC_SECP160R1: + case WOLFSSL_ECC_SECP160R2: + case WOLFSSL_ECC_SECP192K1: + case WOLFSSL_ECC_SECP192R1: + case WOLFSSL_ECC_SECP224K1: + case WOLFSSL_ECC_SECP224R1: + case WOLFSSL_ECC_SECP256K1: + case WOLFSSL_ECC_SECP256R1: + case WOLFSSL_ECC_SECP384R1: + case WOLFSSL_ECC_SECP521R1: + case WOLFSSL_ECC_BRAINPOOLP256R1: + case WOLFSSL_ECC_BRAINPOOLP384R1: + case WOLFSSL_ECC_BRAINPOOLP512R1: + case WOLFSSL_ECC_SM2P256V1: + case WOLFSSL_ECC_X25519: + case WOLFSSL_ECC_X448: + case WOLFSSL_ECC_BRAINPOOLP256R1TLS13: + case WOLFSSL_ECC_BRAINPOOLP384R1TLS13: + case WOLFSSL_ECC_BRAINPOOLP512R1TLS13: - signers = cm->caTable[row]; - s->next = signers; - cm->caTable[row] = s; + case WOLFSSL_FFDHE_2048: + case WOLFSSL_FFDHE_3072: + case WOLFSSL_FFDHE_4096: + case WOLFSSL_FFDHE_6144: + case WOLFSSL_FFDHE_8192: - wc_UnLockMutex(&cm->caLock); - return 0; +#ifdef WOLFSSL_HAVE_MLKEM +#ifndef WOLFSSL_NO_ML_KEM + case WOLFSSL_ML_KEM_512: + case WOLFSSL_ML_KEM_768: + case WOLFSSL_ML_KEM_1024: + #if defined(WOLFSSL_WC_MLKEM) || defined(HAVE_LIBOQS) + case WOLFSSL_SECP256R1MLKEM512: + case WOLFSSL_SECP384R1MLKEM768: + case WOLFSSL_SECP521R1MLKEM1024: + case WOLFSSL_SECP384R1MLKEM1024: + case WOLFSSL_X25519MLKEM512: + case WOLFSSL_X448MLKEM768: + case WOLFSSL_X25519MLKEM768: + case WOLFSSL_SECP256R1MLKEM768: + #endif +#endif /* !WOLFSSL_NO_ML_KEM */ +#ifdef WOLFSSL_MLKEM_KYBER + case WOLFSSL_KYBER_LEVEL1: + case WOLFSSL_KYBER_LEVEL3: + case WOLFSSL_KYBER_LEVEL5: + #if defined(WOLFSSL_WC_MLKEM) || defined(HAVE_LIBOQS) + case WOLFSSL_P256_KYBER_LEVEL1: + case WOLFSSL_P384_KYBER_LEVEL3: + case WOLFSSL_P521_KYBER_LEVEL5: + case WOLFSSL_X25519_KYBER_LEVEL1: + case WOLFSSL_X448_KYBER_LEVEL3: + case WOLFSSL_X25519_KYBER_LEVEL3: + case WOLFSSL_P256_KYBER_LEVEL3: + #endif +#endif /* WOLFSSL_MLKEM_KYBER */ +#endif + return 1; + + default: + return 0; + } } -/* owns der, internal now uses too */ -/* type flag ids from user or from chain received during verify - don't allow chain ones to be added w/o isCA extension */ -int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) +int wolfSSL_UseSupportedCurve(WOLFSSL* ssl, word16 name) { - int ret; - Signer* signer = NULL; - word32 row; - byte* subjectHash; - WC_DECLARE_VAR(cert, DecodedCert, 1, 0); - DerBuffer* der = *pDer; - - WOLFSSL_MSG_CERT_LOG("Adding a CA"); - - if (cm == NULL) { - FreeDer(pDer); + if (ssl == NULL || !isValidCurveGroup(name)) return BAD_FUNC_ARG; - } - #ifdef WOLFSSL_SMALL_STACK - cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); - if (cert == NULL) { - FreeDer(pDer); - return MEMORY_E; - } - #endif + ssl->options.userCurves = 1; +#if defined(NO_TLS) + return WOLFSSL_FAILURE; +#else + return TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap); +#endif /* NO_TLS */ +} - InitDecodedCert(cert, der->buffer, der->length, cm->heap); -#ifdef WC_ASN_UNKNOWN_EXT_CB - if (cm->unknownExtCallback != NULL) { - wc_SetUnknownExtCallback(cert, cm->unknownExtCallback); - } -#endif +int wolfSSL_CTX_UseSupportedCurve(WOLFSSL_CTX* ctx, word16 name) +{ + if (ctx == NULL || !isValidCurveGroup(name)) + return BAD_FUNC_ARG; - WOLFSSL_MSG_CERT("\tParsing new CA"); - ret = ParseCert(cert, CA_TYPE, verify, cm); + ctx->userCurves = 1; +#if defined(NO_TLS) + return WOLFSSL_FAILURE; +#else + return TLSX_UseSupportedCurve(&ctx->extensions, name, ctx->heap); +#endif /* NO_TLS */ +} - WOLFSSL_MSG("\tParsed new CA"); -#ifdef WOLFSSL_DEBUG_CERTS - { - const char* err_msg; - if (ret == 0) { - WOLFSSL_MSG_CERT_EX(WOLFSSL_MSG_CERT_INDENT "issuer: '%s'", - cert->issuer); - WOLFSSL_MSG_CERT_EX(WOLFSSL_MSG_CERT_INDENT "subject: '%s'", - cert->subject); +#if defined(OPENSSL_EXTRA) +int wolfSSL_CTX_set1_groups(WOLFSSL_CTX* ctx, int* groups, + int count) +{ + int i; + int _groups[WOLFSSL_MAX_GROUP_COUNT]; + WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); + if (count == 0) { + WOLFSSL_MSG("Group count is zero"); + return WOLFSSL_FAILURE; + } + for (i = 0; i < count; i++) { + if (isValidCurveGroup((word16)groups[i])) { + _groups[i] = groups[i]; } +#ifdef HAVE_ECC else { - WOLFSSL_MSG_CERT( - WOLFSSL_MSG_CERT_INDENT "Failed during parse of new CA"); - err_msg = wc_GetErrorString(ret); - WOLFSSL_MSG_CERT_EX(WOLFSSL_MSG_CERT_INDENT "error ret: %d; %s", - ret, err_msg); + /* groups may be populated with curve NIDs */ + int oid = (int)nid2oid(groups[i], oidCurveType); + int name = (int)GetCurveByOID(oid); + if (name == 0) { + WOLFSSL_MSG("Invalid group name"); + return WOLFSSL_FAILURE; + } + _groups[i] = name; } - } -#endif /* WOLFSSL_DEBUG_CERTS */ - -#ifndef NO_SKID - subjectHash = cert->extSubjKeyId; #else - subjectHash = cert->subjectHash; -#endif - - /* check CA key size */ - if (verify && (ret == 0 )) { - switch (cert->keyOID) { - #ifndef NO_RSA - #ifdef WC_RSA_PSS - case RSAPSSk: - #endif - case RSAk: - if (cm->minRsaKeySz < 0 || - cert->pubKeySize < (word16)cm->minRsaKeySz) { - ret = RSA_KEY_SIZE_E; - WOLFSSL_MSG_CERT_LOG("\tCA RSA key size error"); - WOLFSSL_MSG_CERT_EX("\tCA RSA pubKeySize = %d; " - "minRsaKeySz = %d", - cert->pubKeySize, cm->minRsaKeySz); - } - break; - #endif /* !NO_RSA */ - #ifdef HAVE_ECC - case ECDSAk: - if (cm->minEccKeySz < 0 || - cert->pubKeySize < (word16)cm->minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG_CERT_LOG("\tCA ECC key size error"); - WOLFSSL_MSG_CERT_EX("\tCA ECC pubKeySize = %d; " - "minEccKeySz = %d", - cert->pubKeySize, cm->minEccKeySz); - } - break; - #endif /* HAVE_ECC */ - #ifdef HAVE_ED25519 - case ED25519k: - if (cm->minEccKeySz < 0 || - ED25519_KEY_SIZE < (word16)cm->minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("\tCA ECC key size error"); - } - break; - #endif /* HAVE_ED25519 */ - #ifdef HAVE_ED448 - case ED448k: - if (cm->minEccKeySz < 0 || - ED448_KEY_SIZE < (word16)cm->minEccKeySz) { - ret = ECC_KEY_SIZE_E; - WOLFSSL_MSG("\tCA ECC key size error"); - } - break; - #endif /* HAVE_ED448 */ - #if defined(HAVE_FALCON) - case FALCON_LEVEL1k: - if (cm->minFalconKeySz < 0 || - FALCON_LEVEL1_KEY_SIZE < (word16)cm->minFalconKeySz) { - ret = FALCON_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Falcon level 1 key size error"); - } - break; - case FALCON_LEVEL5k: - if (cm->minFalconKeySz < 0 || - FALCON_LEVEL5_KEY_SIZE < (word16)cm->minFalconKeySz) { - ret = FALCON_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Falcon level 5 key size error"); - } - break; - #endif /* HAVE_FALCON */ - #if defined(HAVE_DILITHIUM) - #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT - case DILITHIUM_LEVEL2k: - if (cm->minDilithiumKeySz < 0 || - DILITHIUM_LEVEL2_KEY_SIZE < (word16)cm->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Dilithium level 2 key size error"); - } - break; - case DILITHIUM_LEVEL3k: - if (cm->minDilithiumKeySz < 0 || - DILITHIUM_LEVEL3_KEY_SIZE < (word16)cm->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Dilithium level 3 key size error"); - } - break; - case DILITHIUM_LEVEL5k: - if (cm->minDilithiumKeySz < 0 || - DILITHIUM_LEVEL5_KEY_SIZE < (word16)cm->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Dilithium level 5 key size error"); - } - break; - #endif /* WOLFSSL_DILITHIUM_FIPS204_DRAFT */ - case ML_DSA_LEVEL2k: - if (cm->minDilithiumKeySz < 0 || - ML_DSA_LEVEL2_KEY_SIZE < (word16)cm->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Dilithium level 2 key size error"); - } - break; - case ML_DSA_LEVEL3k: - if (cm->minDilithiumKeySz < 0 || - ML_DSA_LEVEL3_KEY_SIZE < (word16)cm->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Dilithium level 3 key size error"); - } - break; - case ML_DSA_LEVEL5k: - if (cm->minDilithiumKeySz < 0 || - ML_DSA_LEVEL5_KEY_SIZE < (word16)cm->minDilithiumKeySz) { - ret = DILITHIUM_KEY_SIZE_E; - WOLFSSL_MSG("\tCA Dilithium level 5 key size error"); - } - break; - #endif /* HAVE_DILITHIUM */ - - default: - WOLFSSL_MSG("\tNo key size check done on CA"); - break; /* no size check if key type is not in switch */ + else { + WOLFSSL_MSG("Invalid group name"); + return WOLFSSL_FAILURE; } - } - - if (ret == 0 && cert->isCA == 0 && type != WOLFSSL_USER_CA && - type != WOLFSSL_TEMP_CA) { - WOLFSSL_MSG("\tCan't add as CA if not actually one"); - ret = NOT_CA_ERROR; - } -#ifndef ALLOW_INVALID_CERTSIGN - else if (ret == 0 && cert->isCA == 1 && type != WOLFSSL_USER_CA && - type != WOLFSSL_TEMP_CA && !cert->selfSigned && - (cert->extKeyUsage & KEYUSE_KEY_CERT_SIGN) == 0) { - /* Intermediate CA certs are required to have the keyCertSign - * extension set. User loaded root certs are not. */ - WOLFSSL_MSG("\tDoesn't have key usage certificate signing"); - ret = NOT_CA_ERROR; - } #endif - else if (ret == 0 && AlreadySigner(cm, subjectHash)) { - WOLFSSL_MSG("\tAlready have this CA, not adding again"); - (void)ret; - } - else if (ret == 0) { - /* take over signer parts */ - signer = MakeSigner(cm->heap); - if (!signer) - ret = MEMORY_ERROR; } - if (ret == 0 && signer != NULL) { - ret = FillSigner(signer, cert, type, der); + return wolfSSL_CTX_set_groups(ctx, _groups, count) == WOLFSSL_SUCCESS ? + WOLFSSL_SUCCESS : WOLFSSL_FAILURE; +} - if (ret == 0){ - #ifndef NO_SKID - row = HashSigner(signer->subjectKeyIdHash); - #else - row = HashSigner(signer->subjectNameHash); - #endif +int wolfSSL_set1_groups(WOLFSSL* ssl, int* groups, int count) +{ + int i; + int _groups[WOLFSSL_MAX_GROUP_COUNT]; + WOLFSSL_ENTER("wolfSSL_CTX_set1_groups"); + if (count == 0) { + WOLFSSL_MSG("Group count is zero"); + return WOLFSSL_FAILURE; + } + for (i = 0; i < count; i++) { + if (isValidCurveGroup((word16)groups[i])) { + _groups[i] = groups[i]; } - - #if defined(WOLFSSL_RENESAS_TSIP_TLS) || defined(WOLFSSL_RENESAS_FSPSM_TLS) - /* Verify CA by TSIP so that generated tsip key is going to */ - /* be able to be used for peer's cert verification */ - /* TSIP is only able to handle USER CA, and only one CA. */ - /* Therefore, it doesn't need to call TSIP again if there is already */ - /* verified CA. */ - if ( ret == 0 && signer != NULL ) { - signer->cm_idx = row; - if (type == WOLFSSL_USER_CA) { - if ((ret = wc_Renesas_cmn_RootCertVerify(cert->source, - cert->maxIdx, - cert->sigCtx.CertAtt.pubkey_n_start, - cert->sigCtx.CertAtt.pubkey_n_len - 1, - cert->sigCtx.CertAtt.pubkey_e_start, - cert->sigCtx.CertAtt.pubkey_e_len - 1, - row/* cm index */)) - < 0) - WOLFSSL_MSG("Renesas_RootCertVerify() failed"); - else - WOLFSSL_MSG("Renesas_RootCertVerify() succeed or skipped"); +#ifdef HAVE_ECC + else { + /* groups may be populated with curve NIDs */ + int oid = (int)nid2oid(groups[i], oidCurveType); + int name = (int)GetCurveByOID(oid); + if (name == 0) { + WOLFSSL_MSG("Invalid group name"); + return WOLFSSL_FAILURE; } + _groups[i] = name; } - #endif /* TSIP or SCE */ - - if (ret == 0 && wc_LockMutex(&cm->caLock) == 0) { - signer->next = cm->caTable[row]; - cm->caTable[row] = signer; /* takes ownership */ - wc_UnLockMutex(&cm->caLock); - if (cm->caCacheCallback) - cm->caCacheCallback(der->buffer, (int)der->length, type); - } +#else else { - WOLFSSL_MSG("\tCA Mutex Lock failed"); - ret = BAD_MUTEX_E; + WOLFSSL_MSG("Invalid group name"); + return WOLFSSL_FAILURE; } - } - - WOLFSSL_MSG("\tFreeing Parsed CA"); - FreeDecodedCert(cert); - if (ret != 0 && signer != NULL) - FreeSigner(signer, cm->heap); - WC_FREE_VAR_EX(cert, NULL, DYNAMIC_TYPE_DCERT); - WOLFSSL_MSG("\tFreeing der CA"); - FreeDer(pDer); - WOLFSSL_MSG("\t\tOK Freeing der CA"); - - WOLFSSL_LEAVE("AddCA", ret); - - return ret == 0 ? WOLFSSL_SUCCESS : ret; +#endif + } + return wolfSSL_set_groups(ssl, _groups, count) == WOLFSSL_SUCCESS ? + WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } +#endif /* OPENSSL_EXTRA */ +#endif /* HAVE_SUPPORTED_CURVES */ + +/* Application-Layer Protocol Negotiation */ +#ifdef HAVE_ALPN -/* Removes the CA with the passed in subject hash from the - cert manager's CA cert store. */ -int RemoveCA(WOLFSSL_CERT_MANAGER* cm, byte* hash, int type) +WOLFSSL_ABI +int wolfSSL_UseALPN(WOLFSSL* ssl, char *protocol_name_list, + word32 protocol_name_listSz, byte options) { - Signer* current; - Signer** prev; + char *list, *ptr = NULL, **token; + word16 len; + int idx = 0; int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - word32 row; - WOLFSSL_MSG("Removing a CA"); + WOLFSSL_ENTER("wolfSSL_UseALPN"); + + if (ssl == NULL || protocol_name_list == NULL) + return BAD_FUNC_ARG; - if (cm == NULL || hash == NULL) { + if (protocol_name_listSz > (WOLFSSL_MAX_ALPN_NUMBER * + WOLFSSL_MAX_ALPN_PROTO_NAME_LEN + + WOLFSSL_MAX_ALPN_NUMBER)) { + WOLFSSL_MSG("Invalid arguments, protocol name list too long"); return BAD_FUNC_ARG; } - row = HashSigner(hash); + if (!(options & WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) && + !(options & WOLFSSL_ALPN_FAILED_ON_MISMATCH)) { + WOLFSSL_MSG("Invalid arguments, options not supported"); + return BAD_FUNC_ARG; + } + - if (wc_LockMutex(&cm->caLock) != 0) { - return BAD_MUTEX_E; + list = (char *)XMALLOC(protocol_name_listSz+1, ssl->heap, + DYNAMIC_TYPE_ALPN); + if (list == NULL) { + WOLFSSL_MSG("Memory failure"); + return MEMORY_ERROR; } - current = cm->caTable[row]; - prev = &cm->caTable[row]; - while (current) { - byte* subjectHash; - #ifndef NO_SKID - subjectHash = current->subjectKeyIdHash; - #else - subjectHash = current->subjectNameHash; - #endif + token = (char **)XMALLOC(sizeof(char *) * (WOLFSSL_MAX_ALPN_NUMBER+1), + ssl->heap, DYNAMIC_TYPE_ALPN); + if (token == NULL) { + XFREE(list, ssl->heap, DYNAMIC_TYPE_ALPN); + WOLFSSL_MSG("Memory failure"); + return MEMORY_ERROR; + } + XMEMSET(token, 0, sizeof(char *) * (WOLFSSL_MAX_ALPN_NUMBER+1)); - if ((current->type == type) && - (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0)) { - *prev = current->next; - FreeSigner(current, cm->heap); - ret = WOLFSSL_SUCCESS; + XSTRNCPY(list, protocol_name_list, protocol_name_listSz); + list[protocol_name_listSz] = '\0'; + + /* read all protocol name from the list */ + token[idx] = XSTRTOK(list, ",", &ptr); + while (idx < WOLFSSL_MAX_ALPN_NUMBER && token[idx] != NULL) + token[++idx] = XSTRTOK(NULL, ",", &ptr); + + /* add protocol name list in the TLS extension in reverse order */ + while ((idx--) > 0) { + len = (word16)XSTRLEN(token[idx]); + + ret = TLSX_UseALPN(&ssl->extensions, token[idx], len, options, + ssl->heap); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("TLSX_UseALPN failure"); break; } - prev = ¤t->next; - current = current->next; } - wc_UnLockMutex(&cm->caLock); - WOLFSSL_LEAVE("RemoveCA", ret); + XFREE(token, ssl->heap, DYNAMIC_TYPE_ALPN); + XFREE(list, ssl->heap, DYNAMIC_TYPE_ALPN); return ret; } +int wolfSSL_ALPN_GetProtocol(WOLFSSL* ssl, char **protocol_name, word16 *size) +{ + return TLSX_ALPN_GetRequest(ssl ? ssl->extensions : NULL, + (void **)protocol_name, size); +} -/* Sets the CA with the passed in subject hash - to the provided type. */ -int SetCAType(WOLFSSL_CERT_MANAGER* cm, byte* hash, int type) +int wolfSSL_ALPN_GetPeerProtocol(WOLFSSL* ssl, char **list, word16 *listSz) { - Signer* current; - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - word32 row; + int i, len; + char *p; + byte *s; - WOLFSSL_MSG_EX("Setting CA to type %d", type); + if (ssl == NULL || list == NULL || listSz == NULL) + return BAD_FUNC_ARG; - if (cm == NULL || hash == NULL || - type < WOLFSSL_USER_CA || type > WOLFSSL_USER_INTER) { - return ret; - } + if (ssl->alpn_peer_requested == NULL + || ssl->alpn_peer_requested_length == 0) + return BUFFER_ERROR; - row = HashSigner(hash); + /* ssl->alpn_peer_requested are the original bytes sent in a ClientHello, + * formatted as (len-byte chars+)+. To turn n protocols into a + * comma-separated C string, one needs (n-1) commas and a final 0 byte + * which has the same length as the original. + * The returned length is the strlen() of the C string, so -1 of that. */ + *listSz = ssl->alpn_peer_requested_length-1; + *list = p = (char *)XMALLOC(ssl->alpn_peer_requested_length, ssl->heap, + DYNAMIC_TYPE_TLSX); + if (p == NULL) + return MEMORY_ERROR; - if (wc_LockMutex(&cm->caLock) != 0) { - return ret; + for (i = 0, s = ssl->alpn_peer_requested; + i < ssl->alpn_peer_requested_length; + p += len, i += len) + { + if (i) + *p++ = ','; + len = s[i++]; + /* guard against bad length bytes. */ + if (i + len > ssl->alpn_peer_requested_length) { + XFREE(*list, ssl->heap, DYNAMIC_TYPE_TLSX); + *list = NULL; + return WOLFSSL_FAILURE; + } + XMEMCPY(p, s + i, (size_t)len); } - current = cm->caTable[row]; - while (current) { - byte* subjectHash; + *p = 0; - #ifndef NO_SKID - subjectHash = current->subjectKeyIdHash; - #else - subjectHash = current->subjectNameHash; - #endif + return WOLFSSL_SUCCESS; +} - if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { - current->type = (byte)type; - ret = WOLFSSL_SUCCESS; - break; - } - current = current->next; + +/* used to free memory allocated by wolfSSL_ALPN_GetPeerProtocol */ +int wolfSSL_ALPN_FreePeerProtocol(WOLFSSL* ssl, char **list) +{ + if (ssl == NULL) { + return BAD_FUNC_ARG; } - wc_UnLockMutex(&cm->caLock); - WOLFSSL_LEAVE("SetCAType", ret); + XFREE(*list, ssl->heap, DYNAMIC_TYPE_TLSX); + *list = NULL; - return ret; + return WOLFSSL_SUCCESS; } -#endif /* !NO_CERTS */ +#endif /* HAVE_ALPN */ -#if defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_OPENSSL_RAND_CB) -static int wolfSSL_RAND_InitMutex(void); -#endif +/* Secure Renegotiation */ +#ifdef HAVE_SERVER_RENEGOTIATION_INFO -/* If we don't have static mutex initializers, but we do have static atomic - * initializers, activate WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS to leverage - * the latter. - * - * See further explanation below in wolfSSL_Init(). - */ -#ifndef WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS - #if !defined(WOLFSSL_MUTEX_INITIALIZER) && !defined(SINGLE_THREADED) && \ - defined(WOLFSSL_ATOMIC_OPS) && defined(WOLFSSL_ATOMIC_INITIALIZER) - #define WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS 1 - #else - #define WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS 0 - #endif -#elif defined(WOLFSSL_MUTEX_INITIALIZER) || defined(SINGLE_THREADED) - #undef WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS - #define WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS 0 -#endif +/* user is forcing ability to use secure renegotiation, we discourage it */ +int wolfSSL_UseSecureRenegotiation(WOLFSSL* ssl) +{ + int ret = WC_NO_ERR_TRACE(BAD_FUNC_ARG); +#if defined(NO_TLS) + (void)ssl; +#else + if (ssl) + ret = TLSX_UseSecureRenegotiation(&ssl->extensions, ssl->heap); + else + ret = BAD_FUNC_ARG; -#if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS - #ifndef WOLFSSL_ATOMIC_OPS - #error WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS requires WOLFSSL_ATOMIC_OPS - #endif - #ifndef WOLFSSL_ATOMIC_INITIALIZER - #error WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS requires WOLFSSL_ATOMIC_INITIALIZER - #endif - static wolfSSL_Atomic_Int inits_count_mutex_atomic_initing_flag = - WOLFSSL_ATOMIC_INITIALIZER(0); -#endif /* WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS && !WOLFSSL_MUTEX_INITIALIZER */ + if (ret == WOLFSSL_SUCCESS) { + TLSX* extension = TLSX_Find(ssl->extensions, TLSX_RENEGOTIATION_INFO); -#if defined(OPENSSL_EXTRA) && defined(HAVE_ATEXIT) -static void AtExitCleanup(void) -{ - if (initRefCount > 0) { - initRefCount = 1; - (void)wolfSSL_Cleanup(); -#if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS - if (inits_count_mutex_valid == 1) { - (void)wc_FreeMutex(&inits_count_mutex); - inits_count_mutex_valid = 0; - inits_count_mutex_atomic_initing_flag = 0; - } -#endif + if (extension) + ssl->secure_renegotiation = (SecureRenegotiation*)extension->data; } +#endif /* !NO_TLS */ + return ret; } -#endif -WOLFSSL_ABI -int wolfSSL_Init(void) +int wolfSSL_CTX_UseSecureRenegotiation(WOLFSSL_CTX* ctx) { - int ret = WOLFSSL_SUCCESS; -#if !defined(NO_SESSION_CACHE) && defined(ENABLE_SESSION_CACHE_ROW_LOCK) - int i; -#endif - - WOLFSSL_ENTER("wolfSSL_Init"); + if (ctx == NULL) + return BAD_FUNC_ARG; -#if defined(LIBWOLFSSL_CMAKE_OUTPUT) - WOLFSSL_MSG(LIBWOLFSSL_CMAKE_OUTPUT); -#else - WOLFSSL_MSG("No extra wolfSSL cmake messages found"); -#endif + ctx->useSecureReneg = 1; + return WOLFSSL_SUCCESS; +} -#ifndef WOLFSSL_MUTEX_INITIALIZER - if (inits_count_mutex_valid == 0) { - #if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS +#ifdef HAVE_SECURE_RENEGOTIATION +/* do a secure renegotiation handshake, user forced, we discourage */ +static int _Rehandshake(WOLFSSL* ssl) +{ + int ret; - /* Without this mitigation, if two threads enter wolfSSL_Init() at the - * same time, and both see zero inits_count_mutex_valid, then both will - * run wc_InitMutex(&inits_count_mutex), leading to process corruption - * or (best case) a resource leak. - * - * When WOLFSSL_ATOMIC_INITIALIZER() is available, we can mitigate this - * by use an atomic counting int as a mutex. - */ + if (ssl == NULL) + return BAD_FUNC_ARG; - if (wolfSSL_Atomic_Int_FetchAdd(&inits_count_mutex_atomic_initing_flag, - 1) != 0) - { - (void)wolfSSL_Atomic_Int_FetchSub( - &inits_count_mutex_atomic_initing_flag, 1); - return DEADLOCK_AVERTED_E; - } - #endif /* WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS */ - if (wc_InitMutex(&inits_count_mutex) != 0) { - WOLFSSL_MSG("Bad Init Mutex count"); - #if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS - (void)wolfSSL_Atomic_Int_FetchSub( - &inits_count_mutex_atomic_initing_flag, 1); - #endif - return BAD_MUTEX_E; - } - else { - inits_count_mutex_valid = 1; - } + if (IsAtLeastTLSv1_3(ssl->version)) { + WOLFSSL_MSG("Secure Renegotiation not supported in TLS 1.3"); + return SECURE_RENEGOTIATION_E; } -#endif /* !WOLFSSL_MUTEX_INITIALIZER */ - if (wc_LockMutex(&inits_count_mutex) != 0) { - WOLFSSL_MSG("Bad Lock Mutex count"); - return BAD_MUTEX_E; + if (ssl->secure_renegotiation == NULL) { + WOLFSSL_MSG("Secure Renegotiation not forced on by user"); + return SECURE_RENEGOTIATION_E; + } + + if (ssl->secure_renegotiation->enabled == 0) { + WOLFSSL_MSG("Secure Renegotiation not enabled at extension level"); + return SECURE_RENEGOTIATION_E; } -#if FIPS_VERSION_GE(5,1) - if ((ret == WOLFSSL_SUCCESS) && (initRefCount == 0)) { - ret = wolfCrypt_SetPrivateKeyReadEnable_fips(1, WC_KEYTYPE_ALL); - if (ret == 0) - ret = WOLFSSL_SUCCESS; +#ifdef WOLFSSL_DTLS + if (ssl->options.dtls && ssl->keys.dtls_epoch == 0xFFFF) { + WOLFSSL_MSG("Secure Renegotiation not allowed. Epoch would wrap"); + return SECURE_RENEGOTIATION_E; } #endif - if ((ret == WOLFSSL_SUCCESS) && (initRefCount == 0)) { - /* Initialize crypto for use with TLS connection */ - - if (wolfCrypt_Init() != 0) { - WOLFSSL_MSG("Bad wolfCrypt Init"); - ret = WC_INIT_E; - } + /* If the client started the renegotiation, the server will already + * have processed the client's hello. */ + if (ssl->options.side != WOLFSSL_SERVER_END || + ssl->options.acceptState != ACCEPT_FIRST_REPLY_DONE) { -#if defined(HAVE_GLOBAL_RNG) && !defined(WOLFSSL_MUTEX_INITIALIZER) - if (ret == WOLFSSL_SUCCESS) { - if (wc_InitMutex(&globalRNGMutex) != 0) { - WOLFSSL_MSG("Bad Init Mutex rng"); - ret = BAD_MUTEX_E; + if (ssl->options.handShakeState != HANDSHAKE_DONE) { + if (!ssl->options.handShakeDone) { + WOLFSSL_MSG("Can't renegotiate until initial " + "handshake complete"); + return SECURE_RENEGOTIATION_E; } else { - globalRNGMutex_valid = 1; + WOLFSSL_MSG("Renegotiation already started. " + "Moving it forward."); + ret = wolfSSL_negotiate(ssl); + if (ret == WOLFSSL_SUCCESS) + ssl->secure_rene_count++; + return ret; } } -#endif - #ifdef WC_RNG_SEED_CB - wc_SetSeed_Cb(WC_GENERATE_SEED_DEFAULT); - #endif + /* reset handshake states */ + ssl->options.sendVerify = 0; + ssl->options.serverState = NULL_STATE; + ssl->options.clientState = NULL_STATE; + ssl->options.connectState = CONNECT_BEGIN; + ssl->options.acceptState = ACCEPT_BEGIN_RENEG; + ssl->options.handShakeState = NULL_STATE; + ssl->options.processReply = 0; /* TODO, move states in internal.h */ -#ifdef OPENSSL_EXTRA - #ifndef WOLFSSL_NO_OPENSSL_RAND_CB - if ((ret == WOLFSSL_SUCCESS) && (wolfSSL_RAND_InitMutex() != 0)) { - ret = BAD_MUTEX_E; - } - #endif - if ((ret == WOLFSSL_SUCCESS) && - (wolfSSL_RAND_seed(NULL, 0) != WOLFSSL_SUCCESS)) { - WOLFSSL_MSG("wolfSSL_RAND_seed failed"); - ret = WC_INIT_E; - } -#endif + XMEMSET(&ssl->msgsReceived, 0, sizeof(ssl->msgsReceived)); -#ifndef NO_SESSION_CACHE - #ifdef ENABLE_SESSION_CACHE_ROW_LOCK - for (i = 0; i < SESSION_ROWS; ++i) { - SessionCache[i].lock_valid = 0; - } - for (i = 0; (ret == WOLFSSL_SUCCESS) && (i < SESSION_ROWS); ++i) { - if (wc_InitRwLock(&SessionCache[i].row_lock) != 0) { - WOLFSSL_MSG("Bad Init Mutex session"); - ret = BAD_MUTEX_E; - } - else { - SessionCache[i].lock_valid = 1; - } - } - #else - if (ret == WOLFSSL_SUCCESS) { - if (wc_InitRwLock(&session_lock) != 0) { - WOLFSSL_MSG("Bad Init Mutex session"); - ret = BAD_MUTEX_E; - } - else { - session_lock_valid = 1; - } - } - #endif - #ifndef NO_CLIENT_CACHE - #ifndef WOLFSSL_MUTEX_INITIALIZER - if (ret == WOLFSSL_SUCCESS) { - if (wc_InitMutex(&clisession_mutex) != 0) { - WOLFSSL_MSG("Bad Init Mutex session"); - ret = BAD_MUTEX_E; - } - else { - clisession_mutex_valid = 1; + ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED; + +#if !defined(NO_WOLFSSL_SERVER) && !defined(WOLFSSL_NO_TLS12) + if (ssl->options.side == WOLFSSL_SERVER_END) { + ret = SendHelloRequest(ssl); + if (ret != 0) { + ssl->error = ret; + return WOLFSSL_FATAL_ERROR; } } - #endif - #endif -#endif -#if defined(OPENSSL_EXTRA) && defined(HAVE_ATEXIT) - /* OpenSSL registers cleanup using atexit */ - if ((ret == WOLFSSL_SUCCESS) && (atexit(AtExitCleanup) != 0)) { - WOLFSSL_MSG("Bad atexit registration"); - ret = WC_INIT_E; +#endif /* !NO_WOLFSSL_SERVER && !WOLFSSL_NO_TLS12 */ + + ret = InitHandshakeHashes(ssl); + if (ret != 0) { + ssl->error = ret; + return WOLFSSL_FATAL_ERROR; } -#endif } + ret = wolfSSL_negotiate(ssl); + if (ret == WOLFSSL_SUCCESS) + ssl->secure_rene_count++; + return ret; +} -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) - /* System wide crypto policy disabled by default. */ - XMEMSET(&crypto_policy, 0, sizeof(crypto_policy)); -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - if (ret == WOLFSSL_SUCCESS) { - initRefCount = initRefCount + 1; +/* do a secure renegotiation handshake, user forced, we discourage */ +int wolfSSL_Rehandshake(WOLFSSL* ssl) +{ + int ret; + WOLFSSL_ENTER("wolfSSL_Rehandshake"); + + if (ssl == NULL) + return WOLFSSL_FAILURE; + +#ifdef HAVE_SESSION_TICKET + ret = WOLFSSL_SUCCESS; +#endif + + if (ssl->options.side == WOLFSSL_SERVER_END) { + /* Reset option to send certificate verify. */ + ssl->options.sendVerify = 0; + /* Reset resuming flag to do full secure handshake. */ + ssl->options.resuming = 0; } else { - initRefCount = 1; /* Force cleanup */ + /* Reset resuming flag to do full secure handshake. */ + ssl->options.resuming = 0; + #if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_CLIENT) + /* Clearing the ticket. */ + ret = wolfSSL_UseSessionTicket(ssl); + #endif } + /* CLIENT/SERVER: Reset peer authentication for full secure handshake. */ + ssl->options.peerAuthGood = 0; - wc_UnLockMutex(&inits_count_mutex); - - if (ret != WOLFSSL_SUCCESS) { - (void)wolfSSL_Cleanup(); /* Ignore any error from cleanup */ - } +#ifdef HAVE_SESSION_TICKET + if (ret == WOLFSSL_SUCCESS) +#endif + ret = _Rehandshake(ssl); return ret; } -#if defined(WOLFSSL_SYS_CRYPTO_POLICY) -/* Helper function for wolfSSL_crypto_policy_enable and - * wolfSSL_crypto_policy_enable_buffer. - * - * Parses the crypto policy string, verifies values, - * and sets in global crypto policy struct. Not thread - * safe. String length has already been verified. - * - * Returns WOLFSSL_SUCCESS on success. - * Returns CRYPTO_POLICY_FORBIDDEN if already enabled. - * Returns < 0 on misc error. - * */ -static int crypto_policy_parse(void) + +#ifndef NO_WOLFSSL_CLIENT + +/* do a secure resumption handshake, user forced, we discourage */ +int wolfSSL_SecureResume(WOLFSSL* ssl) { - const char * hdr = WOLFSSL_SECLEVEL_STR; - int sec_level = 0; - size_t i = 0; + WOLFSSL_ENTER("wolfSSL_SecureResume"); - /* All policies should begin with "@SECLEVEL=" (N={0..5}) followed - * by bulk cipher list. */ - if (XMEMCMP(crypto_policy.str, hdr, strlen(hdr)) != 0) { - WOLFSSL_MSG("error: crypto policy: invalid header"); - return WOLFSSL_BAD_FILE; - } + if (ssl == NULL) + return BAD_FUNC_ARG; - { - /* Extract the security level. */ - char * policy_mem = crypto_policy.str; - policy_mem += strlen(hdr); - sec_level = (int) (*policy_mem - '0'); + if (ssl->options.side == WOLFSSL_SERVER_END) { + ssl->error = SIDE_ERROR; + return WOLFSSL_FATAL_ERROR; } - if (sec_level < MIN_WOLFSSL_SEC_LEVEL || - sec_level > MAX_WOLFSSL_SEC_LEVEL) { - WOLFSSL_MSG_EX("error: invalid SECLEVEL: %d", sec_level); - return WOLFSSL_BAD_FILE; - } + return _Rehandshake(ssl); +} - /* Remove trailing '\r' or '\n'. */ - for (i = 0; i < MAX_WOLFSSL_CRYPTO_POLICY_SIZE; ++i) { - if (crypto_policy.str[i] == '\0') { - break; - } +#endif /* NO_WOLFSSL_CLIENT */ + +#endif /* HAVE_SECURE_RENEGOTIATION */ + +long wolfSSL_SSL_get_secure_renegotiation_support(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_SSL_get_secure_renegotiation_support"); + + if (!ssl || !ssl->secure_renegotiation) + return WOLFSSL_FAILURE; + return ssl->secure_renegotiation->enabled; +} + +#endif /* HAVE_SECURE_RENEGOTIATION_INFO */ + +#if !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \ + defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK) +WOLFSSL_API int wolfSSL_get_scr_check_enabled(const WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_get_scr_check_enabled"); + + if (ssl == NULL) + return BAD_FUNC_ARG; + + return ssl->scr_check_enabled; +} + +WOLFSSL_API int wolfSSL_set_scr_check_enabled(WOLFSSL* ssl, byte enabled) +{ + WOLFSSL_ENTER("wolfSSL_set_scr_check_enabled"); + + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->scr_check_enabled = !!enabled; + return WOLFSSL_SUCCESS; +} +#endif - if (crypto_policy.str[i] == '\r' || crypto_policy.str[i] == '\n') { - crypto_policy.str[i] = '\0'; - break; - } - } +#if defined(HAVE_SESSION_TICKET) +/* Session Ticket */ - #if defined(DEBUG_WOLFSSL_VERBOSE) - WOLFSSL_MSG_EX("info: SECLEVEL=%d", sec_level); - WOLFSSL_MSG_EX("info: using crypto-policy file: %s, %ld", policy_file, sz); - #endif /* DEBUG_WOLFSSL_VERBOSE */ +#if !defined(NO_WOLFSSL_SERVER) +int wolfSSL_CTX_NoTicketTLSv12(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; - crypto_policy.secLevel = sec_level; - crypto_policy.enabled = 1; + ctx->noTicketTls12 = 1; return WOLFSSL_SUCCESS; } -#ifndef NO_FILESYSTEM -/* Enables wolfSSL system wide crypto-policy, using the given policy - * file arg. If NULL is passed, then the default system crypto-policy - * file that was set at configure time will be used instead. - * - * While enabled: - * - TLS methods, min key sizes, and cipher lists are all configured - * automatically by the policy. - * - Attempting to use lesser strength parameters will fail with - * error CRYPTO_POLICY_FORBIDDEN. - * - * Disable with wolfSSL_crypto_policy_disable. - * - * Note: the wolfSSL_crypto_policy_X API are not thread safe, and should - * only be called at program init time. - * - * Returns WOLFSSL_SUCCESS on success. - * Returns CRYPTO_POLICY_FORBIDDEN if already enabled. - * Returns < 0 on misc error. - * */ -int wolfSSL_crypto_policy_enable(const char * policy_file) +int wolfSSL_NoTicketTLSv12(WOLFSSL* ssl) { - XFILE file; - long sz = 0; - size_t n_read = 0; - - WOLFSSL_ENTER("wolfSSL_crypto_policy_enable"); + if (ssl == NULL) + return BAD_FUNC_ARG; - if (wolfSSL_crypto_policy_is_enabled()) { - WOLFSSL_MSG_EX("error: crypto policy already enabled: %s", - policy_file); - return CRYPTO_POLICY_FORBIDDEN; - } + ssl->options.noTicketTls12 = 1; - if (policy_file == NULL) { - /* Use the configure-time default if NULL passed. */ - policy_file = WC_STRINGIFY(WOLFSSL_CRYPTO_POLICY_FILE); - } + return WOLFSSL_SUCCESS; +} - if (policy_file == NULL || *policy_file == '\0') { - WOLFSSL_MSG("error: crypto policy empty file"); +/* WOLFSSL_SUCCESS on ok */ +int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx, SessionTicketEncCb cb) +{ + if (ctx == NULL) return BAD_FUNC_ARG; - } - - XMEMSET(&crypto_policy, 0, sizeof(crypto_policy)); - file = XFOPEN(policy_file, "rb"); + ctx->ticketEncCb = cb; - if (file == XBADFILE) { - WOLFSSL_MSG_EX("error: crypto policy file open failed: %s", - policy_file); - return WOLFSSL_BAD_FILE; - } + return WOLFSSL_SUCCESS; +} - if (XFSEEK(file, 0, XSEEK_END) != 0) { - WOLFSSL_MSG_EX("error: crypto policy file seek end failed: %s", - policy_file); - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } +/* set hint interval, WOLFSSL_SUCCESS on ok */ +int wolfSSL_CTX_set_TicketHint(WOLFSSL_CTX* ctx, int hint) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; - sz = XFTELL(file); + ctx->ticketHint = hint; - if (XFSEEK(file, 0, XSEEK_SET) != 0) { - WOLFSSL_MSG_EX("error: crypto policy file seek failed: %s", - policy_file); - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } + return WOLFSSL_SUCCESS; +} - if (sz <= 0 || sz > MAX_WOLFSSL_CRYPTO_POLICY_SIZE) { - WOLFSSL_MSG_EX("error: crypto policy file %s, invalid size: %ld", - policy_file, sz); - XFCLOSE(file); - return WOLFSSL_BAD_FILE; - } +/* set user context, WOLFSSL_SUCCESS on ok */ +int wolfSSL_CTX_set_TicketEncCtx(WOLFSSL_CTX* ctx, void* userCtx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; - n_read = XFREAD(crypto_policy.str, 1, sz, file); - XFCLOSE(file); + ctx->ticketEncCtx = userCtx; - if (n_read != (size_t) sz) { - WOLFSSL_MSG_EX("error: crypto policy file %s: read %zu, " - "expected %ld", policy_file, n_read, sz); - return WOLFSSL_BAD_FILE; - } + return WOLFSSL_SUCCESS; +} - crypto_policy.str[n_read] = '\0'; +/* get user context - returns userCtx on success, NULL on failure */ +void* wolfSSL_CTX_get_TicketEncCtx(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return NULL; - return crypto_policy_parse(); + return ctx->ticketEncCtx; } -#endif /* ! NO_FILESYSTEM */ -/* Same behavior as wolfSSL_crypto_policy_enable, but loads - * via memory buf instead of file. - * - * Returns WOLFSSL_SUCCESS on success. - * Returns CRYPTO_POLICY_FORBIDDEN if already enabled. - * Returns < 0 on misc error. - * */ -int wolfSSL_crypto_policy_enable_buffer(const char * buf) +#ifdef WOLFSSL_TLS13 +/* set the maximum number of tickets to send + * return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on fail + */ +int wolfSSL_CTX_set_num_tickets(WOLFSSL_CTX* ctx, size_t mxTickets) { - size_t sz = 0; + if (ctx == NULL) + return WOLFSSL_FAILURE; - WOLFSSL_ENTER("wolfSSL_crypto_policy_enable_buffer"); + ctx->maxTicketTls13 = (unsigned int)mxTickets; + return WOLFSSL_SUCCESS; +} - if (wolfSSL_crypto_policy_is_enabled()) { - WOLFSSL_MSG_EX("error: crypto policy already enabled"); - return CRYPTO_POLICY_FORBIDDEN; - } +/* get the maximum number of tickets to send + * return number of tickets set to be sent + */ +size_t wolfSSL_CTX_get_num_tickets(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return 0; - if (buf == NULL || *buf == '\0') { + return (size_t)ctx->maxTicketTls13; +} +#endif /* WOLFSSL_TLS13 */ +#endif /* !NO_WOLFSSL_SERVER */ + +#if !defined(NO_WOLFSSL_CLIENT) +int wolfSSL_UseSessionTicket(WOLFSSL* ssl) +{ + if (ssl == NULL) return BAD_FUNC_ARG; - } - sz = XSTRLEN(buf); + return TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap); +} - if (sz == 0 || sz > MAX_WOLFSSL_CRYPTO_POLICY_SIZE) { +int wolfSSL_CTX_UseSessionTicket(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) return BAD_FUNC_ARG; - } - - XMEMSET(&crypto_policy, 0, sizeof(crypto_policy)); - XMEMCPY(crypto_policy.str, buf, sz); - return crypto_policy_parse(); + return TLSX_UseSessionTicket(&ctx->extensions, NULL, ctx->heap); } -/* Returns whether the system wide crypto-policy is enabled. - * - * Returns 1 if enabled. - * 0 if disabled. - * */ -int wolfSSL_crypto_policy_is_enabled(void) +int wolfSSL_get_SessionTicket(WOLFSSL* ssl, byte* buf, word32* bufSz) { - WOLFSSL_ENTER("wolfSSL_crypto_policy_is_enabled"); + if (ssl == NULL || bufSz == NULL) + return BAD_FUNC_ARG; - return crypto_policy.enabled == 1; + if (*bufSz == 0 && buf == NULL) { + *bufSz = ssl->session->ticketLen; + return LENGTH_ONLY_E; + } + + if (buf == NULL) + return BAD_FUNC_ARG; + + if (ssl->session->ticketLen <= *bufSz) { + XMEMCPY(buf, ssl->session->ticket, ssl->session->ticketLen); + *bufSz = ssl->session->ticketLen; + } + else + *bufSz = 0; + + return WOLFSSL_SUCCESS; } -/* Disables the system wide crypto-policy. - * note: SSL and CTX structures already instantiated will - * keep their security policy parameters. This will only - * affect new instantiations. - * */ -void wolfSSL_crypto_policy_disable(void) +int wolfSSL_set_SessionTicket(WOLFSSL* ssl, const byte* buf, + word32 bufSz) { - WOLFSSL_ENTER("wolfSSL_crypto_policy_disable"); - crypto_policy.enabled = 0; - XMEMSET(&crypto_policy, 0, sizeof(crypto_policy)); - return; + if (ssl == NULL || (buf == NULL && bufSz > 0)) + return BAD_FUNC_ARG; + + if (bufSz > 0) { + /* Ticket will fit into static ticket */ + if (bufSz <= SESSION_TICKET_LEN) { + if (ssl->session->ticketLenAlloc > 0) { + XFREE(ssl->session->ticket, ssl->session->heap, + DYNAMIC_TYPE_SESSION_TICK); + ssl->session->ticketLenAlloc = 0; + ssl->session->ticket = ssl->session->staticTicket; + } + } + else { /* Ticket requires dynamic ticket storage */ + /* is dyn buffer big enough */ + if (ssl->session->ticketLen < bufSz) { + if (ssl->session->ticketLenAlloc > 0) { + XFREE(ssl->session->ticket, ssl->session->heap, + DYNAMIC_TYPE_SESSION_TICK); + } + ssl->session->ticket = (byte*)XMALLOC(bufSz, ssl->session->heap, + DYNAMIC_TYPE_SESSION_TICK); + if(ssl->session->ticket == NULL) { + ssl->session->ticket = ssl->session->staticTicket; + ssl->session->ticketLenAlloc = 0; + return MEMORY_ERROR; + } + ssl->session->ticketLenAlloc = (word16)bufSz; + } + } + XMEMCPY(ssl->session->ticket, buf, bufSz); + } + ssl->session->ticketLen = (word16)bufSz; + + return WOLFSSL_SUCCESS; } -/* Get the crypto-policy bulk cipher list string. - * String is not owned by caller, should not be freed. - * - * Returns pointer to bulk cipher list string. - * Returns NULL if NOT enabled, or on error. - * */ -const char * wolfSSL_crypto_policy_get_ciphers(void) + +int wolfSSL_set_SessionTicket_cb(WOLFSSL* ssl, + CallbackSessionTicket cb, void* ctx) { - WOLFSSL_ENTER("wolfSSL_crypto_policy_get_ciphers"); + if (ssl == NULL) + return BAD_FUNC_ARG; - if (crypto_policy.enabled == 1) { - /* The crypto policy config will have - * this form: - * "@SECLEVEL=2:kEECDH:kRSA..." */ - return crypto_policy.str; - } + ssl->session_ticket_cb = cb; + ssl->session_ticket_ctx = ctx; - return NULL; + return WOLFSSL_SUCCESS; } +#endif /* !NO_WOLFSSL_CLIENT */ -/* Get the configured crypto-policy security level. - * A security level of 0 does not impose any additional - * restrictions. - * - * Returns 1 - 5 if enabled. - * Returns 0 if NOT enabled. - * */ -int wolfSSL_crypto_policy_get_level(void) -{ - if (crypto_policy.enabled == 1) { - return crypto_policy.secLevel; - } +#endif /* HAVE_SESSION_TICKET */ - return 0; -} -/* Get security level from ssl structure. - * @param ssl a pointer to WOLFSSL structure - */ -int wolfSSL_get_security_level(const WOLFSSL * ssl) +#ifdef HAVE_EXTENDED_MASTER +#ifndef NO_WOLFSSL_CLIENT + +int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx) { - if (ssl == NULL) { + if (ctx == NULL) return BAD_FUNC_ARG; - } - return ssl->secLevel; + ctx->haveEMS = 0; + + return WOLFSSL_SUCCESS; } -#ifndef NO_WOLFSSL_STUB -/* - * Set security level (wolfSSL doesn't support setting the security level). - * - * The security level can only be set through a system wide crypto-policy - * with wolfSSL_crypto_policy_enable(). - * - * @param ssl a pointer to WOLFSSL structure - * @param level security level - */ -void wolfSSL_set_security_level(WOLFSSL * ssl, int level) + +int wolfSSL_DisableExtendedMasterSecret(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_set_security_level"); - (void)ssl; - (void)level; -} -#endif /* !NO_WOLFSSL_STUB */ + if (ssl == NULL) + return BAD_FUNC_ARG; -#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ + ssl->options.haveEMS = 0; + return WOLFSSL_SUCCESS; +} -#define WOLFSSL_SSL_LOAD_INCLUDED -#include +#endif +#endif -#ifndef NO_CERTS -#ifdef HAVE_CRL +#ifndef WOLFSSL_LEANPSK -int wolfSSL_CTX_LoadCRLBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, - long sz, int type) +int wolfSSL_send(WOLFSSL* ssl, const void* data, int sz, int flags) { - WOLFSSL_ENTER("wolfSSL_CTX_LoadCRLBuffer"); + int ret; + int oldFlags; - if (ctx == NULL) + WOLFSSL_ENTER("wolfSSL_send"); + + if (ssl == NULL || data == NULL || sz < 0) return BAD_FUNC_ARG; - return wolfSSL_CertManagerLoadCRLBuffer(ctx->cm, buff, sz, type); + oldFlags = ssl->wflags; + + ssl->wflags = flags; + ret = wolfSSL_write(ssl, data, sz); + ssl->wflags = oldFlags; + + WOLFSSL_LEAVE("wolfSSL_send", ret); + + return ret; } -int wolfSSL_LoadCRLBuffer(WOLFSSL* ssl, const unsigned char* buff, - long sz, int type) +int wolfSSL_recv(WOLFSSL* ssl, void* data, int sz, int flags) { - WOLFSSL_ENTER("wolfSSL_LoadCRLBuffer"); + int ret; + int oldFlags; + + WOLFSSL_ENTER("wolfSSL_recv"); - if (ssl == NULL || ssl->ctx == NULL) + if (ssl == NULL || data == NULL || sz < 0) return BAD_FUNC_ARG; - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerLoadCRLBuffer(SSL_CM(ssl), buff, sz, type); -} + oldFlags = ssl->rflags; -#endif /* HAVE_CRL */ + ssl->rflags = flags; + ret = wolfSSL_read(ssl, data, sz); + ssl->rflags = oldFlags; -#ifdef HAVE_OCSP -int wolfSSL_EnableOCSP(WOLFSSL* ssl, int options) + WOLFSSL_LEAVE("wolfSSL_recv", ret); + + return ret; +} +#endif + +int wolfSSL_SendUserCanceled(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_EnableOCSP"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerEnableOCSP(SSL_CM(ssl), options); + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + WOLFSSL_ENTER("wolfSSL_recv"); + + if (ssl != NULL) { + ssl->error = SendAlert(ssl, alert_warning, user_canceled); + if (ssl->error < 0) { + WOLFSSL_ERROR(ssl->error); + } + else { + ret = wolfSSL_shutdown(ssl); + } } - else - return BAD_FUNC_ARG; + + WOLFSSL_LEAVE("wolfSSL_SendUserCanceled", ret); + + return ret; } -int wolfSSL_DisableOCSP(WOLFSSL* ssl) +/* WOLFSSL_SUCCESS on ok */ +WOLFSSL_ABI +int wolfSSL_shutdown(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_DisableOCSP"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerDisableOCSP(SSL_CM(ssl)); + int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); + WOLFSSL_ENTER("wolfSSL_shutdown"); + + if (ssl == NULL) + return WOLFSSL_FATAL_ERROR; + + if (ssl->options.quietShutdown) { + WOLFSSL_MSG("quiet shutdown, no close notify sent"); + ret = WOLFSSL_SUCCESS; + } + else { + + /* Try to flush the buffer first, it might contain the alert */ + if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE) && + ssl->buffers.outputBuffer.length > 0) { + ret = SendBuffered(ssl); + if (ret != 0) { + ssl->error = ret; + /* for error tracing */ + if (ret != WC_NO_ERR_TRACE(WANT_WRITE)) + WOLFSSL_ERROR(ret); + ret = WOLFSSL_FATAL_ERROR; + WOLFSSL_LEAVE("wolfSSL_shutdown", ret); + return ret; + } + + ssl->error = WOLFSSL_ERROR_NONE; + /* we succeeded in sending the alert now */ + if (ssl->options.sentNotify) { + /* just after we send the alert, if we didn't receive the alert + * from the other peer yet, return WOLFSSL_STHUDOWN_NOT_DONE */ + if (!ssl->options.closeNotify) { + ret = WOLFSSL_SHUTDOWN_NOT_DONE; + WOLFSSL_LEAVE("wolfSSL_shutdown", ret); + return ret; + } + else { + ssl->options.shutdownDone = 1; + ret = WOLFSSL_SUCCESS; + } + } + } + + /* try to send close notify, not an error if can't */ + if (!ssl->options.isClosed && !ssl->options.connReset && + !ssl->options.sentNotify) { + ssl->error = SendAlert(ssl, alert_warning, close_notify); + + /* the alert is now sent or sitting in the buffer, + * where will be sent eventually */ + if (ssl->error == 0 || ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) + ssl->options.sentNotify = 1; + + if (ssl->error < 0) { + WOLFSSL_ERROR(ssl->error); + return WOLFSSL_FATAL_ERROR; + } + + if (ssl->options.closeNotify) { + ret = WOLFSSL_SUCCESS; + ssl->options.shutdownDone = 1; + } + else { + ret = WOLFSSL_SHUTDOWN_NOT_DONE; + WOLFSSL_LEAVE("wolfSSL_shutdown", ret); + return ret; + } + } + +#ifdef WOLFSSL_SHUTDOWNONCE + if (ssl->options.isClosed || ssl->options.connReset) { + /* Shutdown has already occurred. + * Caller is free to ignore this error. */ + return SSL_SHUTDOWN_ALREADY_DONE_E; + } +#endif + + /* wolfSSL_shutdown called again for bidirectional shutdown */ + if (ssl->options.sentNotify && !ssl->options.closeNotify) { + ret = ProcessReply(ssl); + if ((ret == WC_NO_ERR_TRACE(ZERO_RETURN)) || + (ret == WC_NO_ERR_TRACE(SOCKET_ERROR_E))) { + /* simulate OpenSSL behavior */ + ssl->options.shutdownDone = 1; + /* Clear error */ + ssl->error = WOLFSSL_ERROR_NONE; + ret = WOLFSSL_SUCCESS; + } + else if (ret == WC_NO_ERR_TRACE(MEMORY_E)) { + ret = WOLFSSL_FATAL_ERROR; + } + else if (ret == WC_NO_ERR_TRACE(WANT_READ)) { + ssl->error = ret; + ret = WOLFSSL_FATAL_ERROR; + } + else if (ssl->error == WOLFSSL_ERROR_NONE) { + ret = WOLFSSL_SHUTDOWN_NOT_DONE; + } + else { + WOLFSSL_ERROR(ssl->error); + ret = WOLFSSL_FATAL_ERROR; + } + } + } + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) + /* reset WOLFSSL structure state for possible reuse */ + if (ret == WOLFSSL_SUCCESS) { + if (wolfSSL_clear(ssl) != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("could not clear WOLFSSL"); + ret = WOLFSSL_FATAL_ERROR; + } } - else - return BAD_FUNC_ARG; -} +#endif + WOLFSSL_LEAVE("wolfSSL_shutdown", ret); -int wolfSSL_EnableOCSPStapling(WOLFSSL* ssl) -{ - WOLFSSL_ENTER("wolfSSL_EnableOCSPStapling"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerEnableOCSPStapling(SSL_CM(ssl)); - } - else - return BAD_FUNC_ARG; + return ret; } +#endif /* !NO_TLS */ -int wolfSSL_DisableOCSPStapling(WOLFSSL* ssl) +/* get current error state value */ +int wolfSSL_state(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_DisableOCSPStapling"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerDisableOCSPStapling(SSL_CM(ssl)); - } - else + if (ssl == NULL) { return BAD_FUNC_ARG; -} - -int wolfSSL_SetOCSP_OverrideURL(WOLFSSL* ssl, const char* url) -{ - WOLFSSL_ENTER("wolfSSL_SetOCSP_OverrideURL"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerSetOCSPOverrideURL(SSL_CM(ssl), url); } - else - return BAD_FUNC_ARG; + + return ssl->error; } -int wolfSSL_SetOCSP_Cb(WOLFSSL* ssl, - CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx) +WOLFSSL_ABI +int wolfSSL_get_error(WOLFSSL* ssl, int ret) { - WOLFSSL_ENTER("wolfSSL_SetOCSP_Cb"); - if (ssl) { - SSL_CM_WARNING(ssl); - ssl->ocspIOCtx = ioCbCtx; /* use SSL specific ioCbCtx */ - return wolfSSL_CertManagerSetOCSP_Cb(SSL_CM(ssl), - ioCb, respFreeCb, NULL); - } - else - return BAD_FUNC_ARG; -} + WOLFSSL_ENTER("wolfSSL_get_error"); -int wolfSSL_CTX_EnableOCSP(WOLFSSL_CTX* ctx, int options) -{ - WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSP"); - if (ctx) - return wolfSSL_CertManagerEnableOCSP(ctx->cm, options); - else + if (ret > 0) + return WOLFSSL_ERROR_NONE; + if (ssl == NULL) return BAD_FUNC_ARG; -} + WOLFSSL_LEAVE("wolfSSL_get_error", ssl->error); -int wolfSSL_CTX_DisableOCSP(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSP"); - if (ctx) - return wolfSSL_CertManagerDisableOCSP(ctx->cm); - else - return BAD_FUNC_ARG; + /* make sure converted types are handled in SetErrorString() too */ + if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) + return WOLFSSL_ERROR_WANT_READ; /* convert to OpenSSL type */ + else if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) + return WOLFSSL_ERROR_WANT_WRITE; /* convert to OpenSSL type */ + else if (ssl->error == WC_NO_ERR_TRACE(ZERO_RETURN) || + ssl->options.shutdownDone) + return WOLFSSL_ERROR_ZERO_RETURN; /* convert to OpenSSL type */ +#ifdef OPENSSL_EXTRA + else if (ssl->error == WC_NO_ERR_TRACE(MATCH_SUITE_ERROR)) + return WOLFSSL_ERROR_SYSCALL; /* convert to OpenSSL type */ + else if (ssl->error == WC_NO_ERR_TRACE(SOCKET_PEER_CLOSED_E)) + return WOLFSSL_ERROR_SYSCALL; /* convert to OpenSSL type */ +#endif + return ssl->error; } -int wolfSSL_CTX_SetOCSP_OverrideURL(WOLFSSL_CTX* ctx, const char* url) +/* retrieve alert history, WOLFSSL_SUCCESS on ok */ +int wolfSSL_get_alert_history(WOLFSSL* ssl, WOLFSSL_ALERT_HISTORY *h) { - WOLFSSL_ENTER("wolfSSL_SetOCSP_OverrideURL"); - if (ctx) - return wolfSSL_CertManagerSetOCSPOverrideURL(ctx->cm, url); - else - return BAD_FUNC_ARG; + if (ssl && h) { + *h = ssl->alert_history; + } + return WOLFSSL_SUCCESS; } - -int wolfSSL_CTX_SetOCSP_Cb(WOLFSSL_CTX* ctx, CbOCSPIO ioCb, - CbOCSPRespFree respFreeCb, void* ioCbCtx) +#ifdef OPENSSL_EXTRA +/* returns SSL_WRITING, SSL_READING or SSL_NOTHING */ +int wolfSSL_want(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_CTX_SetOCSP_Cb"); - if (ctx) - return wolfSSL_CertManagerSetOCSP_Cb(ctx->cm, ioCb, - respFreeCb, ioCbCtx); - else - return BAD_FUNC_ARG; + int rw_state = WOLFSSL_NOTHING; + if (ssl) { + if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) + rw_state = WOLFSSL_READING; + else if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) + rw_state = WOLFSSL_WRITING; + } + return rw_state; } +#endif -#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ - || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) -int wolfSSL_CTX_EnableOCSPStapling(WOLFSSL_CTX* ctx) +/* return TRUE if current error is want read */ +int wolfSSL_want_read(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSPStapling"); - if (ctx) - return wolfSSL_CertManagerEnableOCSPStapling(ctx->cm); - else - return BAD_FUNC_ARG; -} + WOLFSSL_ENTER("wolfSSL_want_read"); + if (ssl->error == WC_NO_ERR_TRACE(WANT_READ)) + return 1; -int wolfSSL_CTX_DisableOCSPStapling(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSPStapling"); - if (ctx) - return wolfSSL_CertManagerDisableOCSPStapling(ctx->cm); - else - return BAD_FUNC_ARG; + return 0; } -int wolfSSL_CTX_EnableOCSPMustStaple(WOLFSSL_CTX* ctx) +/* return TRUE if current error is want write */ +int wolfSSL_want_write(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSPMustStaple"); - if (ctx) - return wolfSSL_CertManagerEnableOCSPMustStaple(ctx->cm); - else - return BAD_FUNC_ARG; -} + WOLFSSL_ENTER("wolfSSL_want_write"); + if (ssl->error == WC_NO_ERR_TRACE(WANT_WRITE)) + return 1; -int wolfSSL_CTX_DisableOCSPMustStaple(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSPMustStaple"); - if (ctx) - return wolfSSL_CertManagerDisableOCSPMustStaple(ctx->cm); - else - return BAD_FUNC_ARG; + return 0; } -#endif /* HAVE_CERTIFICATE_STATUS_REQUEST || \ - * HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ - -#endif /* HAVE_OCSP */ -#ifdef HAVE_CRL - -int wolfSSL_EnableCRL(WOLFSSL* ssl, int options) +char* wolfSSL_ERR_error_string(unsigned long errNumber, char* data) { - WOLFSSL_ENTER("wolfSSL_EnableCRL"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerEnableCRL(SSL_CM(ssl), options); + WOLFSSL_ENTER("wolfSSL_ERR_error_string"); + if (data) { + SetErrorString((int)errNumber, data); + return data; + } + else { + static char tmp[WOLFSSL_MAX_ERROR_SZ] = {0}; + SetErrorString((int)errNumber, tmp); + return tmp; } - else - return BAD_FUNC_ARG; } -int wolfSSL_DisableCRL(WOLFSSL* ssl) +void wolfSSL_ERR_error_string_n(unsigned long e, char* buf, unsigned long len) { - WOLFSSL_ENTER("wolfSSL_DisableCRL"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerDisableCRL(SSL_CM(ssl)); + WOLFSSL_ENTER("wolfSSL_ERR_error_string_n"); + if (len >= WOLFSSL_MAX_ERROR_SZ) + wolfSSL_ERR_error_string(e, buf); + else { + WOLFSSL_MSG("Error buffer too short, truncating"); + if (len) { + char tmp[WOLFSSL_MAX_ERROR_SZ]; + wolfSSL_ERR_error_string(e, tmp); + XMEMCPY(buf, tmp, len-1); + buf[len-1] = '\0'; + } } - else - return BAD_FUNC_ARG; } -#ifndef NO_FILESYSTEM -int wolfSSL_LoadCRL(WOLFSSL* ssl, const char* path, int type, int monitor) -{ - WOLFSSL_ENTER("wolfSSL_LoadCRL"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerLoadCRL(SSL_CM(ssl), path, type, monitor); - } - else - return BAD_FUNC_ARG; -} -int wolfSSL_LoadCRLFile(WOLFSSL* ssl, const char* file, int type) +/* don't free temporary arrays at end of handshake */ +void wolfSSL_KeepArrays(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_LoadCRLFile"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerLoadCRLFile(SSL_CM(ssl), file, type); - } - else - return BAD_FUNC_ARG; + if (ssl) + ssl->options.saveArrays = 1; } -#endif -int wolfSSL_SetCRL_Cb(WOLFSSL* ssl, CbMissingCRL cb) -{ - WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerSetCRL_Cb(SSL_CM(ssl), cb); - } - else - return BAD_FUNC_ARG; -} -int wolfSSL_SetCRL_ErrorCb(WOLFSSL* ssl, crlErrorCb cb, void* ctx) +/* user doesn't need temporary arrays anymore, Free */ +void wolfSSL_FreeArrays(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerSetCRL_ErrorCb(SSL_CM(ssl), cb, ctx); + if (ssl && ssl->options.handShakeState == HANDSHAKE_DONE) { + ssl->options.saveArrays = 0; + FreeArrays(ssl, 1); } - else - return BAD_FUNC_ARG; } -#ifdef HAVE_CRL_IO -int wolfSSL_SetCRL_IOCb(WOLFSSL* ssl, CbCrlIO cb) +/* Set option to indicate that the resources are not to be freed after + * handshake. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. + */ +int wolfSSL_KeepHandshakeResources(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); - if (ssl) { - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerSetCRL_IOCb(SSL_CM(ssl), cb); - } - else + if (ssl == NULL) return BAD_FUNC_ARG; -} -#endif -int wolfSSL_CTX_EnableCRL(WOLFSSL_CTX* ctx, int options) -{ - WOLFSSL_ENTER("wolfSSL_CTX_EnableCRL"); - if (ctx) - return wolfSSL_CertManagerEnableCRL(ctx->cm, options); - else - return BAD_FUNC_ARG; -} + ssl->options.keepResources = 1; + return 0; +} -int wolfSSL_CTX_DisableCRL(WOLFSSL_CTX* ctx) +/* Free the handshake resources after handshake. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. + */ +int wolfSSL_FreeHandshakeResources(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_CTX_DisableCRL"); - if (ctx) - return wolfSSL_CertManagerDisableCRL(ctx->cm); - else + if (ssl == NULL) return BAD_FUNC_ARG; -} + FreeHandshakeResources(ssl); -#ifndef NO_FILESYSTEM -int wolfSSL_CTX_LoadCRL(WOLFSSL_CTX* ctx, const char* path, - int type, int monitor) -{ - WOLFSSL_ENTER("wolfSSL_CTX_LoadCRL"); - if (ctx) - return wolfSSL_CertManagerLoadCRL(ctx->cm, path, type, monitor); - else - return BAD_FUNC_ARG; + return 0; } -int wolfSSL_CTX_LoadCRLFile(WOLFSSL_CTX* ctx, const char* file, - int type) +/* Use the client's order of preference when matching cipher suites. + * + * ssl The SSL/TLS context object. + * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. + */ +int wolfSSL_CTX_UseClientSuites(WOLFSSL_CTX* ctx) { - WOLFSSL_ENTER("wolfSSL_CTX_LoadCRL"); - if (ctx) - return wolfSSL_CertManagerLoadCRLFile(ctx->cm, file, type); - else + if (ctx == NULL) return BAD_FUNC_ARG; -} -#endif + ctx->useClientOrder = 1; -int wolfSSL_CTX_SetCRL_Cb(WOLFSSL_CTX* ctx, CbMissingCRL cb) -{ - WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_Cb"); - if (ctx) - return wolfSSL_CertManagerSetCRL_Cb(ctx->cm, cb); - else - return BAD_FUNC_ARG; -} - -int wolfSSL_CTX_SetCRL_ErrorCb(WOLFSSL_CTX* ctx, crlErrorCb cb, void* cbCtx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_ErrorCb"); - if (ctx) - return wolfSSL_CertManagerSetCRL_ErrorCb(ctx->cm, cb, cbCtx); - else - return BAD_FUNC_ARG; + return 0; } -#ifdef HAVE_CRL_IO -int wolfSSL_CTX_SetCRL_IOCb(WOLFSSL_CTX* ctx, CbCrlIO cb) +/* Use the client's order of preference when matching cipher suites. + * + * ssl The SSL/TLS object. + * returns BAD_FUNC_ARG when ssl is NULL and 0 on success. + */ +int wolfSSL_UseClientSuites(WOLFSSL* ssl) { - WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_IOCb"); - if (ctx) - return wolfSSL_CertManagerSetCRL_IOCb(ctx->cm, cb); - else + if (ssl == NULL) return BAD_FUNC_ARG; -} -#endif - - -#endif /* HAVE_CRL */ + ssl->options.useClientOrder = 1; -/* Sets the max chain depth when verifying a certificate chain. Default depth - * is set to MAX_CHAIN_DEPTH. - * - * ctx WOLFSSL_CTX structure to set depth in - * depth max depth - */ -void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx, int depth) { - WOLFSSL_ENTER("wolfSSL_CTX_set_verify_depth"); + return 0; +} - if (ctx == NULL || depth < 0 || depth > MAX_CHAIN_DEPTH) { - WOLFSSL_MSG("Bad depth argument, too large or less than 0"); - return; - } +#ifdef WOLFSSL_DTLS +const byte* wolfSSL_GetDtlsMacSecret(WOLFSSL* ssl, int verify, int epochOrder) +{ +#ifndef WOLFSSL_AEAD_ONLY + Keys* keys = NULL; - ctx->verifyDepth = (byte)depth; -} + (void)epochOrder; + if (ssl == NULL) + return NULL; -/* get cert chaining depth using ssl struct */ -long wolfSSL_get_verify_depth(WOLFSSL* ssl) -{ - if(ssl == NULL) { - return BAD_FUNC_ARG; +#ifdef HAVE_SECURE_RENEGOTIATION + switch (epochOrder) { + case PEER_ORDER: + if (IsDtlsMsgSCRKeys(ssl)) + keys = &ssl->secure_renegotiation->tmp_keys; + else + keys = &ssl->keys; + break; + case PREV_ORDER: + keys = &ssl->keys; + break; + case CUR_ORDER: + if (DtlsUseSCRKeys(ssl)) + keys = &ssl->secure_renegotiation->tmp_keys; + else + keys = &ssl->keys; + break; + default: + WOLFSSL_MSG("Unknown epoch order"); + return NULL; } -#ifndef OPENSSL_EXTRA - return MAX_CHAIN_DEPTH; #else - return ssl->options.verifyDepth; + keys = &ssl->keys; #endif -} - -/* get cert chaining depth using ctx struct */ -long wolfSSL_CTX_get_verify_depth(WOLFSSL_CTX* ctx) -{ - if (ctx == NULL) { - return BAD_FUNC_ARG; - } -#ifndef OPENSSL_EXTRA - return MAX_CHAIN_DEPTH; + if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) || + (ssl->options.side == WOLFSSL_SERVER_END && verify) ) + return keys->client_write_MAC_secret; + else + return keys->server_write_MAC_secret; #else - return ctx->verifyDepth; + (void)ssl; + (void)verify; + (void)epochOrder; + + return NULL; #endif } +#endif /* WOLFSSL_DTLS */ -#ifndef NO_CHECK_PRIVATE_KEY - -#ifdef WOLF_PRIVATE_KEY_ID -/* Check private against public in certificate for match using external - * device with given devId */ -static int check_cert_key_dev(word32 keyOID, byte* privKey, word32 privSz, - const byte* pubKey, word32 pubSz, int label, int id, void* heap, int devId) +const byte* wolfSSL_GetMacSecret(WOLFSSL* ssl, int verify) { - int ret = 0; - int type = 0; - void *pkey = NULL; +#ifndef WOLFSSL_AEAD_ONLY + if (ssl == NULL) + return NULL; - if (privKey == NULL) { - return MISSING_KEY; - } + if ( (ssl->options.side == WOLFSSL_CLIENT_END && !verify) || + (ssl->options.side == WOLFSSL_SERVER_END && verify) ) + return ssl->keys.client_write_MAC_secret; + else + return ssl->keys.server_write_MAC_secret; +#else + (void)ssl; + (void)verify; -#ifndef NO_RSA - if (keyOID == RSAk) { - type = DYNAMIC_TYPE_RSA; - } -#ifdef WC_RSA_PSS - if (keyOID == RSAPSSk) { - type = DYNAMIC_TYPE_RSA; - } -#endif -#endif -#ifdef HAVE_ECC - if (keyOID == ECDSAk) { - type = DYNAMIC_TYPE_ECC; - } -#endif -#if defined(HAVE_DILITHIUM) - if ((keyOID == ML_DSA_LEVEL2k) || - (keyOID == ML_DSA_LEVEL3k) || - (keyOID == ML_DSA_LEVEL5k) - #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT - || (keyOID == DILITHIUM_LEVEL2k) - || (keyOID == DILITHIUM_LEVEL3k) - || (keyOID == DILITHIUM_LEVEL5k) - #endif /* WOLFSSL_DILITHIUM_FIPS204_DRAFT */ - ) { - type = DYNAMIC_TYPE_DILITHIUM; - } -#endif -#if defined(HAVE_FALCON) - if ((keyOID == FALCON_LEVEL1k) || - (keyOID == FALCON_LEVEL5k)) { - type = DYNAMIC_TYPE_FALCON; - } + return NULL; #endif - - ret = CreateDevPrivateKey(&pkey, privKey, privSz, type, label, id, - heap, devId); - #ifdef WOLF_CRYPTO_CB - if (ret == 0) { - #ifndef NO_RSA - if (keyOID == RSAk - #ifdef WC_RSA_PSS - || keyOID == RSAPSSk - #endif - ) { - ret = wc_CryptoCb_RsaCheckPrivKey((RsaKey*)pkey, pubKey, pubSz); - } - #endif - #ifdef HAVE_ECC - if (keyOID == ECDSAk) { - ret = wc_CryptoCb_EccCheckPrivKey((ecc_key*)pkey, pubKey, pubSz); - } - #endif - #if defined(HAVE_DILITHIUM) - if ((keyOID == ML_DSA_LEVEL2k) || - (keyOID == ML_DSA_LEVEL3k) || - (keyOID == ML_DSA_LEVEL5k) - #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT - || (keyOID == DILITHIUM_LEVEL2k) - || (keyOID == DILITHIUM_LEVEL3k) - || (keyOID == DILITHIUM_LEVEL5k) - #endif /* WOLFSSL_DILITHIUM_FIPS204_DRAFT */ - ) { - ret = wc_CryptoCb_PqcSignatureCheckPrivKey(pkey, - WC_PQC_SIG_TYPE_DILITHIUM, - pubKey, pubSz); - } - #endif - #if defined(HAVE_FALCON) - if ((keyOID == FALCON_LEVEL1k) || - (keyOID == FALCON_LEVEL5k)) { - ret = wc_CryptoCb_PqcSignatureCheckPrivKey(pkey, - WC_PQC_SIG_TYPE_FALCON, - pubKey, pubSz); - } - #endif - } - #else - /* devId was set, don't check, for now */ - /* TODO: Add callback for private key check? */ - (void) pubKey; - (void) pubSz; - #endif - if (pkey != NULL) { - #ifndef NO_RSA - if (keyOID == RSAk - #ifdef WC_RSA_PSS - || keyOID == RSAPSSk - #endif - ) { - wc_FreeRsaKey((RsaKey*)pkey); - } - #endif - #ifdef HAVE_ECC - if (keyOID == ECDSAk) { - wc_ecc_free((ecc_key*)pkey); - } - #endif - #if defined(HAVE_DILITHIUM) - if ((keyOID == ML_DSA_LEVEL2k) || - (keyOID == ML_DSA_LEVEL3k) || - (keyOID == ML_DSA_LEVEL5k) - #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT - || (keyOID == DILITHIUM_LEVEL2k) - || (keyOID == DILITHIUM_LEVEL3k) - || (keyOID == DILITHIUM_LEVEL5k) - #endif /* WOLFSSL_DILITHIUM_FIPS204_DRAFT */ - ) { - wc_dilithium_free((dilithium_key*)pkey); - } - #endif - #if defined(HAVE_FALCON) - if ((keyOID == FALCON_LEVEL1k) || - (keyOID == FALCON_LEVEL5k)) { - wc_falcon_free((falcon_key*)pkey); - } - #endif - XFREE(pkey, heap, type); - } - - return ret; } -#endif /* WOLF_PRIVATE_KEY_ID */ -/* Check private against public in certificate for match - * - * Returns WOLFSSL_SUCCESS on good private key - * WOLFSSL_FAILURE if mismatched */ -static int check_cert_key(const DerBuffer* cert, const DerBuffer* key, - const DerBuffer* altKey, void* heap, int devId, int isKeyLabel, int isKeyId, - int altDevId, int isAltKeyLabel, int isAltKeyId) +int wolfSSL_GetSide(WOLFSSL* ssl) { - WC_DECLARE_VAR(der, DecodedCert, 1, 0); - word32 size; - byte* buff; - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + if (ssl) + return ssl->options.side; - WOLFSSL_ENTER("check_cert_key"); + return BAD_FUNC_ARG; +} - if (cert == NULL || key == NULL) { - return WOLFSSL_FAILURE; - } +#ifdef ATOMIC_USER - WC_ALLOC_VAR_EX(der, DecodedCert, 1, heap, DYNAMIC_TYPE_DCERT, - return MEMORY_E); +void wolfSSL_CTX_SetMacEncryptCb(WOLFSSL_CTX* ctx, CallbackMacEncrypt cb) +{ + if (ctx) + ctx->MacEncryptCb = cb; +} - size = cert->length; - buff = cert->buffer; - InitDecodedCert_ex(der, buff, size, heap, devId); - if (ParseCertRelative(der, CERT_TYPE, NO_VERIFY, NULL, NULL) != 0) { - FreeDecodedCert(der); - WC_FREE_VAR_EX(der, heap, DYNAMIC_TYPE_DCERT); - return WOLFSSL_FAILURE; - } - size = key->length; - buff = key->buffer; -#ifdef WOLF_PRIVATE_KEY_ID - if (devId != INVALID_DEVID) { - ret = check_cert_key_dev(der->keyOID, buff, size, der->publicKey, - der->pubKeySize, isKeyLabel, isKeyId, heap, - devId); - if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { - ret = (ret == 0) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; - } - } - else { - /* fall through if unavailable */ - ret = CRYPTOCB_UNAVAILABLE; - } +void wolfSSL_SetMacEncryptCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->MacEncryptCtx = ctx; +} - if (ret == WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) -#endif /* WOLF_PRIVATE_KEY_ID */ - { - ret = wc_CheckPrivateKeyCert(buff, size, der, 0, heap); - ret = (ret == 1) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; - } -#ifdef WOLFSSL_DUAL_ALG_CERTS - if (ret == WOLFSSL_SUCCESS && der->extSapkiSet && der->sapkiDer != NULL) { - /* Certificate contains an alternative public key. Hence, we also - * need an alternative private key. */ - if (altKey == NULL) { - ret = MISSING_KEY; - buff = NULL; - size = 0; - } - else { - size = altKey->length; - buff = altKey->buffer; - } -#ifdef WOLF_PRIVATE_KEY_ID - if (ret == WOLFSSL_SUCCESS && altDevId != INVALID_DEVID) { - /* We have to decode the public key first */ - /* Default to max pub key size. */ - word32 pubKeyLen = MAX_PUBLIC_KEY_SZ; - byte* decodedPubKey = (byte*)XMALLOC(pubKeyLen, heap, - DYNAMIC_TYPE_PUBLIC_KEY); - if (decodedPubKey == NULL) { - ret = MEMORY_E; - } - if (ret == WOLFSSL_SUCCESS) { - if (der->sapkiOID == RSAk || der->sapkiOID == ECDSAk) { - /* Simply copy the data */ - XMEMCPY(decodedPubKey, der->sapkiDer, der->sapkiLen); - pubKeyLen = der->sapkiLen; - ret = 0; - } - else { - #if defined(WC_ENABLE_ASYM_KEY_IMPORT) - word32 idx = 0; - ret = DecodeAsymKeyPublic(der->sapkiDer, &idx, - der->sapkiLen, decodedPubKey, - &pubKeyLen, der->sapkiOID); - #else - ret = NOT_COMPILED_IN; - #endif /* WC_ENABLE_ASYM_KEY_IMPORT */ - } - } - if (ret == 0) { - ret = check_cert_key_dev(der->sapkiOID, buff, size, - decodedPubKey, pubKeyLen, - isAltKeyLabel, isAltKeyId, - heap, altDevId); - } - XFREE(decodedPubKey, heap, DYNAMIC_TYPE_PUBLIC_KEY); - if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { - ret = (ret == 0) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; - } - } - else { - /* fall through if unavailable */ - ret = CRYPTOCB_UNAVAILABLE; - } +void* wolfSSL_GetMacEncryptCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->MacEncryptCtx; - if (ret == WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) -#else - if (ret == WOLFSSL_SUCCESS) -#endif /* WOLF_PRIVATE_KEY_ID */ - { - ret = wc_CheckPrivateKeyCert(buff, size, der, 1, heap); - ret = (ret == 1) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; - } - } -#endif /* WOLFSSL_DUAL_ALG_CERTS */ - FreeDecodedCert(der); - WC_FREE_VAR_EX(der, heap, DYNAMIC_TYPE_DCERT); + return NULL; +} - (void)devId; - (void)isKeyLabel; - (void)isKeyId; - (void)altKey; - (void)altDevId; - (void)isAltKeyLabel; - (void)isAltKeyId; - return ret; +void wolfSSL_CTX_SetDecryptVerifyCb(WOLFSSL_CTX* ctx, CallbackDecryptVerify cb) +{ + if (ctx) + ctx->DecryptVerifyCb = cb; } -/* Check private against public in certificate for match - * - * ctx WOLFSSL_CTX structure to check private key in - * - * Returns WOLFSSL_SUCCESS on good private key - * WOLFSSL_FAILURE if mismatched. */ -int wolfSSL_CTX_check_private_key(const WOLFSSL_CTX* ctx) -{ - int res = WOLFSSL_SUCCESS; -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - DerBuffer *privateKey; -#ifdef WOLFSSL_DUAL_ALG_CERTS - DerBuffer *altPrivateKey; -#endif -#else - const DerBuffer *privateKey; -#ifdef WOLFSSL_DUAL_ALG_CERTS - const DerBuffer *altPrivateKey; -#endif -#endif - if (ctx == NULL) { - return WOLFSSL_FAILURE; - } +void wolfSSL_SetDecryptVerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->DecryptVerifyCtx = ctx; +} -#ifdef WOLFSSL_DUAL_ALG_CERTS -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - privateKey = wolfssl_priv_der_unblind(ctx->privateKey, ctx->privateKeyMask); - if (privateKey == NULL) { - res = WOLFSSL_FAILURE; - } - if (ctx->altPrivateKey != NULL) { - altPrivateKey = wolfssl_priv_der_unblind(ctx->altPrivateKey, - ctx->altPrivateKeyMask); - if (altPrivateKey == NULL) { - res = WOLFSSL_FAILURE; - } - } - else { - altPrivateKey = NULL; - } -#else - privateKey = ctx->privateKey; - altPrivateKey = ctx->altPrivateKey; -#endif - if (res == WOLFSSL_SUCCESS) { - res = check_cert_key(ctx->certificate, privateKey, altPrivateKey, - ctx->heap, ctx->privateKeyDevId, ctx->privateKeyLabel, - ctx->privateKeyId, ctx->altPrivateKeyDevId, - ctx->altPrivateKeyLabel, ctx->altPrivateKeyId) != 0; - } -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - wolfssl_priv_der_unblind_free(privateKey); - wolfssl_priv_der_unblind_free(altPrivateKey); -#endif -#else -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - privateKey = wolfssl_priv_der_unblind(ctx->privateKey, ctx->privateKeyMask); - if (privateKey == NULL) { - res = WOLFSSL_FAILURE; - } -#else - privateKey = ctx->privateKey; -#endif - if (res == WOLFSSL_SUCCESS) { - res = check_cert_key(ctx->certificate, privateKey, NULL, ctx->heap, - ctx->privateKeyDevId, ctx->privateKeyLabel, - ctx->privateKeyId, INVALID_DEVID, 0, 0); - } -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - wolfssl_priv_der_unblind_free(privateKey); -#endif -#endif - /* placing error into error queue for Python port */ - if (res != WOLFSSL_SUCCESS) { - WOLFSSL_ERROR(WC_KEY_MISMATCH_E); - } +void* wolfSSL_GetDecryptVerifyCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->DecryptVerifyCtx; - return res; + return NULL; } -#endif /* !NO_CHECK_PRIVATE_KEY */ -#ifdef OPENSSL_ALL +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) /** - * Return the private key of the WOLFSSL_CTX struct - * @return WOLFSSL_EVP_PKEY* The caller doesn *NOT*` free the returned object. + * Set the callback, against the context, that encrypts then MACs. * - * Note, even though the supplied ctx pointer is designated const, on success - * ctx->privateKeyPKey is changed by this call. The change is done safely using - * a hardware-synchronized store. + * ctx SSL/TLS context. + * cb Callback function to use with Encrypt-Then-MAC. */ -WOLFSSL_EVP_PKEY* wolfSSL_CTX_get0_privatekey(const WOLFSSL_CTX* ctx) -{ - WOLFSSL_EVP_PKEY* res; - const unsigned char *key; - int type; - - WOLFSSL_ENTER("wolfSSL_CTX_get0_privatekey"); - - if (ctx == NULL || ctx->privateKey == NULL || - ctx->privateKey->buffer == NULL) { - WOLFSSL_MSG("Bad parameter or key not set"); - return NULL; - } - - switch (ctx->privateKeyType) { -#ifndef NO_RSA - case rsa_sa_algo: - type = WC_EVP_PKEY_RSA; - break; -#endif -#ifdef HAVE_ECC - case ecc_dsa_sa_algo: - type = WC_EVP_PKEY_EC; - break; -#endif -#ifdef WOLFSSL_SM2 - case sm2_sa_algo: - type = WC_EVP_PKEY_EC; - break; -#endif - default: - /* Other key types not supported either as ssl private keys - * or in the EVP layer */ - WOLFSSL_MSG("Unsupported key type"); - return NULL; - } - - if (ctx->privateKeyPKey != NULL) { - res = ctx->privateKeyPKey; - } - else { - #ifdef WOLFSSL_BLIND_PRIVATE_KEY - DerBuffer *unblinded_privateKey = - wolfssl_priv_der_unblind(ctx->privateKey, ctx->privateKeyMask); - if (unblinded_privateKey == NULL) - return NULL; - key = unblinded_privateKey->buffer; - #else - key = ctx->privateKey->buffer; - #endif - res = wolfSSL_d2i_PrivateKey(type, NULL, &key, - (long)ctx->privateKey->length); - #ifdef WOLFSSL_BLIND_PRIVATE_KEY - wolfssl_priv_der_unblind_free(unblinded_privateKey); - #endif - if (res) { -#ifdef WOLFSSL_ATOMIC_OPS - WOLFSSL_EVP_PKEY *current_pkey = NULL; - if (! wolfSSL_Atomic_Ptr_CompareExchange( - (void * volatile *)&ctx->privateKeyPKey, - (void **)¤t_pkey, res)) - { - wolfSSL_EVP_PKEY_free(res); - res = current_pkey; - } -#else - ((WOLFSSL_CTX *)ctx)->privateKeyPKey = res; -#endif - } - } - - return res; +void wolfSSL_CTX_SetEncryptMacCb(WOLFSSL_CTX* ctx, CallbackEncryptMac cb) +{ + if (ctx) + ctx->EncryptMacCb = cb; } -#endif -#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) - -#if !defined(NO_RSA) -static int d2iTryRsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, - long memSz, int priv) +/** + * Set the context to use with callback that encrypts then MACs. + * + * ssl SSL/TLS object. + * ctx Callback function's context. + */ +void wolfSSL_SetEncryptMacCtx(WOLFSSL* ssl, void *ctx) { - WOLFSSL_EVP_PKEY* pkey; - word32 keyIdx = 0; - int isRsaKey; - int ret = 1; -#ifndef WOLFSSL_SMALL_STACK - RsaKey rsa[1]; -#else - RsaKey *rsa = (RsaKey*)XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA); - if (rsa == NULL) - return 0; -#endif - - XMEMSET(rsa, 0, sizeof(RsaKey)); - - if (wc_InitRsaKey(rsa, NULL) != 0) { - WC_FREE_VAR_EX(rsa, NULL, DYNAMIC_TYPE_RSA); - return 0; - } - /* test if RSA key */ - if (priv) { - isRsaKey = - (wc_RsaPrivateKeyDecode(mem, &keyIdx, rsa, (word32)memSz) == 0); - } - else { - isRsaKey = - (wc_RsaPublicKeyDecode(mem, &keyIdx, rsa, (word32)memSz) == 0); - } - wc_FreeRsaKey(rsa); - WC_FREE_VAR_EX(rsa, NULL, DYNAMIC_TYPE_RSA); - - if (!isRsaKey) { - return WOLFSSL_FATAL_ERROR; - } + if (ssl) + ssl->EncryptMacCtx = ctx; +} - if (*out != NULL) { - pkey = *out; - } - else { - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) { - WOLFSSL_MSG("RSA wolfSSL_EVP_PKEY_new error"); - return 0; - } - } +/** + * Get the context being used with callback that encrypts then MACs. + * + * ssl SSL/TLS object. + * returns callback function's context or NULL if SSL/TLS object is NULL. + */ +void* wolfSSL_GetEncryptMacCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->EncryptMacCtx; - pkey->pkey_sz = (int)keyIdx; - pkey->pkey.ptr = (char*)XMALLOC((size_t)memSz, NULL, - priv ? DYNAMIC_TYPE_PRIVATE_KEY : - DYNAMIC_TYPE_PUBLIC_KEY); - if (pkey->pkey.ptr == NULL) { - ret = 0; - } - if (ret == 1) { - XMEMCPY(pkey->pkey.ptr, mem, keyIdx); - pkey->type = WC_EVP_PKEY_RSA; + return NULL; +} - pkey->ownRsa = 1; - pkey->rsa = wolfssl_rsa_d2i(NULL, mem, memSz, - priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC); - if (pkey->rsa == NULL) { - ret = 0; - } - } - if (ret == 1) { - *out = pkey; - } +/** + * Set the callback, against the context, that MAC verifies then decrypts. + * + * ctx SSL/TLS context. + * cb Callback function to use with Encrypt-Then-MAC. + */ +void wolfSSL_CTX_SetVerifyDecryptCb(WOLFSSL_CTX* ctx, CallbackVerifyDecrypt cb) +{ + if (ctx) + ctx->VerifyDecryptCb = cb; +} - if ((ret == 0) && (*out == NULL)) { - wolfSSL_EVP_PKEY_free(pkey); - } - return ret; +/** + * Set the context to use with callback that MAC verifies then decrypts. + * + * ssl SSL/TLS object. + * ctx Callback function's context. + */ +void wolfSSL_SetVerifyDecryptCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->VerifyDecryptCtx = ctx; } -#endif /* !NO_RSA */ -#if defined(HAVE_ECC) && defined(OPENSSL_EXTRA) -static int d2iTryEccKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, - long memSz, int priv) +/** + * Get the context being used with callback that MAC verifies then decrypts. + * + * ssl SSL/TLS object. + * returns callback function's context or NULL if SSL/TLS object is NULL. + */ +void* wolfSSL_GetVerifyDecryptCtx(WOLFSSL* ssl) { - WOLFSSL_EVP_PKEY* pkey; - word32 keyIdx = 0; - int isEccKey; - int ret = 1; -#ifndef WOLFSSL_SMALL_STACK - ecc_key ecc[1]; -#else - ecc_key *ecc = (ecc_key*)XMALLOC(sizeof(ecc_key), NULL, - DYNAMIC_TYPE_ECC); - if (ecc == NULL) - return 0; -#endif + if (ssl) + return ssl->VerifyDecryptCtx; - XMEMSET(ecc, 0, sizeof(ecc_key)); + return NULL; +} +#endif /* HAVE_ENCRYPT_THEN_MAC !WOLFSSL_AEAD_ONLY */ - if (wc_ecc_init(ecc) != 0) { - WC_FREE_VAR_EX(ecc, NULL, DYNAMIC_TYPE_ECC); - return 0; - } - if (priv) { - isEccKey = - (wc_EccPrivateKeyDecode(mem, &keyIdx, ecc, (word32)memSz) == 0); - } - else { - isEccKey = - (wc_EccPublicKeyDecode(mem, &keyIdx, ecc, (word32)memSz) == 0); - } - wc_ecc_free(ecc); - WC_FREE_VAR_EX(ecc, NULL, DYNAMIC_TYPE_ECC); - if (!isEccKey) { - return WOLFSSL_FATAL_ERROR; - } +const byte* wolfSSL_GetClientWriteKey(WOLFSSL* ssl) +{ + if (ssl) + return ssl->keys.client_write_key; - if (*out != NULL) { - pkey = *out; - } - else { - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) { - WOLFSSL_MSG("ECC wolfSSL_EVP_PKEY_new error"); - return 0; - } - } + return NULL; +} - pkey->pkey_sz = (int)keyIdx; - pkey->pkey.ptr = (char*)XMALLOC(keyIdx, NULL, - priv ? DYNAMIC_TYPE_PRIVATE_KEY : - DYNAMIC_TYPE_PUBLIC_KEY); - if (pkey->pkey.ptr == NULL) { - ret = 0; - } - if (ret == 1) { - XMEMCPY(pkey->pkey.ptr, mem, keyIdx); - pkey->type = WC_EVP_PKEY_EC; - pkey->ownEcc = 1; - pkey->ecc = wolfSSL_EC_KEY_new(); - if (pkey->ecc == NULL) { - ret = 0; - } - } - if ((ret == 1) && (wolfSSL_EC_KEY_LoadDer_ex(pkey->ecc, - (const unsigned char*)pkey->pkey.ptr, - pkey->pkey_sz, priv ? WOLFSSL_RSA_LOAD_PRIVATE - : WOLFSSL_RSA_LOAD_PUBLIC) != 1)) { - ret = 0; - } - if (ret == 1) { - *out = pkey; - } +const byte* wolfSSL_GetClientWriteIV(WOLFSSL* ssl) +{ + if (ssl) + return ssl->keys.client_write_IV; - if ((ret == 0) && (*out == NULL)) { - wolfSSL_EVP_PKEY_free(pkey); - } - return ret; + return NULL; } -#endif /* HAVE_ECC && OPENSSL_EXTRA */ -#if !defined(NO_DSA) -static int d2iTryDsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, - long memSz, int priv) + +const byte* wolfSSL_GetServerWriteKey(WOLFSSL* ssl) { - WOLFSSL_EVP_PKEY* pkey; - word32 keyIdx = 0; - int isDsaKey; - int ret = 1; -#ifndef WOLFSSL_SMALL_STACK - DsaKey dsa[1]; -#else - DsaKey *dsa = (DsaKey*)XMALLOC(sizeof(DsaKey), NULL, DYNAMIC_TYPE_DSA); - if (dsa == NULL) - return 0; -#endif + if (ssl) + return ssl->keys.server_write_key; - XMEMSET(dsa, 0, sizeof(DsaKey)); + return NULL; +} - if (wc_InitDsaKey(dsa) != 0) { - WC_FREE_VAR_EX(dsa, NULL, DYNAMIC_TYPE_DSA); - return 0; - } - if (priv) { - isDsaKey = - (wc_DsaPrivateKeyDecode(mem, &keyIdx, dsa, (word32)memSz) == 0); - } - else { - isDsaKey = - (wc_DsaPublicKeyDecode(mem, &keyIdx, dsa, (word32)memSz) == 0); - } - wc_FreeDsaKey(dsa); - WC_FREE_VAR_EX(dsa, NULL, DYNAMIC_TYPE_DSA); +const byte* wolfSSL_GetServerWriteIV(WOLFSSL* ssl) +{ + if (ssl) + return ssl->keys.server_write_IV; - /* test if DSA key */ - if (!isDsaKey) { - return WOLFSSL_FATAL_ERROR; - } + return NULL; +} - if (*out != NULL) { - pkey = *out; - } - else { - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) { - WOLFSSL_MSG("DSA wolfSSL_EVP_PKEY_new error"); - return 0; - } - } +int wolfSSL_GetKeySize(WOLFSSL* ssl) +{ + if (ssl) + return ssl->specs.key_size; - pkey->pkey_sz = (int)keyIdx; - pkey->pkey.ptr = (char*)XMALLOC((size_t)memSz, NULL, - priv ? DYNAMIC_TYPE_PRIVATE_KEY : - DYNAMIC_TYPE_PUBLIC_KEY); - if (pkey->pkey.ptr == NULL) { - ret = 0; - } - if (ret == 1) { - XMEMCPY(pkey->pkey.ptr, mem, keyIdx); - pkey->type = WC_EVP_PKEY_DSA; + return BAD_FUNC_ARG; +} - pkey->ownDsa = 1; - pkey->dsa = wolfSSL_DSA_new(); - if (pkey->dsa == NULL) { - ret = 0; - } - } - if ((ret == 1) && (wolfSSL_DSA_LoadDer_ex(pkey->dsa, - (const unsigned char*)pkey->pkey.ptr, - pkey->pkey_sz, priv ? WOLFSSL_RSA_LOAD_PRIVATE - : WOLFSSL_RSA_LOAD_PUBLIC) != 1)) { - ret = 0; - } - if (ret == 1) { - *out = pkey; - } +int wolfSSL_GetIVSize(WOLFSSL* ssl) +{ + if (ssl) + return ssl->specs.iv_size; - if ((ret == 0) && (*out == NULL)) { - wolfSSL_EVP_PKEY_free(pkey); - } - return ret; + return BAD_FUNC_ARG; } -#endif /* NO_DSA */ -#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ - (HAVE_FIPS_VERSION > 2)) -static int d2iTryDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, - long memSz, int priv) -{ - WOLFSSL_EVP_PKEY* pkey; - int isDhKey; - word32 keyIdx = 0; - int ret = 1; -#ifndef WOLFSSL_SMALL_STACK - DhKey dh[1]; -#else - DhKey *dh = (DhKey*)XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH); - if (dh == NULL) - return 0; -#endif - XMEMSET(dh, 0, sizeof(DhKey)); +int wolfSSL_GetBulkCipher(WOLFSSL* ssl) +{ + if (ssl) + return ssl->specs.bulk_cipher_algorithm; - if (wc_InitDhKey(dh) != 0) { - WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH); - return 0; - } + return BAD_FUNC_ARG; +} - isDhKey = (wc_DhKeyDecode(mem, &keyIdx, dh, (word32)memSz) == 0); - wc_FreeDhKey(dh); - WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH); - /* test if DH key */ - if (!isDhKey) { - return WOLFSSL_FATAL_ERROR; - } +int wolfSSL_GetCipherType(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; - if (*out != NULL) { - pkey = *out; - } - else { - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) { - WOLFSSL_MSG("DH wolfSSL_EVP_PKEY_new error"); - return 0; - } - } +#ifndef WOLFSSL_AEAD_ONLY + if (ssl->specs.cipher_type == block) + return WOLFSSL_BLOCK_TYPE; + if (ssl->specs.cipher_type == stream) + return WOLFSSL_STREAM_TYPE; +#endif + if (ssl->specs.cipher_type == aead) + return WOLFSSL_AEAD_TYPE; - pkey->pkey_sz = (int)memSz; - pkey->pkey.ptr = (char*)XMALLOC((size_t)memSz, NULL, - priv ? DYNAMIC_TYPE_PRIVATE_KEY : - DYNAMIC_TYPE_PUBLIC_KEY); - if (pkey->pkey.ptr == NULL) { - ret = 0; - } - if (ret == 1) { - XMEMCPY(pkey->pkey.ptr, mem, (size_t)memSz); - pkey->type = WC_EVP_PKEY_DH; + return WOLFSSL_FATAL_ERROR; +} - pkey->ownDh = 1; - pkey->dh = wolfSSL_DH_new(); - if (pkey->dh == NULL) { - ret = 0; - } - } - if ((ret == 1) && (wolfSSL_DH_LoadDer(pkey->dh, - (const unsigned char*)pkey->pkey.ptr, - pkey->pkey_sz) != WOLFSSL_SUCCESS)) { - ret = 0; - } - if (ret == 1) { - *out = pkey; - } +int wolfSSL_GetCipherBlockSize(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; - if ((ret == 0) && (*out == NULL)) { - wolfSSL_EVP_PKEY_free(pkey); - } - return ret; + return ssl->specs.block_size; } -#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ -#endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */ -#if !defined(NO_DH) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_DH_EXTRA) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ - (HAVE_FIPS_VERSION > 2)) -static int d2iTryAltDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, - long memSz, int priv) + +int wolfSSL_GetAeadMacSize(WOLFSSL* ssl) { - WOLFSSL_EVP_PKEY* pkey; - word32 keyIdx = 0; - DhKey* key = NULL; - int elements; - int ret; -#ifndef WOLFSSL_SMALL_STACK - DhKey dh[1]; -#else - DhKey* dh = (DhKey*)XMALLOC(sizeof(DhKey), NULL, DYNAMIC_TYPE_DH); - if (dh == NULL) - return 0; -#endif - XMEMSET(dh, 0, sizeof(DhKey)); + if (ssl == NULL) + return BAD_FUNC_ARG; - /* test if DH-public key */ - if (wc_InitDhKey(dh) != 0) { - WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH); - return 0; - } + return ssl->specs.aead_mac_size; +} - ret = wc_DhKeyDecode(mem, &keyIdx, dh, (word32)memSz); - wc_FreeDhKey(dh); - WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH); - if (ret != 0) { - return WOLFSSL_FATAL_ERROR; - } +int wolfSSL_IsTLSv1_1(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; - if (*out != NULL) { - pkey = *out; - } - else { - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) { - return 0; - } - } + if (ssl->options.tls1_1) + return 1; - ret = 1; - pkey->type = WC_EVP_PKEY_DH; - pkey->pkey_sz = (int)memSz; - pkey->pkey.ptr = (char*)XMALLOC((size_t)memSz, NULL, - priv ? DYNAMIC_TYPE_PRIVATE_KEY : - DYNAMIC_TYPE_PUBLIC_KEY); - if (pkey->pkey.ptr == NULL) { - ret = 0; - } - if (ret == 1) { - XMEMCPY(pkey->pkey.ptr, mem, (size_t)memSz); - pkey->ownDh = 1; - pkey->dh = wolfSSL_DH_new(); - if (pkey->dh == NULL) { - ret = 0; - } - } + return 0; +} - if (ret == 1) { - key = (DhKey*)pkey->dh->internal; - keyIdx = 0; - if (wc_DhKeyDecode(mem, &keyIdx, key, (word32)memSz) != 0) { - ret = 0; - } - } - if (ret == 1) { - elements = ELEMENT_P | ELEMENT_G | ELEMENT_Q | ELEMENT_PUB; - if (priv) { - elements |= ELEMENT_PRV; - } - if (SetDhExternal_ex(pkey->dh, elements) != WOLFSSL_SUCCESS ) { - ret = 0; - } - } - if (ret == 1) { - *out = pkey; - } +int wolfSSL_GetHmacSize(WOLFSSL* ssl) +{ + /* AEAD ciphers don't have HMAC keys */ + if (ssl) + return (ssl->specs.cipher_type != aead) ? ssl->specs.hash_size : 0; - if ((ret == 0) && (*out == NULL)) { - wolfSSL_EVP_PKEY_free(pkey); - } - return ret; + return BAD_FUNC_ARG; } -#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ -#endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */ -#ifdef HAVE_FALCON -static int d2iTryFalconKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, - long memSz, int priv) +#ifdef WORD64_AVAILABLE +int wolfSSL_GetPeerSequenceNumber(WOLFSSL* ssl, word64 *seq) { - WOLFSSL_EVP_PKEY* pkey; - int isFalcon = 0; -#ifndef WOLFSSL_SMALL_STACK - falcon_key falcon[1]; -#else - falcon_key *falcon = (falcon_key *)XMALLOC(sizeof(falcon_key), NULL, - DYNAMIC_TYPE_FALCON); - if (falcon == NULL) { - return 0; - } -#endif + if ((ssl == NULL) || (seq == NULL)) + return BAD_FUNC_ARG; - if (wc_falcon_init(falcon) != 0) { - WC_FREE_VAR_EX(falcon, NULL, DYNAMIC_TYPE_FALCON); - return 0; - } + *seq = ((word64)ssl->keys.peer_sequence_number_hi << 32) | + ssl->keys.peer_sequence_number_lo; + return !(*seq); +} - /* test if Falcon key */ - if (priv) { - /* Try level 1 */ - isFalcon = ((wc_falcon_set_level(falcon, 1) == 0) && - (wc_falcon_import_private_only(mem, (word32)memSz, - falcon) == 0)); - if (!isFalcon) { - /* Try level 5 */ - isFalcon = ((wc_falcon_set_level(falcon, 5) == 0) && - (wc_falcon_import_private_only(mem, (word32)memSz, - falcon) == 0)); - } - } - else { - /* Try level 1 */ - isFalcon = ((wc_falcon_set_level(falcon, 1) == 0) && - (wc_falcon_import_public(mem, (word32)memSz, falcon) == 0)); +int wolfSSL_GetSequenceNumber(WOLFSSL* ssl, word64 *seq) +{ + if ((ssl == NULL) || (seq == NULL)) + return BAD_FUNC_ARG; - if (!isFalcon) { - /* Try level 5 */ - isFalcon = ((wc_falcon_set_level(falcon, 5) == 0) && - (wc_falcon_import_public(mem, (word32)memSz, - falcon) == 0)); - } - } - wc_falcon_free(falcon); - WC_FREE_VAR_EX(falcon, NULL, DYNAMIC_TYPE_FALCON); + *seq = ((word64)ssl->keys.sequence_number_hi << 32) | + ssl->keys.sequence_number_lo; + return !(*seq); +} +#endif - if (!isFalcon) { - return WOLFSSL_FATAL_ERROR; - } +#endif /* ATOMIC_USER */ - if (*out != NULL) { - pkey = *out; - } - else { - /* Create a fake Falcon EVP_PKEY. In the future, we might integrate - * Falcon into the compatibility layer. */ - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) { - WOLFSSL_MSG("Falcon wolfSSL_EVP_PKEY_new error"); - return 0; - } - } - pkey->type = WC_EVP_PKEY_FALCON; - pkey->pkey.ptr = NULL; - pkey->pkey_sz = 0; +#if !defined(NO_FILESYSTEM) && !defined(NO_STDIO_FILESYSTEM) \ + && defined(XFPRINTF) - *out = pkey; - return 1; +void wolfSSL_ERR_print_errors_fp(XFILE fp, int err) +{ + char data[WOLFSSL_MAX_ERROR_SZ + 1]; + + WOLFSSL_ENTER("wolfSSL_ERR_print_errors_fp"); + SetErrorString(err, data); + if (XFPRINTF(fp, "%s", data) < 0) + WOLFSSL_MSG("fprintf failed in wolfSSL_ERR_print_errors_fp"); +} +#if defined(OPENSSL_EXTRA) || defined(DEBUG_WOLFSSL_VERBOSE) +void wolfSSL_ERR_dump_errors_fp(XFILE fp) +{ + wc_ERR_print_errors_fp(fp); } -#endif /* HAVE_FALCON */ -#ifdef HAVE_DILITHIUM -static int d2iTryDilithiumKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, - long memSz, int priv) +void wolfSSL_ERR_print_errors_cb (int (*cb)(const char *str, size_t len, + void *u), void *u) { - WOLFSSL_EVP_PKEY* pkey; - int isDilithium = 0; -#ifndef WOLFSSL_SMALL_STACK - dilithium_key dilithium[1]; -#else - dilithium_key *dilithium = (dilithium_key *) - XMALLOC(sizeof(dilithium_key), NULL, DYNAMIC_TYPE_DILITHIUM); - if (dilithium == NULL) { - return 0; - } + wc_ERR_print_errors_cb(cb, u); +} #endif +#endif /* !NO_FILESYSTEM && !NO_STDIO_FILESYSTEM && XFPRINTF */ - if (wc_dilithium_init(dilithium) != 0) { - WC_FREE_VAR_EX(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM); - return 0; - } - - /* Test if Dilithium key. Try all levels. */ - if (priv) { - isDilithium = ((wc_dilithium_set_level(dilithium, WC_ML_DSA_44) == 0) && - (wc_dilithium_import_private(mem, - (word32)memSz, dilithium) == 0)); - if (!isDilithium) { - isDilithium = ((wc_dilithium_set_level(dilithium, WC_ML_DSA_65) == 0) && - (wc_dilithium_import_private(mem, - (word32)memSz, dilithium) == 0)); - } - if (!isDilithium) { - isDilithium = ((wc_dilithium_set_level(dilithium, WC_ML_DSA_87) == 0) && - (wc_dilithium_import_private(mem, - (word32)memSz, dilithium) == 0)); - } - } - else { - isDilithium = ((wc_dilithium_set_level(dilithium, WC_ML_DSA_44) == 0) && - (wc_dilithium_import_public(mem, (word32)memSz, - dilithium) == 0)); - if (!isDilithium) { - isDilithium = ((wc_dilithium_set_level(dilithium, WC_ML_DSA_65) == 0) && - (wc_dilithium_import_public(mem, (word32)memSz, - dilithium) == 0)); - } - if (!isDilithium) { - isDilithium = ((wc_dilithium_set_level(dilithium, WC_ML_DSA_87) == 0) && - (wc_dilithium_import_public(mem, (word32)memSz, - dilithium) == 0)); - } - } - wc_dilithium_free(dilithium); - WC_FREE_VAR_EX(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM); - - if (!isDilithium) { - return WOLFSSL_FATAL_ERROR; - } - - if (*out != NULL) { - pkey = *out; - } - else { - /* Create a fake Dilithium EVP_PKEY. In the future, we might - * integrate Dilithium into the compatibility layer. */ - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) { - WOLFSSL_MSG("Dilithium wolfSSL_EVP_PKEY_new error"); - return 0; - } - } - pkey->type = WC_EVP_PKEY_DILITHIUM; - pkey->pkey.ptr = NULL; - pkey->pkey_sz = 0; +/* + * TODO This ssl parameter needs to be changed to const once our ABI checker + * stops flagging qualifier additions as ABI breaking. + */ +WOLFSSL_ABI +int wolfSSL_pending(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_pending"); + if (ssl == NULL) + return WOLFSSL_FAILURE; - *out = pkey; - return 1; + return (int)ssl->buffers.clearOutputBuffer.length; } -#endif /* HAVE_DILITHIUM */ -static WOLFSSL_EVP_PKEY* d2iGenericKey(WOLFSSL_EVP_PKEY** out, - const unsigned char** in, long inSz, int priv) +int wolfSSL_has_pending(const WOLFSSL* ssl) { - WOLFSSL_EVP_PKEY* pkey = NULL; + WOLFSSL_ENTER("wolfSSL_has_pending"); + if (ssl == NULL) + return WOLFSSL_FAILURE; - WOLFSSL_ENTER("d2iGenericKey"); + return ssl->buffers.clearOutputBuffer.length > 0; +} - if (in == NULL || *in == NULL || inSz < 0) { - WOLFSSL_MSG("Bad argument"); - return NULL; - } +#ifndef WOLFSSL_LEANPSK +/* turn on handshake group messages for context */ +int wolfSSL_CTX_set_group_messages(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; - if ((out != NULL) && (*out != NULL)) { - pkey = *out; - } + ctx->groupMessages = 1; -#if !defined(NO_RSA) - if (d2iTryRsaKey(&pkey, *in, inSz, priv) >= 0) { - ; - } - else -#endif /* NO_RSA */ -#if defined(HAVE_ECC) && defined(OPENSSL_EXTRA) - if (d2iTryEccKey(&pkey, *in, inSz, priv) >= 0) { - ; - } - else -#endif /* HAVE_ECC && OPENSSL_EXTRA */ -#if !defined(NO_DSA) - if (d2iTryDsaKey(&pkey, *in, inSz, priv) >= 0) { - ; - } - else -#endif /* NO_DSA */ -#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ - (HAVE_FIPS_VERSION > 2)) - if (d2iTryDhKey(&pkey, *in, inSz, priv) >= 0) { - ; - } - else -#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ -#endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */ + return WOLFSSL_SUCCESS; +} -#if !defined(NO_DH) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_DH_EXTRA) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ - (HAVE_FIPS_VERSION > 2)) - if (d2iTryAltDhKey(&pkey, *in, inSz, priv) >= 0) { - ; - } - else -#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ -#endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */ +int wolfSSL_CTX_clear_group_messages(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; -#ifdef HAVE_FALCON - if (d2iTryFalconKey(&pkey, *in, inSz, priv) >= 0) { - ; - } - else -#endif /* HAVE_FALCON */ -#ifdef HAVE_DILITHIUM - if (d2iTryDilithiumKey(&pkey, *in, inSz, priv) >= 0) { - ; - } - else -#endif /* HAVE_DILITHIUM */ - { - WOLFSSL_MSG("wolfSSL_d2i_PUBKEY couldn't determine key type"); - } + ctx->groupMessages = 0; - if ((pkey != NULL) && (out != NULL)) { - *out = pkey; - } - return pkey; + return WOLFSSL_SUCCESS; } -#endif /* OPENSSL_EXTRA || WPA_SMALL */ +#endif -#ifdef OPENSSL_EXTRA -WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY( - WOLFSSL_PKCS8_PRIV_KEY_INFO** pkey, const unsigned char** keyBuf, - long keyLen) +#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_TLS) +/* connect enough to get peer cert chain */ +int wolfSSL_connect_cert(WOLFSSL* ssl) { - WOLFSSL_PKCS8_PRIV_KEY_INFO* pkcs8 = NULL; -#ifdef WOLFSSL_PEM_TO_DER - int ret; - DerBuffer* pkcs8Der = NULL; - DerBuffer rawDer; - EncryptedInfo info; - int advanceLen = 0; - - XMEMSET(&info, 0, sizeof(info)); - XMEMSET(&rawDer, 0, sizeof(rawDer)); + int ret; - if (keyBuf == NULL || *keyBuf == NULL || keyLen <= 0) { - WOLFSSL_MSG("Bad key PEM/DER args"); - return NULL; - } + if (ssl == NULL) + return WOLFSSL_FAILURE; - ret = PemToDer(*keyBuf, keyLen, PRIVATEKEY_TYPE, &pkcs8Der, NULL, &info, - NULL); - if (ret < 0) { - WOLFSSL_MSG("Not PEM format"); - ret = AllocDer(&pkcs8Der, (word32)keyLen, PRIVATEKEY_TYPE, NULL); - if (ret == 0) { - XMEMCPY(pkcs8Der->buffer, *keyBuf, keyLen); - } - } - else { - advanceLen = (int)info.consumed; - } + ssl->options.certOnly = 1; + ret = wolfSSL_connect(ssl); + ssl->options.certOnly = 0; - if (ret == 0) { - /* Verify this is PKCS8 Key */ - word32 inOutIdx = 0; - word32 algId; - ret = ToTraditionalInline_ex(pkcs8Der->buffer, &inOutIdx, - pkcs8Der->length, &algId); - if (ret >= 0) { - if (advanceLen == 0) /* Set only if not PEM */ - advanceLen = (int)inOutIdx + ret; - if (algId == DHk) { - /* Special case for DH as we expect the DER buffer to be always - * be in PKCS8 format */ - rawDer.buffer = pkcs8Der->buffer; - rawDer.length = inOutIdx + (word32)ret; - } - else { - rawDer.buffer = pkcs8Der->buffer + inOutIdx; - rawDer.length = (word32)ret; - } - ret = 0; /* good DER */ - } - } + return ret; +} +#endif - if (ret == 0) { - pkcs8 = wolfSSL_EVP_PKEY_new(); - if (pkcs8 == NULL) - ret = MEMORY_E; - } - if (ret == 0) { - pkcs8->pkey.ptr = (char*)XMALLOC(rawDer.length, NULL, - DYNAMIC_TYPE_PUBLIC_KEY); - if (pkcs8->pkey.ptr == NULL) - ret = MEMORY_E; - } - if (ret == 0) { - XMEMCPY(pkcs8->pkey.ptr, rawDer.buffer, rawDer.length); - pkcs8->pkey_sz = (int)rawDer.length; - } - FreeDer(&pkcs8Der); - if (ret != 0) { - wolfSSL_EVP_PKEY_free(pkcs8); - pkcs8 = NULL; - } - else { - *keyBuf += advanceLen; - } - if (pkey != NULL) { - *pkey = pkcs8; - } +#ifndef WOLFSSL_LEANPSK +/* turn on handshake group messages for ssl object */ +int wolfSSL_set_group_messages(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; -#else - (void)bio; - (void)pkey; -#endif /* WOLFSSL_PEM_TO_DER */ + ssl->options.groupMessages = 1; - return pkcs8; + return WOLFSSL_SUCCESS; } -#ifdef OPENSSL_ALL -int wolfSSL_i2d_PKCS8_PKEY(WOLFSSL_PKCS8_PRIV_KEY_INFO* key, unsigned char** pp) +int wolfSSL_clear_group_messages(WOLFSSL* ssl) { - word32 keySz = 0; - unsigned char* out; - int len; + if (ssl == NULL) + return BAD_FUNC_ARG; - WOLFSSL_ENTER("wolfSSL_i2d_PKCS8_PKEY"); + ssl->options.groupMessages = 0; - if (key == NULL) - return WOLFSSL_FATAL_ERROR; + return WOLFSSL_SUCCESS; +} - if (pkcs8_encode(key, NULL, &keySz) != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) - return WOLFSSL_FATAL_ERROR; - len = (int)keySz; +/* make minVersion the internal equivalent SSL version */ +static int SetMinVersionHelper(byte* minVersion, int version) +{ + (void)minVersion; + + switch (version) { +#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) + case WOLFSSL_SSLV3: + *minVersion = SSLv3_MINOR; + break; +#endif - if ((pp == NULL) || (len == 0)) - return len; +#ifndef NO_TLS + #ifndef NO_OLD_TLS + #ifdef WOLFSSL_ALLOW_TLSV10 + case WOLFSSL_TLSV1: + *minVersion = TLSv1_MINOR; + break; + #endif - if (*pp == NULL) { - out = (unsigned char*)XMALLOC((size_t)len, NULL, DYNAMIC_TYPE_ASN1); - if (out == NULL) - return WOLFSSL_FATAL_ERROR; - } - else { - out = *pp; - } + case WOLFSSL_TLSV1_1: + *minVersion = TLSv1_1_MINOR; + break; + #endif + #ifndef WOLFSSL_NO_TLS12 + case WOLFSSL_TLSV1_2: + *minVersion = TLSv1_2_MINOR; + break; + #endif +#endif + #ifdef WOLFSSL_TLS13 + case WOLFSSL_TLSV1_3: + *minVersion = TLSv1_3_MINOR; + break; + #endif + +#ifdef WOLFSSL_DTLS + case WOLFSSL_DTLSV1: + *minVersion = DTLS_MINOR; + break; + case WOLFSSL_DTLSV1_2: + *minVersion = DTLSv1_2_MINOR; + break; +#ifdef WOLFSSL_DTLS13 + case WOLFSSL_DTLSV1_3: + *minVersion = DTLSv1_3_MINOR; + break; +#endif /* WOLFSSL_DTLS13 */ +#endif /* WOLFSSL_DTLS */ - if (pkcs8_encode(key, out, &keySz) != len) { - if (*pp == NULL) - XFREE(out, NULL, DYNAMIC_TYPE_ASN1); - return WOLFSSL_FATAL_ERROR; + default: + WOLFSSL_MSG("Bad function argument"); + return BAD_FUNC_ARG; } - if (*pp == NULL) - *pp = out; - else - *pp += len; - - return len; + return WOLFSSL_SUCCESS; } -#endif -#ifndef NO_BIO -/* put SSL type in extra for now, not very common */ -/* Converts a DER format key read from "bio" to a PKCS8 structure. - * - * bio input bio to read DER from - * pkey If not NULL then this pointer will be overwritten with a new PKCS8 - * structure. - * - * returns a WOLFSSL_PKCS8_PRIV_KEY_INFO pointer on success and NULL in fail - * case. - */ -WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY_bio(WOLFSSL_BIO* bio, - WOLFSSL_PKCS8_PRIV_KEY_INFO** pkey) +/* Set minimum downgrade version allowed, WOLFSSL_SUCCESS on ok */ +WOLFSSL_ABI +int wolfSSL_CTX_SetMinVersion(WOLFSSL_CTX* ctx, int version) { - WOLFSSL_PKCS8_PRIV_KEY_INFO* pkcs8 = NULL; -#ifdef WOLFSSL_PEM_TO_DER - unsigned char* mem = NULL; - int memSz; - - WOLFSSL_ENTER("wolfSSL_d2i_PKCS8_PKEY_bio"); + WOLFSSL_ENTER("wolfSSL_CTX_SetMinVersion"); - if (bio == NULL) { - return NULL; + if (ctx == NULL) { + WOLFSSL_MSG("Bad function argument"); + return BAD_FUNC_ARG; } - if ((memSz = wolfSSL_BIO_get_mem_data(bio, &mem)) < 0) { - return NULL; +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled) { + return CRYPTO_POLICY_FORBIDDEN; } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - pkcs8 = wolfSSL_d2i_PKCS8_PKEY(pkey, (const unsigned char**)&mem, memSz); -#else - (void)bio; - (void)pkey; -#endif /* WOLFSSL_PEM_TO_DER */ - - return pkcs8; + return SetMinVersionHelper(&ctx->minDowngrade, version); } -/* expecting DER format public key - * - * bio input bio to read DER from - * out If not NULL then this pointer will be overwritten with a new - * WOLFSSL_EVP_PKEY pointer - * - * returns a WOLFSSL_EVP_PKEY pointer on success and NULL in fail case. - */ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY_bio(WOLFSSL_BIO* bio, - WOLFSSL_EVP_PKEY** out) +/* Set minimum downgrade version allowed, WOLFSSL_SUCCESS on ok */ +int wolfSSL_SetMinVersion(WOLFSSL* ssl, int version) { - unsigned char* mem; - long memSz; - WOLFSSL_EVP_PKEY* pkey = NULL; - - WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY_bio"); - - if (bio == NULL) { - return NULL; - } - (void)out; - - memSz = wolfSSL_BIO_get_len(bio); - if (memSz <= 0) { - return NULL; - } + WOLFSSL_ENTER("wolfSSL_SetMinVersion"); - mem = (unsigned char*)XMALLOC((size_t)memSz, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (mem == NULL) { - return NULL; + if (ssl == NULL) { + WOLFSSL_MSG("Bad function argument"); + return BAD_FUNC_ARG; } - if (wolfSSL_BIO_read(bio, mem, (int)memSz) == memSz) { - pkey = wolfSSL_d2i_PUBKEY(NULL, (const unsigned char**)&mem, memSz); - if (out != NULL && pkey != NULL) { - *out = pkey; - } +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + if (crypto_policy.enabled) { + return CRYPTO_POLICY_FORBIDDEN; } +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - return pkey; -} - -#endif /* !NO_BIO */ - - -/* Converts a DER encoded public key to a WOLFSSL_EVP_PKEY structure. - * - * out pointer to new WOLFSSL_EVP_PKEY structure. Can be NULL - * in DER buffer to convert - * inSz size of in buffer - * - * returns a pointer to a new WOLFSSL_EVP_PKEY structure on success and NULL - * on fail - */ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY(WOLFSSL_EVP_PKEY** out, - const unsigned char** in, long inSz) -{ - WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY"); - return d2iGenericKey(out, in, inSz, 0); + return SetMinVersionHelper(&ssl->options.minDowngrade, version); } -#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && !defined(NO_ASN) && \ - !defined(NO_PWDBASED) -/* helper function to get raw pointer to DER buffer from WOLFSSL_EVP_PKEY */ -static int wolfSSL_EVP_PKEY_get_der(const WOLFSSL_EVP_PKEY* key, - unsigned char** der) +/* Function to get version as WOLFSSL_ enum value for wolfSSL_SetVersion */ +int wolfSSL_GetVersion(const WOLFSSL* ssl) { - int sz; - word16 pkcs8HeaderSz; - - if (!key || !key->pkey_sz) - return WOLFSSL_FATAL_ERROR; + if (ssl == NULL) + return BAD_FUNC_ARG; - /* return the key without PKCS8 for compatibility */ - /* if pkcs8HeaderSz is invalid, use 0 and return all of pkey */ - pkcs8HeaderSz = 0; - if (key->pkey_sz > key->pkcs8HeaderSz) - pkcs8HeaderSz = key->pkcs8HeaderSz; - sz = key->pkey_sz - pkcs8HeaderSz; - if (der) { - unsigned char* pt = (unsigned char*)key->pkey.ptr; - if (*der) { - /* since this function signature has no size value passed in it is - * assumed that the user has allocated a large enough buffer */ - XMEMCPY(*der, pt + pkcs8HeaderSz, (size_t)sz); - *der += sz; + if (ssl->version.major == SSLv3_MAJOR) { + switch (ssl->version.minor) { + case SSLv3_MINOR : + return WOLFSSL_SSLV3; + case TLSv1_MINOR : + return WOLFSSL_TLSV1; + case TLSv1_1_MINOR : + return WOLFSSL_TLSV1_1; + case TLSv1_2_MINOR : + return WOLFSSL_TLSV1_2; + case TLSv1_3_MINOR : + return WOLFSSL_TLSV1_3; + default: + break; } - else { - *der = (unsigned char*)XMALLOC((size_t)sz, NULL, - DYNAMIC_TYPE_OPENSSL); - if (*der == NULL) { - return WOLFSSL_FATAL_ERROR; - } - XMEMCPY(*der, pt + pkcs8HeaderSz, (size_t)sz); + } +#ifdef WOLFSSL_DTLS + if (ssl->version.major == DTLS_MAJOR) { + switch (ssl->version.minor) { + case DTLS_MINOR : + return WOLFSSL_DTLSV1; + case DTLSv1_2_MINOR : + return WOLFSSL_DTLSV1_2; + case DTLSv1_3_MINOR : + return WOLFSSL_DTLSV1_3; + default: + break; } } - return sz; -} +#endif /* WOLFSSL_DTLS */ -int wolfSSL_i2d_PUBKEY(const WOLFSSL_EVP_PKEY *key, unsigned char **der) -{ - return wolfSSL_i2d_PublicKey(key, der); + return VERSION_ERROR; } -#endif /* OPENSSL_EXTRA && !NO_CERTS && !NO_ASN && !NO_PWDBASED */ - -static WOLFSSL_EVP_PKEY* _d2i_PublicKey(int type, WOLFSSL_EVP_PKEY** out, - const unsigned char **in, long inSz, int priv) +int wolfSSL_SetVersion(WOLFSSL* ssl, int version) { - int ret = 0; - word32 idx = 0, algId; - word16 pkcs8HeaderSz = 0; - WOLFSSL_EVP_PKEY* local; - int opt = 0; - - (void)opt; - - if (in == NULL || inSz < 0) { - WOLFSSL_MSG("Bad argument"); - return NULL; - } - - if (priv == 1) { - /* Check if input buffer has PKCS8 header. In the case that it does not - * have a PKCS8 header then do not error out. */ - if ((ret = ToTraditionalInline_ex((const byte*)(*in), &idx, - (word32)inSz, &algId)) > 0) { - WOLFSSL_MSG("Found PKCS8 header"); - pkcs8HeaderSz = (word16)idx; - - if ((type == WC_EVP_PKEY_RSA && algId != RSAk - #ifdef WC_RSA_PSS - && algId != RSAPSSk - #endif - ) || - (type == WC_EVP_PKEY_EC && algId != ECDSAk) || - (type == WC_EVP_PKEY_DSA && algId != DSAk) || - (type == WC_EVP_PKEY_DH && algId != DHk)) { - WOLFSSL_MSG("PKCS8 does not match EVP key type"); - return NULL; - } + word16 haveRSA = 1; + word16 havePSK = 0; + int keySz = 0; - (void)idx; /* not used */ - } - else { - if (ret != WC_NO_ERR_TRACE(ASN_PARSE_E)) { - WOLFSSL_MSG("Unexpected error with trying to remove PKCS8 " - "header"); - return NULL; - } - } - } + WOLFSSL_ENTER("wolfSSL_SetVersion"); - if (out != NULL && *out != NULL) { - wolfSSL_EVP_PKEY_free(*out); - *out = NULL; - } - local = wolfSSL_EVP_PKEY_new(); - if (local == NULL) { - return NULL; + if (ssl == NULL) { + WOLFSSL_MSG("Bad function argument"); + return BAD_FUNC_ARG; } - local->type = type; - local->pkey_sz = (int)inSz; - local->pkcs8HeaderSz = pkcs8HeaderSz; - local->pkey.ptr = (char*)XMALLOC((size_t)inSz, NULL, - DYNAMIC_TYPE_PUBLIC_KEY); - if (local->pkey.ptr == NULL) { - wolfSSL_EVP_PKEY_free(local); - local = NULL; - return NULL; - } - else { - XMEMCPY(local->pkey.ptr, *in, (size_t)inSz); - } + switch (version) { +#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS) + case WOLFSSL_SSLV3: + ssl->version = MakeSSLv3(); + break; +#endif - switch (type) { -#ifndef NO_RSA - case WC_EVP_PKEY_RSA: - opt = priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC; - local->ownRsa = 1; - local->rsa = wolfssl_rsa_d2i(NULL, - (const unsigned char*)local->pkey.ptr, local->pkey_sz, opt); - if (local->rsa == NULL) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } +#ifndef NO_TLS + #ifndef NO_OLD_TLS + #ifdef WOLFSSL_ALLOW_TLSV10 + case WOLFSSL_TLSV1: + ssl->version = MakeTLSv1(); break; -#endif /* NO_RSA */ -#ifdef HAVE_ECC - case WC_EVP_PKEY_EC: - local->ownEcc = 1; - local->ecc = wolfSSL_EC_KEY_new(); - if (local->ecc == NULL) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - opt = priv ? WOLFSSL_EC_KEY_LOAD_PRIVATE : - WOLFSSL_EC_KEY_LOAD_PUBLIC; - if (wolfSSL_EC_KEY_LoadDer_ex(local->ecc, - (const unsigned char*)local->pkey.ptr, local->pkey_sz, - opt) - != WOLFSSL_SUCCESS) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } + #endif + + case WOLFSSL_TLSV1_1: + ssl->version = MakeTLSv1_1(); break; -#endif /* HAVE_ECC */ -#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH) -#ifndef NO_DSA - case WC_EVP_PKEY_DSA: - local->ownDsa = 1; - local->dsa = wolfSSL_DSA_new(); - if (local->dsa == NULL) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - opt = priv ? WOLFSSL_DSA_LOAD_PRIVATE : WOLFSSL_DSA_LOAD_PUBLIC; - if (wolfSSL_DSA_LoadDer_ex(local->dsa, - (const unsigned char*)local->pkey.ptr, local->pkey_sz, - opt) - != WOLFSSL_SUCCESS) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } + #endif + #ifndef WOLFSSL_NO_TLS12 + case WOLFSSL_TLSV1_2: + ssl->version = MakeTLSv1_2(); break; -#endif /* NO_DSA */ -#ifndef NO_DH -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) - case WC_EVP_PKEY_DH: - local->ownDh = 1; - local->dh = wolfSSL_DH_new(); - if (local->dh == NULL) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - if (wolfSSL_DH_LoadDer(local->dh, - (const unsigned char*)local->pkey.ptr, local->pkey_sz) - != WOLFSSL_SUCCESS) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } + #endif + + #ifdef WOLFSSL_TLS13 + case WOLFSSL_TLSV1_3: + ssl->version = MakeTLSv1_3(); break; -#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ -#endif /* HAVE_DH */ -#endif /* WOLFSSL_QT || OPENSSL_ALL || WOLFSSL_OPENSSH */ + #endif /* WOLFSSL_TLS13 */ +#endif + default: - WOLFSSL_MSG("Unsupported key type"); - wolfSSL_EVP_PKEY_free(local); - return NULL; + WOLFSSL_MSG("Bad function argument"); + return BAD_FUNC_ARG; } - /* advance pointer with success */ - if (local != NULL) { - if (local->pkey_sz <= (int)inSz) { - *in += local->pkey_sz; - } + ssl->options.downgrade = 0; - if (out != NULL) { - *out = local; - } - } + #ifdef NO_RSA + haveRSA = 0; + #endif + #ifndef NO_PSK + havePSK = ssl->options.havePSK; + #endif + #ifndef NO_CERTS + keySz = ssl->buffers.keySz; + #endif - return local; + if (AllocateSuites(ssl) != 0) + return WOLFSSL_FAILURE; + InitSuites(ssl->suites, ssl->version, keySz, haveRSA, havePSK, + ssl->options.haveDH, ssl->options.haveECDSAsig, + ssl->options.haveECC, TRUE, ssl->options.haveStaticECC, + ssl->options.useAnon, TRUE, TRUE, TRUE, TRUE, ssl->options.side); + return WOLFSSL_SUCCESS; } +#endif /* !leanpsk */ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PublicKey(int type, WOLFSSL_EVP_PKEY** out, - const unsigned char **in, long inSz) -{ - WOLFSSL_ENTER("wolfSSL_d2i_PublicKey"); +#if defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_OPENSSL_RAND_CB) +static int wolfSSL_RAND_InitMutex(void); +#endif - return _d2i_PublicKey(type, out, in, inSz, 0); -} -/* Reads in a DER format key. If PKCS8 headers are found they are stripped off. - * - * type type of key - * out newly created WOLFSSL_EVP_PKEY structure - * in pointer to input key DER - * inSz size of in buffer +/* If we don't have static mutex initializers, but we do have static atomic + * initializers, activate WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS to leverage + * the latter. * - * On success a non null pointer is returned and the pointer in is advanced the - * same number of bytes read. + * See further explanation below in wolfSSL_Init(). */ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey(int type, WOLFSSL_EVP_PKEY** out, - const unsigned char **in, long inSz) -{ - WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey"); +#ifndef WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS + #if !defined(WOLFSSL_MUTEX_INITIALIZER) && !defined(SINGLE_THREADED) && \ + defined(WOLFSSL_ATOMIC_OPS) && defined(WOLFSSL_ATOMIC_INITIALIZER) + #define WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS 1 + #else + #define WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS 0 + #endif +#elif defined(WOLFSSL_MUTEX_INITIALIZER) || defined(SINGLE_THREADED) + #undef WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS + #define WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS 0 +#endif + +#if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS + #ifndef WOLFSSL_ATOMIC_OPS + #error WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS requires WOLFSSL_ATOMIC_OPS + #endif + #ifndef WOLFSSL_ATOMIC_INITIALIZER + #error WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS requires WOLFSSL_ATOMIC_INITIALIZER + #endif + static wolfSSL_Atomic_Int inits_count_mutex_atomic_initing_flag = + WOLFSSL_ATOMIC_INITIALIZER(0); +#endif /* WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS && !WOLFSSL_MUTEX_INITIALIZER */ - return _d2i_PublicKey(type, out, in, inSz, 1); +#if defined(OPENSSL_EXTRA) && defined(HAVE_ATEXIT) +static void AtExitCleanup(void) +{ + if (initRefCount > 0) { + initRefCount = 1; + (void)wolfSSL_Cleanup(); +#if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS + if (inits_count_mutex_valid == 1) { + (void)wc_FreeMutex(&inits_count_mutex); + inits_count_mutex_valid = 0; + inits_count_mutex_atomic_initing_flag = 0; + } +#endif + } } +#endif -#ifdef WOLF_PRIVATE_KEY_ID -/* Create an EVP structure for use with crypto callbacks */ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_id(int type, WOLFSSL_EVP_PKEY** out, - void* heap, int devId) +WOLFSSL_ABI +int wolfSSL_Init(void) { - WOLFSSL_EVP_PKEY* local; + int ret = WOLFSSL_SUCCESS; +#if !defined(NO_SESSION_CACHE) && defined(ENABLE_SESSION_CACHE_ROW_LOCK) + int i; +#endif - if (out != NULL && *out != NULL) { - wolfSSL_EVP_PKEY_free(*out); - *out = NULL; - } + WOLFSSL_ENTER("wolfSSL_Init"); - local = wolfSSL_EVP_PKEY_new_ex(heap); - if (local == NULL) { - return NULL; - } +#if defined(LIBWOLFSSL_CMAKE_OUTPUT) + WOLFSSL_MSG(LIBWOLFSSL_CMAKE_OUTPUT); +#else + WOLFSSL_MSG("No extra wolfSSL cmake messages found"); +#endif - local->type = type; - local->pkey_sz = 0; - local->pkcs8HeaderSz = 0; +#ifndef WOLFSSL_MUTEX_INITIALIZER + if (inits_count_mutex_valid == 0) { + #if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS - switch (type) { -#ifndef NO_RSA - case WC_EVP_PKEY_RSA: + /* Without this mitigation, if two threads enter wolfSSL_Init() at the + * same time, and both see zero inits_count_mutex_valid, then both will + * run wc_InitMutex(&inits_count_mutex), leading to process corruption + * or (best case) a resource leak. + * + * When WOLFSSL_ATOMIC_INITIALIZER() is available, we can mitigate this + * by use an atomic counting int as a mutex. + */ + + if (wolfSSL_Atomic_Int_FetchAdd(&inits_count_mutex_atomic_initing_flag, + 1) != 0) { - RsaKey* key; - local->ownRsa = 1; - local->rsa = wolfSSL_RSA_new_ex(heap, devId); - if (local->rsa == NULL) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - key = (RsaKey*)local->rsa->internal; - #ifdef WOLF_CRYPTO_CB - key->devId = devId; - #endif - (void)key; - local->rsa->inSet = 1; - break; + (void)wolfSSL_Atomic_Int_FetchSub( + &inits_count_mutex_atomic_initing_flag, 1); + return DEADLOCK_AVERTED_E; } -#endif /* !NO_RSA */ -#ifdef HAVE_ECC - case WC_EVP_PKEY_EC: - { - ecc_key* key; - local->ownEcc = 1; - local->ecc = wolfSSL_EC_KEY_new_ex(heap, devId); - if (local->ecc == NULL) { - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - key = (ecc_key*)local->ecc->internal; - #ifdef WOLF_CRYPTO_CB - key->devId = devId; - #endif - key->type = ECC_PRIVATEKEY; - /* key is required to have a key size / curve set, although - * actual one used is determined by devId callback function */ - wc_ecc_set_curve(key, ECDHE_SIZE, ECC_CURVE_DEF); - - local->ecc->inSet = 1; - break; + #endif /* WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS */ + if (wc_InitMutex(&inits_count_mutex) != 0) { + WOLFSSL_MSG("Bad Init Mutex count"); + #if WOLFSSL_CLEANUP_THREADSAFE_BY_ATOMIC_OPS + (void)wolfSSL_Atomic_Int_FetchSub( + &inits_count_mutex_atomic_initing_flag, 1); + #endif + return BAD_MUTEX_E; + } + else { + inits_count_mutex_valid = 1; } -#endif /* HAVE_ECC */ - default: - WOLFSSL_MSG("Unsupported private key id type"); - wolfSSL_EVP_PKEY_free(local); - return NULL; } +#endif /* !WOLFSSL_MUTEX_INITIALIZER */ - if (local != NULL && out != NULL) { - *out = local; + if (wc_LockMutex(&inits_count_mutex) != 0) { + WOLFSSL_MSG("Bad Lock Mutex count"); + return BAD_MUTEX_E; } - return local; -} -#endif /* WOLF_PRIVATE_KEY_ID */ - -#ifndef NO_CERTS /* // NOLINT(readability-redundant-preprocessor) */ - -#ifndef NO_CHECK_PRIVATE_KEY -/* Check private against public in certificate for match - * - * ssl WOLFSSL structure to check private key in - * - * Returns WOLFSSL_SUCCESS on good private key - * WOLFSSL_FAILURE if mismatched. */ -int wolfSSL_check_private_key(const WOLFSSL* ssl) -{ - int res = WOLFSSL_SUCCESS; - -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - DerBuffer *privateKey; -#ifdef WOLFSSL_DUAL_ALG_CERTS - DerBuffer *altPrivateKey; -#endif -#else - const DerBuffer *privateKey; -#ifdef WOLFSSL_DUAL_ALG_CERTS - const DerBuffer *altPrivateKey; -#endif -#endif - - if (ssl == NULL) { - return WOLFSSL_FAILURE; - } -#ifdef WOLFSSL_DUAL_ALG_CERTS -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - privateKey = wolfssl_priv_der_unblind(ssl->buffers.key, - ssl->buffers.keyMask); - if (privateKey == NULL) { - res = WOLFSSL_FAILURE; - } - if (ssl->buffers.altKey != NULL) { - altPrivateKey = wolfssl_priv_der_unblind(ssl->buffers.altKey, - ssl->buffers.altKeyMask); - if (altPrivateKey == NULL) { - res = WOLFSSL_FAILURE; - } - } - else { - altPrivateKey = NULL; - } -#else - privateKey = ssl->buffers.key; - altPrivateKey = ssl->buffers.altKey; -#endif - if (res == WOLFSSL_SUCCESS) { - res = check_cert_key(ssl->buffers.certificate, privateKey, - altPrivateKey, ssl->heap, ssl->buffers.keyDevId, - ssl->buffers.keyLabel, ssl->buffers.keyId, ssl->buffers.altKeyDevId, - ssl->buffers.altKeyLabel, ssl->buffers.altKeyId); - } -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - wolfssl_priv_der_unblind_free(privateKey); - wolfssl_priv_der_unblind_free(altPrivateKey); -#endif -#else -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - privateKey = wolfssl_priv_der_unblind(ssl->buffers.key, - ssl->buffers.keyMask); - if (privateKey == NULL) { - res = WOLFSSL_FAILURE; - } -#else - privateKey = ssl->buffers.key; -#endif - if (res == WOLFSSL_SUCCESS) { - res = check_cert_key(ssl->buffers.certificate, privateKey, NULL, - ssl->heap, ssl->buffers.keyDevId, ssl->buffers.keyLabel, - ssl->buffers.keyId, INVALID_DEVID, 0, 0); +#if FIPS_VERSION_GE(5,1) + if ((ret == WOLFSSL_SUCCESS) && (initRefCount == 0)) { + ret = wolfCrypt_SetPrivateKeyReadEnable_fips(1, WC_KEYTYPE_ALL); + if (ret == 0) + ret = WOLFSSL_SUCCESS; } -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - wolfssl_priv_der_unblind_free(privateKey); -#endif #endif - return res; -} -#endif /* !NO_CHECK_PRIVATE_KEY */ - -#endif /* !NO_CERTS */ + if ((ret == WOLFSSL_SUCCESS) && (initRefCount == 0)) { + /* Initialize crypto for use with TLS connection */ -#endif /* OPENSSL_EXTRA */ + if (wolfCrypt_Init() != 0) { + WOLFSSL_MSG("Bad wolfCrypt Init"); + ret = WC_INIT_E; + } -#if defined(HAVE_RPK) -/* Confirm that all the byte data in the buffer is unique. - * return 1 if all the byte data in the buffer is unique, otherwise 0. - */ -static int isArrayUnique(const char* buf, size_t len) -{ - size_t i, j; - /* check the array is unique */ - for (i = 0; i < len -1; ++i) { - for (j = i+ 1; j < len; ++j) { - if (buf[i] == buf[j]) { - return 0; +#if defined(HAVE_GLOBAL_RNG) && !defined(WOLFSSL_MUTEX_INITIALIZER) + if (ret == WOLFSSL_SUCCESS) { + if (wc_InitMutex(&globalRNGMutex) != 0) { + WOLFSSL_MSG("Bad Init Mutex rng"); + ret = BAD_MUTEX_E; + } + else { + globalRNGMutex_valid = 1; } } - } - return 1; -} - -/* Set user preference for the {client,server}_cert_type extension. - * Takes byte array containing cert types the caller can provide to its peer. - * Cert types are in preferred order in the array. - */ -static int set_cert_type(RpkConfig* cfg, - int client, const char* buf, int bufLen) -{ - int i; - byte* certTypeCnt; - byte* certTypes; - - if (cfg == NULL || bufLen > (client ? MAX_CLIENT_CERT_TYPE_CNT : - MAX_SERVER_CERT_TYPE_CNT)) { - return BAD_FUNC_ARG; - } +#endif - if (client) { - certTypeCnt = &cfg->preferred_ClientCertTypeCnt; - certTypes = cfg->preferred_ClientCertTypes; - } - else { - certTypeCnt = &cfg->preferred_ServerCertTypeCnt; - certTypes = cfg->preferred_ServerCertTypes; - } - /* if buf is set to NULL or bufLen is zero, it defaults the setting*/ - if (buf == NULL || bufLen == 0) { - *certTypeCnt = 1; - for (i = 0; i < 2; i++) - certTypes[i] = WOLFSSL_CERT_TYPE_X509; - return WOLFSSL_SUCCESS; - } + #ifdef WC_RNG_SEED_CB + wc_SetSeed_Cb(WC_GENERATE_SEED_DEFAULT); + #endif - if (!isArrayUnique(buf, (size_t)bufLen)) - return BAD_FUNC_ARG; +#ifdef OPENSSL_EXTRA + #ifndef WOLFSSL_NO_OPENSSL_RAND_CB + if ((ret == WOLFSSL_SUCCESS) && (wolfSSL_RAND_InitMutex() != 0)) { + ret = BAD_MUTEX_E; + } + #endif + if ((ret == WOLFSSL_SUCCESS) && + (wolfSSL_RAND_seed(NULL, 0) != WOLFSSL_SUCCESS)) { + WOLFSSL_MSG("wolfSSL_RAND_seed failed"); + ret = WC_INIT_E; + } +#endif - for (i = 0; i < bufLen; i++) { - if (buf[i] != WOLFSSL_CERT_TYPE_RPK && buf[i] != WOLFSSL_CERT_TYPE_X509) - return BAD_FUNC_ARG; - certTypes[i] = (byte)buf[i]; +#ifndef NO_SESSION_CACHE + #ifdef ENABLE_SESSION_CACHE_ROW_LOCK + for (i = 0; i < SESSION_ROWS; ++i) { + SessionCache[i].lock_valid = 0; + } + for (i = 0; (ret == WOLFSSL_SUCCESS) && (i < SESSION_ROWS); ++i) { + if (wc_InitRwLock(&SessionCache[i].row_lock) != 0) { + WOLFSSL_MSG("Bad Init Mutex session"); + ret = BAD_MUTEX_E; + } + else { + SessionCache[i].lock_valid = 1; + } + } + #else + if (ret == WOLFSSL_SUCCESS) { + if (wc_InitRwLock(&session_lock) != 0) { + WOLFSSL_MSG("Bad Init Mutex session"); + ret = BAD_MUTEX_E; + } + else { + session_lock_valid = 1; + } + } + #endif + #ifndef NO_CLIENT_CACHE + #ifndef WOLFSSL_MUTEX_INITIALIZER + if (ret == WOLFSSL_SUCCESS) { + if (wc_InitMutex(&clisession_mutex) != 0) { + WOLFSSL_MSG("Bad Init Mutex session"); + ret = BAD_MUTEX_E; + } + else { + clisession_mutex_valid = 1; + } + } + #endif + #endif +#endif +#if defined(OPENSSL_EXTRA) && defined(HAVE_ATEXIT) + /* OpenSSL registers cleanup using atexit */ + if ((ret == WOLFSSL_SUCCESS) && (atexit(AtExitCleanup) != 0)) { + WOLFSSL_MSG("Bad atexit registration"); + ret = WC_INIT_E; + } +#endif } - *certTypeCnt = bufLen; - - return WOLFSSL_SUCCESS; -} -int wolfSSL_set_client_cert_type(WOLFSSL* ssl, const char* buf, int buflen) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - return set_cert_type(&ssl->options.rpkConfig, 1, buf, buflen); -} -int wolfSSL_set_server_cert_type(WOLFSSL* ssl, const char* buf, int buflen) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - return set_cert_type(&ssl->options.rpkConfig, 0, buf, buflen); -} -int wolfSSL_CTX_set_client_cert_type(WOLFSSL_CTX* ctx, - const char* buf, int buflen) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - return set_cert_type(&ctx->rpkConfig, 1, buf, buflen); -} -int wolfSSL_CTX_set_server_cert_type(WOLFSSL_CTX* ctx, - const char* buf, int buflen) -{ - if (ctx == NULL) - return BAD_FUNC_ARG; - return set_cert_type(&ctx->rpkConfig, 0, buf, buflen); -} - -/* get negotiated certificate type value and return it to the second parameter. - * cert type value: - * -1: WOLFSSL_CERT_TYPE_UNKNOWN - * 0: WOLFSSL_CERT_TYPE_X509 - * 2: WOLFSSL_CERT_TYPE_RPK - * return WOLFSSL_SUCCESS on success, otherwise negative value. - * in case no negotiation performed, it returns WOLFSSL_SUCCESS and -1 is for - * cert type. - */ -int wolfSSL_get_negotiated_client_cert_type(WOLFSSL* ssl, int* tp) -{ - int ret = WOLFSSL_SUCCESS; - if (ssl == NULL || tp == NULL) - return BAD_FUNC_ARG; +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) + /* System wide crypto policy disabled by default. */ + XMEMSET(&crypto_policy, 0, sizeof(crypto_policy)); +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ - if (ssl->options.side == WOLFSSL_CLIENT_END) { - if (ssl->options.rpkState.received_ClientCertTypeCnt == 1) - *tp = ssl->options.rpkState.received_ClientCertTypes[0]; - else - *tp = WOLFSSL_CERT_TYPE_UNKNOWN; + if (ret == WOLFSSL_SUCCESS) { + initRefCount = initRefCount + 1; } else { - if (ssl->options.rpkState.sending_ClientCertTypeCnt == 1) - *tp = ssl->options.rpkState.sending_ClientCertTypes[0]; - else - *tp = WOLFSSL_CERT_TYPE_UNKNOWN; + initRefCount = 1; /* Force cleanup */ } - return ret; -} - -/* get negotiated certificate type value and return it to the second parameter. - * cert type value: - * -1: WOLFSSL_CERT_TYPE_UNKNOWN - * 0: WOLFSSL_CERT_TYPE_X509 - * 2: WOLFSSL_CERT_TYPE_RPK - * return WOLFSSL_SUCCESS on success, otherwise negative value. - * in case no negotiation performed, it returns WOLFSSL_SUCCESS and -1 is for - * cert type. - */ -int wolfSSL_get_negotiated_server_cert_type(WOLFSSL* ssl, int* tp) -{ - int ret = WOLFSSL_SUCCESS; - - if (ssl == NULL || tp == NULL) - return BAD_FUNC_ARG; - if (ssl->options.side == WOLFSSL_CLIENT_END) { - if (ssl->options.rpkState.received_ServerCertTypeCnt == 1) - *tp = ssl->options.rpkState.received_ServerCertTypes[0]; - else - *tp = WOLFSSL_CERT_TYPE_UNKNOWN; - } - else { - if (ssl->options.rpkState.sending_ServerCertTypeCnt == 1) - *tp = ssl->options.rpkState.sending_ServerCertTypes[0]; - else - *tp = WOLFSSL_CERT_TYPE_UNKNOWN; + wc_UnLockMutex(&inits_count_mutex); + + if (ret != WOLFSSL_SUCCESS) { + (void)wolfSSL_Cleanup(); /* Ignore any error from cleanup */ } + return ret; } -#endif /* HAVE_RPK */ - -#ifdef HAVE_ECC - -/* Set Temp CTX EC-DHE size in octets, can be 14 - 66 (112 - 521 bit) */ -int wolfSSL_CTX_SetTmpEC_DHE_Sz(WOLFSSL_CTX* ctx, word16 sz) +#if defined(WOLFSSL_SYS_CRYPTO_POLICY) +/* Helper function for wolfSSL_crypto_policy_enable and + * wolfSSL_crypto_policy_enable_buffer. + * + * Parses the crypto policy string, verifies values, + * and sets in global crypto policy struct. Not thread + * safe. String length has already been verified. + * + * Returns WOLFSSL_SUCCESS on success. + * Returns CRYPTO_POLICY_FORBIDDEN if already enabled. + * Returns < 0 on misc error. + * */ +static int crypto_policy_parse(void) { - WOLFSSL_ENTER("wolfSSL_CTX_SetTmpEC_DHE_Sz"); + const char * hdr = WOLFSSL_SECLEVEL_STR; + int sec_level = 0; + size_t i = 0; - if (ctx == NULL) - return BAD_FUNC_ARG; + /* All policies should begin with "@SECLEVEL=" (N={0..5}) followed + * by bulk cipher list. */ + if (XMEMCMP(crypto_policy.str, hdr, strlen(hdr)) != 0) { + WOLFSSL_MSG("error: crypto policy: invalid header"); + return WOLFSSL_BAD_FILE; + } - /* if 0 then get from loaded private key */ - if (sz == 0) { - /* applies only to ECDSA */ - if (ctx->privateKeyType != ecc_dsa_sa_algo) - return WOLFSSL_SUCCESS; + { + /* Extract the security level. */ + char * policy_mem = crypto_policy.str; + policy_mem += strlen(hdr); + sec_level = (int) (*policy_mem - '0'); + } - if (ctx->privateKeySz == 0) { - WOLFSSL_MSG("Must set private key/cert first"); - return BAD_FUNC_ARG; + if (sec_level < MIN_WOLFSSL_SEC_LEVEL || + sec_level > MAX_WOLFSSL_SEC_LEVEL) { + WOLFSSL_MSG_EX("error: invalid SECLEVEL: %d", sec_level); + return WOLFSSL_BAD_FILE; + } + + /* Remove trailing '\r' or '\n'. */ + for (i = 0; i < MAX_WOLFSSL_CRYPTO_POLICY_SIZE; ++i) { + if (crypto_policy.str[i] == '\0') { + break; } - sz = (word16)ctx->privateKeySz; + if (crypto_policy.str[i] == '\r' || crypto_policy.str[i] == '\n') { + crypto_policy.str[i] = '\0'; + break; + } } - /* check size */ -#if ECC_MIN_KEY_SZ > 0 - if (sz < ECC_MINSIZE) - return BAD_FUNC_ARG; -#endif - if (sz > ECC_MAXSIZE) - return BAD_FUNC_ARG; + #if defined(DEBUG_WOLFSSL_VERBOSE) + WOLFSSL_MSG_EX("info: SECLEVEL=%d", sec_level); + WOLFSSL_MSG_EX("info: using crypto-policy file: %s, %ld", policy_file, sz); + #endif /* DEBUG_WOLFSSL_VERBOSE */ - ctx->eccTempKeySz = sz; + crypto_policy.secLevel = sec_level; + crypto_policy.enabled = 1; return WOLFSSL_SUCCESS; } - -/* Set Temp SSL EC-DHE size in octets, can be 14 - 66 (112 - 521 bit) */ -int wolfSSL_SetTmpEC_DHE_Sz(WOLFSSL* ssl, word16 sz) +#ifndef NO_FILESYSTEM +/* Enables wolfSSL system wide crypto-policy, using the given policy + * file arg. If NULL is passed, then the default system crypto-policy + * file that was set at configure time will be used instead. + * + * While enabled: + * - TLS methods, min key sizes, and cipher lists are all configured + * automatically by the policy. + * - Attempting to use lesser strength parameters will fail with + * error CRYPTO_POLICY_FORBIDDEN. + * + * Disable with wolfSSL_crypto_policy_disable. + * + * Note: the wolfSSL_crypto_policy_X API are not thread safe, and should + * only be called at program init time. + * + * Returns WOLFSSL_SUCCESS on success. + * Returns CRYPTO_POLICY_FORBIDDEN if already enabled. + * Returns < 0 on misc error. + * */ +int wolfSSL_crypto_policy_enable(const char * policy_file) { - WOLFSSL_ENTER("wolfSSL_SetTmpEC_DHE_Sz"); + XFILE file; + long sz = 0; + size_t n_read = 0; - if (ssl == NULL) - return BAD_FUNC_ARG; + WOLFSSL_ENTER("wolfSSL_crypto_policy_enable"); - /* check size */ -#if ECC_MIN_KEY_SZ > 0 - if (sz < ECC_MINSIZE) - return BAD_FUNC_ARG; -#endif - if (sz > ECC_MAXSIZE) - return BAD_FUNC_ARG; + if (wolfSSL_crypto_policy_is_enabled()) { + WOLFSSL_MSG_EX("error: crypto policy already enabled: %s", + policy_file); + return CRYPTO_POLICY_FORBIDDEN; + } - ssl->eccTempKeySz = sz; + if (policy_file == NULL) { + /* Use the configure-time default if NULL passed. */ + policy_file = WC_STRINGIFY(WOLFSSL_CRYPTO_POLICY_FILE); + } - return WOLFSSL_SUCCESS; -} + if (policy_file == NULL || *policy_file == '\0') { + WOLFSSL_MSG("error: crypto policy empty file"); + return BAD_FUNC_ARG; + } -#endif /* HAVE_ECC */ + XMEMSET(&crypto_policy, 0, sizeof(crypto_policy)); + file = XFOPEN(policy_file, "rb"); -typedef struct { - byte verifyPeer:1; - byte verifyNone:1; - byte failNoCert:1; - byte failNoCertxPSK:1; - byte verifyPostHandshake:1; -} SetVerifyOptions; - -static SetVerifyOptions ModeToVerifyOptions(int mode) -{ - SetVerifyOptions opts; - XMEMSET(&opts, 0, sizeof(SetVerifyOptions)); - - if (mode != WOLFSSL_VERIFY_DEFAULT) { - opts.verifyNone = (mode == WOLFSSL_VERIFY_NONE); - if (!opts.verifyNone) { - opts.verifyPeer = - (mode & WOLFSSL_VERIFY_PEER) != 0; - opts.failNoCertxPSK = - (mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK) != 0; - opts.failNoCert = - (mode & WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT) != 0; -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) - opts.verifyPostHandshake = - (mode & WOLFSSL_VERIFY_POST_HANDSHAKE) != 0; -#endif - } + if (file == XBADFILE) { + WOLFSSL_MSG_EX("error: crypto policy file open failed: %s", + policy_file); + return WOLFSSL_BAD_FILE; } - return opts; -} + if (XFSEEK(file, 0, XSEEK_END) != 0) { + WOLFSSL_MSG_EX("error: crypto policy file seek end failed: %s", + policy_file); + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } -WOLFSSL_ABI -void wolfSSL_CTX_set_verify(WOLFSSL_CTX* ctx, int mode, VerifyCallback verify_callback) -{ - SetVerifyOptions opts; + sz = XFTELL(file); - WOLFSSL_ENTER("wolfSSL_CTX_set_verify"); - if (ctx == NULL) - return; + if (XFSEEK(file, 0, XSEEK_SET) != 0) { + WOLFSSL_MSG_EX("error: crypto policy file seek failed: %s", + policy_file); + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } - opts = ModeToVerifyOptions(mode); + if (sz <= 0 || sz > MAX_WOLFSSL_CRYPTO_POLICY_SIZE) { + WOLFSSL_MSG_EX("error: crypto policy file %s, invalid size: %ld", + policy_file, sz); + XFCLOSE(file); + return WOLFSSL_BAD_FILE; + } - ctx->verifyNone = opts.verifyNone; - ctx->verifyPeer = opts.verifyPeer; - ctx->failNoCert = opts.failNoCert; - ctx->failNoCertxPSK = opts.failNoCertxPSK; -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) - ctx->verifyPostHandshake = opts.verifyPostHandshake; -#endif + n_read = XFREAD(crypto_policy.str, 1, sz, file); + XFCLOSE(file); - ctx->verifyCallback = verify_callback; -} + if (n_read != (size_t) sz) { + WOLFSSL_MSG_EX("error: crypto policy file %s: read %zu, " + "expected %ld", policy_file, n_read, sz); + return WOLFSSL_BAD_FILE; + } -#ifdef OPENSSL_ALL -void wolfSSL_CTX_set_cert_verify_callback(WOLFSSL_CTX* ctx, - CertVerifyCallback cb, void* arg) -{ - WOLFSSL_ENTER("wolfSSL_CTX_set_cert_verify_callback"); - if (ctx == NULL) - return; + crypto_policy.str[n_read] = '\0'; - ctx->verifyCertCb = cb; - ctx->verifyCertCbArg = arg; + return crypto_policy_parse(); } -#endif - +#endif /* ! NO_FILESYSTEM */ -void wolfSSL_set_verify(WOLFSSL* ssl, int mode, VerifyCallback verify_callback) +/* Same behavior as wolfSSL_crypto_policy_enable, but loads + * via memory buf instead of file. + * + * Returns WOLFSSL_SUCCESS on success. + * Returns CRYPTO_POLICY_FORBIDDEN if already enabled. + * Returns < 0 on misc error. + * */ +int wolfSSL_crypto_policy_enable_buffer(const char * buf) { - SetVerifyOptions opts; - - WOLFSSL_ENTER("wolfSSL_set_verify"); - if (ssl == NULL) - return; - - opts = ModeToVerifyOptions(mode); - - ssl->options.verifyNone = opts.verifyNone; - ssl->options.verifyPeer = opts.verifyPeer; - ssl->options.failNoCert = opts.failNoCert; - ssl->options.failNoCertxPSK = opts.failNoCertxPSK; -#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) - ssl->options.verifyPostHandshake = opts.verifyPostHandshake; -#endif - - ssl->verifyCallback = verify_callback; -} + size_t sz = 0; -void wolfSSL_set_verify_result(WOLFSSL *ssl, long v) -{ - WOLFSSL_ENTER("wolfSSL_set_verify_result"); + WOLFSSL_ENTER("wolfSSL_crypto_policy_enable_buffer"); - if (ssl == NULL) - return; + if (wolfSSL_crypto_policy_is_enabled()) { + WOLFSSL_MSG_EX("error: crypto policy already enabled"); + return CRYPTO_POLICY_FORBIDDEN; + } -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) || \ - defined(OPENSSL_ALL) - ssl->peerVerifyRet = (unsigned long)v; -#else - (void)v; - WOLFSSL_STUB("wolfSSL_set_verify_result"); -#endif -} + if (buf == NULL || *buf == '\0') { + return BAD_FUNC_ARG; + } -#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \ - defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) -/* For TLS v1.3 send handshake messages after handshake completes. */ -/* Returns 1=WOLFSSL_SUCCESS or 0=WOLFSSL_FAILURE */ -int wolfSSL_verify_client_post_handshake(WOLFSSL* ssl) -{ - int ret = wolfSSL_request_certificate(ssl); - if (ret != WOLFSSL_SUCCESS) { - if (!IsAtLeastTLSv1_3(ssl->version)) { - /* specific error of wrong version expected */ - WOLFSSL_ERROR(UNSUPPORTED_PROTO_VERSION); + sz = XSTRLEN(buf); - } - else { - WOLFSSL_ERROR(ret); /* log the error in the error queue */ - } + if (sz == 0 || sz > MAX_WOLFSSL_CRYPTO_POLICY_SIZE) { + return BAD_FUNC_ARG; } - return (ret == WOLFSSL_SUCCESS) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; -} -int wolfSSL_CTX_set_post_handshake_auth(WOLFSSL_CTX* ctx, int val) -{ - int ret = wolfSSL_CTX_allow_post_handshake_auth(ctx); - if (ret == 0) { - ctx->postHandshakeAuth = (val != 0); - } - return (ret == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; -} -int wolfSSL_set_post_handshake_auth(WOLFSSL* ssl, int val) -{ - int ret = wolfSSL_allow_post_handshake_auth(ssl); - if (ret == 0) { - ssl->options.postHandshakeAuth = (val != 0); - } - return (ret == 0) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; -} -#endif /* OPENSSL_EXTRA && !NO_CERTS && WOLFSSL_TLS13 && - * WOLFSSL_POST_HANDSHAKE_AUTH */ + XMEMSET(&crypto_policy, 0, sizeof(crypto_policy)); + XMEMCPY(crypto_policy.str, buf, sz); -/* store user ctx for verify callback */ -void wolfSSL_SetCertCbCtx(WOLFSSL* ssl, void* ctx) -{ - WOLFSSL_ENTER("wolfSSL_SetCertCbCtx"); - if (ssl) - ssl->verifyCbCtx = ctx; + return crypto_policy_parse(); } - -/* store user ctx for verify callback */ -void wolfSSL_CTX_SetCertCbCtx(WOLFSSL_CTX* ctx, void* userCtx) +/* Returns whether the system wide crypto-policy is enabled. + * + * Returns 1 if enabled. + * 0 if disabled. + * */ +int wolfSSL_crypto_policy_is_enabled(void) { - WOLFSSL_ENTER("wolfSSL_CTX_SetCertCbCtx"); - if (ctx) - ctx->verifyCbCtx = userCtx; -} + WOLFSSL_ENTER("wolfSSL_crypto_policy_is_enabled"); + return crypto_policy.enabled == 1; +} -/* store context CA Cache addition callback */ -void wolfSSL_CTX_SetCACb(WOLFSSL_CTX* ctx, CallbackCACache cb) +/* Disables the system wide crypto-policy. + * note: SSL and CTX structures already instantiated will + * keep their security policy parameters. This will only + * affect new instantiations. + * */ +void wolfSSL_crypto_policy_disable(void) { - if (ctx && ctx->cm) - ctx->cm->caCacheCallback = cb; + WOLFSSL_ENTER("wolfSSL_crypto_policy_disable"); + crypto_policy.enabled = 0; + XMEMSET(&crypto_policy, 0, sizeof(crypto_policy)); + return; } - -#if defined(PERSIST_CERT_CACHE) - -#if !defined(NO_FILESYSTEM) - -/* Persist cert cache to file */ -int wolfSSL_CTX_save_cert_cache(WOLFSSL_CTX* ctx, const char* fname) +/* Get the crypto-policy bulk cipher list string. + * String is not owned by caller, should not be freed. + * + * Returns pointer to bulk cipher list string. + * Returns NULL if NOT enabled, or on error. + * */ +const char * wolfSSL_crypto_policy_get_ciphers(void) { - WOLFSSL_ENTER("wolfSSL_CTX_save_cert_cache"); + WOLFSSL_ENTER("wolfSSL_crypto_policy_get_ciphers"); - if (ctx == NULL || fname == NULL) - return BAD_FUNC_ARG; + if (crypto_policy.enabled == 1) { + /* The crypto policy config will have + * this form: + * "@SECLEVEL=2:kEECDH:kRSA..." */ + return crypto_policy.str; + } - return CM_SaveCertCache(ctx->cm, fname); + return NULL; } - -/* Persist cert cache from file */ -int wolfSSL_CTX_restore_cert_cache(WOLFSSL_CTX* ctx, const char* fname) +/* Get the configured crypto-policy security level. + * A security level of 0 does not impose any additional + * restrictions. + * + * Returns 1 - 5 if enabled. + * Returns 0 if NOT enabled. + * */ +int wolfSSL_crypto_policy_get_level(void) { - WOLFSSL_ENTER("wolfSSL_CTX_restore_cert_cache"); - - if (ctx == NULL || fname == NULL) - return BAD_FUNC_ARG; + if (crypto_policy.enabled == 1) { + return crypto_policy.secLevel; + } - return CM_RestoreCertCache(ctx->cm, fname); + return 0; } -#endif /* NO_FILESYSTEM */ - -/* Persist cert cache to memory */ -int wolfSSL_CTX_memsave_cert_cache(WOLFSSL_CTX* ctx, void* mem, - int sz, int* used) +/* Get security level from ssl structure. + * @param ssl a pointer to WOLFSSL structure + */ +int wolfSSL_get_security_level(const WOLFSSL * ssl) { - WOLFSSL_ENTER("wolfSSL_CTX_memsave_cert_cache"); - - if (ctx == NULL || mem == NULL || used == NULL || sz <= 0) + if (ssl == NULL) { return BAD_FUNC_ARG; + } - return CM_MemSaveCertCache(ctx->cm, mem, sz, used); + return ssl->secLevel; } - -/* Restore cert cache from memory */ -int wolfSSL_CTX_memrestore_cert_cache(WOLFSSL_CTX* ctx, const void* mem, int sz) +#ifndef NO_WOLFSSL_STUB +/* + * Set security level (wolfSSL doesn't support setting the security level). + * + * The security level can only be set through a system wide crypto-policy + * with wolfSSL_crypto_policy_enable(). + * + * @param ssl a pointer to WOLFSSL structure + * @param level security level + */ +void wolfSSL_set_security_level(WOLFSSL * ssl, int level) { - WOLFSSL_ENTER("wolfSSL_CTX_memrestore_cert_cache"); - - if (ctx == NULL || mem == NULL || sz <= 0) - return BAD_FUNC_ARG; - - return CM_MemRestoreCertCache(ctx->cm, mem, sz); + WOLFSSL_ENTER("wolfSSL_set_security_level"); + (void)ssl; + (void)level; } +#endif /* !NO_WOLFSSL_STUB */ +#endif /* WOLFSSL_SYS_CRYPTO_POLICY */ -/* get how big the the cert cache save buffer needs to be */ -int wolfSSL_CTX_get_cert_cache_memsize(WOLFSSL_CTX* ctx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_get_cert_cache_memsize"); - - if (ctx == NULL) - return BAD_FUNC_ARG; - return CM_GetCertCacheMemSize(ctx->cm); -} +#define WOLFSSL_SSL_LOAD_INCLUDED +#include -#endif /* PERSIST_CERT_CACHE */ -#endif /* !NO_CERTS */ +#define WOLFSSL_SSL_API_CRL_OCSP_INCLUDED +#include "src/ssl_api_crl_ocsp.c" void wolfSSL_load_error_strings(void) @@ -12098,126 +7907,6 @@ int wolfSSL_set_compression(WOLFSSL* ssl) #endif /* HAVE_ANON */ -#ifndef NO_CERTS - - /* unload any certs or keys that SSL owns, leave CTX as is - WOLFSSL_SUCCESS on ok */ - int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl) - { - if (ssl == NULL) { - WOLFSSL_MSG("Null function arg"); - return BAD_FUNC_ARG; - } - - if (ssl->buffers.weOwnCert && !ssl->keepCert) { - WOLFSSL_MSG("Unloading cert"); - FreeDer(&ssl->buffers.certificate); - #ifdef KEEP_OUR_CERT - wolfSSL_X509_free(ssl->ourCert); - ssl->ourCert = NULL; - #endif - ssl->buffers.weOwnCert = 0; - } - - if (ssl->buffers.weOwnCertChain) { - WOLFSSL_MSG("Unloading cert chain"); - FreeDer(&ssl->buffers.certChain); - ssl->buffers.weOwnCertChain = 0; - } - - if (ssl->buffers.weOwnKey) { - WOLFSSL_MSG("Unloading key"); - ForceZero(ssl->buffers.key->buffer, ssl->buffers.key->length); - FreeDer(&ssl->buffers.key); - #ifdef WOLFSSL_BLIND_PRIVATE_KEY - FreeDer(&ssl->buffers.keyMask); - #endif - ssl->buffers.weOwnKey = 0; - } - -#ifdef WOLFSSL_DUAL_ALG_CERTS - if (ssl->buffers.weOwnAltKey) { - WOLFSSL_MSG("Unloading alt key"); - ForceZero(ssl->buffers.altKey->buffer, ssl->buffers.altKey->length); - FreeDer(&ssl->buffers.altKey); - #ifdef WOLFSSL_BLIND_PRIVATE_KEY - FreeDer(&ssl->buffers.altKeyMask); - #endif - ssl->buffers.weOwnAltKey = 0; - } -#endif /* WOLFSSL_DUAL_ALG_CERTS */ - - return WOLFSSL_SUCCESS; - } - - - int wolfSSL_CTX_UnloadCAs(WOLFSSL_CTX* ctx) - { - WOLFSSL_ENTER("wolfSSL_CTX_UnloadCAs"); - - if (ctx == NULL) - return BAD_FUNC_ARG; - - return wolfSSL_CertManagerUnloadCAs(ctx->cm); - } - - int wolfSSL_CTX_UnloadIntermediateCerts(WOLFSSL_CTX* ctx) - { - int ret; - - WOLFSSL_ENTER("wolfSSL_CTX_UnloadIntermediateCerts"); - - if (ctx == NULL) - return BAD_FUNC_ARG; - - ret = wolfSSL_RefWithMutexLock(&ctx->ref); - if (ret < 0) - return ret; - - if (ctx->ref.count > 1) { - WOLFSSL_MSG("ctx object must have a ref count of 1 before " - "unloading intermediate certs"); - ret = BAD_STATE_E; - } - else { - ret = wolfSSL_CertManagerUnloadIntermediateCerts(ctx->cm); - } - - if (wolfSSL_RefWithMutexUnlock(&ctx->ref) != 0) - WOLFSSL_MSG("Failed to unlock mutex!"); - - return ret; - } - - -#ifdef WOLFSSL_TRUST_PEER_CERT - int wolfSSL_CTX_Unload_trust_peers(WOLFSSL_CTX* ctx) - { - WOLFSSL_ENTER("wolfSSL_CTX_Unload_trust_peers"); - - if (ctx == NULL) - return BAD_FUNC_ARG; - - return wolfSSL_CertManagerUnload_trust_peers(ctx->cm); - } - -#ifdef WOLFSSL_LOCAL_X509_STORE - int wolfSSL_Unload_trust_peers(WOLFSSL* ssl) - { - WOLFSSL_ENTER("wolfSSL_CTX_Unload_trust_peers"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - SSL_CM_WARNING(ssl); - return wolfSSL_CertManagerUnload_trust_peers(SSL_CM(ssl)); - } -#endif /* WOLFSSL_LOCAL_X509_STORE */ -#endif /* WOLFSSL_TRUST_PEER_CERT */ -/* old NO_FILESYSTEM end */ -#endif /* !NO_CERTS */ - - #ifdef OPENSSL_EXTRA int wolfSSL_add_all_algorithms(void) @@ -12360,50 +8049,6 @@ int wolfSSL_set_compression(WOLFSSL* ssl) #endif /* !NO_BIO */ #endif /* OPENSSL_EXTRA */ -#ifndef WOLFSSL_NO_CA_NAMES - void wolfSSL_CTX_set_client_CA_list(WOLFSSL_CTX* ctx, - WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) - { - WOLFSSL_ENTER("wolfSSL_CTX_set_client_CA_list"); - if (ctx != NULL) { - wolfSSL_sk_X509_NAME_pop_free(ctx->client_ca_names, NULL); - ctx->client_ca_names = names; - } - } - - void wolfSSL_set_client_CA_list(WOLFSSL* ssl, - WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) - { - WOLFSSL_ENTER("wolfSSL_set_client_CA_list"); - if (ssl != NULL) { - if (ssl->client_ca_names != ssl->ctx->client_ca_names) - wolfSSL_sk_X509_NAME_pop_free(ssl->client_ca_names, NULL); - ssl->client_ca_names = names; - } - } - - void wolfSSL_CTX_set0_CA_list(WOLFSSL_CTX* ctx, - WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) - { - WOLFSSL_ENTER("wolfSSL_CTX_set0_CA_list"); - if (ctx != NULL) { - wolfSSL_sk_X509_NAME_pop_free(ctx->ca_names, NULL); - ctx->ca_names = names; - } - } - - void wolfSSL_set0_CA_list(WOLFSSL* ssl, - WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) - { - WOLFSSL_ENTER("wolfSSL_set0_CA_list"); - if (ssl != NULL) { - if (ssl->ca_names != ssl->ctx->ca_names) - wolfSSL_sk_X509_NAME_pop_free(ssl->ca_names, NULL); - ssl->ca_names = names; - } - } -#endif /* WOLFSSL_NO_CA_NAMES */ - #ifdef WOLFSSL_CERT_SETUP_CB #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) /* registers client cert callback, called during handshake if server @@ -12599,271 +8244,28 @@ int wolfSSL_set_compression(WOLFSSL* ssl) int CertSetupCbWrapper(WOLFSSL* ssl) { int ret = 0; - if (ssl->ctx->certSetupCb != NULL) { - WOLFSSL_MSG("Calling user cert setup callback"); - ret = ssl->ctx->certSetupCb(ssl, ssl->ctx->certSetupCbArg); - if (ret == 1) { - WOLFSSL_MSG("User cert callback returned success"); - ret = 0; - } - else if (ret == 0) { - SendAlert(ssl, alert_fatal, internal_error); - ret = CLIENT_CERT_CB_ERROR; - } - else if (ret < 0) { - ret = WOLFSSL_ERROR_WANT_X509_LOOKUP; - } - else { - WOLFSSL_MSG("Unexpected user callback return"); - ret = CLIENT_CERT_CB_ERROR; - } - } - return ret; - } -#endif /* WOLFSSL_CERT_SETUP_CB */ - -#ifndef WOLFSSL_NO_CA_NAMES - WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_CTX_get_client_CA_list( - const WOLFSSL_CTX *ctx) - { - WOLFSSL_ENTER("wolfSSL_CTX_get_client_CA_list"); - - if (ctx == NULL) { - WOLFSSL_MSG("Bad argument passed to " - "wolfSSL_CTX_get_client_CA_list"); - return NULL; - } - - return ctx->client_ca_names; - } - - /* On server side: returns the CAs set via *_set_client_CA_list(); - * On client side: returns the CAs received from server -- same as - * wolfSSL_get0_peer_CA_list() */ - WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_get_client_CA_list( - const WOLFSSL* ssl) - { - WOLFSSL_ENTER("wolfSSL_get_client_CA_list"); - - if (ssl == NULL) { - WOLFSSL_MSG("Bad argument passed to wolfSSL_get_client_CA_list"); - return NULL; - } - - if (ssl->options.side == WOLFSSL_CLIENT_END) - return ssl->peer_ca_names; - else - return SSL_CLIENT_CA_NAMES(ssl); - } - - WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_CTX_get0_CA_list( - const WOLFSSL_CTX *ctx) - { - WOLFSSL_ENTER("wolfSSL_CTX_get0_CA_list"); - - if (ctx == NULL) { - WOLFSSL_MSG("Bad argument passed to wolfSSL_CTX_get0_CA_list"); - return NULL; - } - - return ctx->ca_names; - } - - /* Always returns the CA's set via *_set0_CA_list */ - WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_get0_CA_list(const WOLFSSL *ssl) - { - WOLFSSL_ENTER("wolfSSL_get0_CA_list"); - - if (ssl == NULL) { - WOLFSSL_MSG("Bad argument passed to wolfSSL_get0_CA_list"); - return NULL; - } - - return SSL_CA_NAMES(ssl); - } - - /* Always returns the CA's received from the peer */ - WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_get0_peer_CA_list( - const WOLFSSL* ssl) - { - WOLFSSL_ENTER("wolfSSL_get0_peer_CA_list"); - - if (ssl == NULL) { - WOLFSSL_MSG("Bad argument passed to wolfSSL_get0_peer_CA_list"); - return NULL; - } - - return ssl->peer_ca_names; - } - - #if !defined(NO_CERTS) - static int add_to_CA_list(WOLFSSL_STACK* ca_names, WOLFSSL_X509* x509) - { - WOLFSSL_X509_NAME *nameCopy = NULL; - - nameCopy = wolfSSL_X509_NAME_dup(wolfSSL_X509_get_subject_name(x509)); - if (nameCopy == NULL) { - WOLFSSL_MSG("wolfSSL_X509_NAME_dup error"); - return WOLFSSL_FAILURE; - } - - if (wolfSSL_sk_X509_NAME_push(ca_names, nameCopy) <= 0) { - WOLFSSL_MSG("wolfSSL_sk_X509_NAME_push error"); - wolfSSL_X509_NAME_free(nameCopy); - return WOLFSSL_FAILURE; - } - - return WOLFSSL_SUCCESS; - } - - int wolfSSL_CTX_add_client_CA(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) - { - WOLFSSL_ENTER("wolfSSL_CTX_add_client_CA"); - if (ctx == NULL || x509 == NULL) { - WOLFSSL_MSG("Bad argument"); - return WOLFSSL_FAILURE; - } - if (ctx->client_ca_names == NULL) { - ctx->client_ca_names = wolfSSL_sk_X509_NAME_new(NULL); - if (ctx->client_ca_names == NULL) { - WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); - return WOLFSSL_FAILURE; - } - } - return add_to_CA_list(ctx->client_ca_names, x509); - } - - int wolfSSL_add_client_CA(WOLFSSL* ssl, WOLFSSL_X509* x509) - { - WOLFSSL_ENTER("wolfSSL_add_client_CA"); - if (ssl == NULL || x509 == NULL) { - WOLFSSL_MSG("Bad argument"); - return WOLFSSL_FAILURE; - } - if (ssl->client_ca_names == NULL) { - ssl->client_ca_names = wolfSSL_sk_X509_NAME_new(NULL); - if (ssl->client_ca_names == NULL) { - WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); - return WOLFSSL_FAILURE; - } - } - return add_to_CA_list(ssl->client_ca_names, x509); - } - - int wolfSSL_CTX_add1_to_CA_list(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) - { - WOLFSSL_ENTER("wolfSSL_CTX_add1_to_CA_list"); - if (ctx == NULL || x509 == NULL) { - WOLFSSL_MSG("Bad argument"); - return WOLFSSL_FAILURE; - } - if (ctx->ca_names == NULL) { - ctx->ca_names = wolfSSL_sk_X509_NAME_new(NULL); - if (ctx->ca_names == NULL) { - WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); - return WOLFSSL_FAILURE; - } - } - return add_to_CA_list(ctx->ca_names, x509); - } - - int wolfSSL_add1_to_CA_list(WOLFSSL* ssl, WOLFSSL_X509* x509) - { - WOLFSSL_ENTER("wolfSSL_add1_to_CA_list"); - if (ssl == NULL || x509 == NULL) { - WOLFSSL_MSG("Bad argument"); - return WOLFSSL_FAILURE; - } - if (ssl->ca_names == NULL) { - ssl->ca_names = wolfSSL_sk_X509_NAME_new(NULL); - if (ssl->ca_names == NULL) { - WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); - return WOLFSSL_FAILURE; - } - } - return add_to_CA_list(ssl->ca_names, x509); - } - #endif /* !NO_CERTS */ - - #ifndef NO_BIO - #if !defined(NO_RSA) && !defined(NO_CERTS) - WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_load_client_CA_file( - const char* fname) - { - /* The webserver build is using this to load a CA into the server - * for client authentication as an option. Have this return NULL in - * that case. If OPENSSL_EXTRA is enabled, go ahead and include - * the function. */ - #ifdef OPENSSL_EXTRA - WOLFSSL_STACK *list = NULL; - WOLFSSL_BIO* bio = NULL; - WOLFSSL_X509 *cert = NULL; - WOLFSSL_X509_NAME *nameCopy = NULL; - unsigned long err = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - - WOLFSSL_ENTER("wolfSSL_load_client_CA_file"); - - bio = wolfSSL_BIO_new_file(fname, "rb"); - if (bio == NULL) { - WOLFSSL_MSG("wolfSSL_BIO_new_file error"); - goto cleanup; + if (ssl->ctx->certSetupCb != NULL) { + WOLFSSL_MSG("Calling user cert setup callback"); + ret = ssl->ctx->certSetupCb(ssl, ssl->ctx->certSetupCbArg); + if (ret == 1) { + WOLFSSL_MSG("User cert callback returned success"); + ret = 0; } - - list = wolfSSL_sk_X509_NAME_new(NULL); - if (list == NULL) { - WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); - goto cleanup; + else if (ret == 0) { + SendAlert(ssl, alert_fatal, internal_error); + ret = CLIENT_CERT_CB_ERROR; } - - /* Read each certificate in the chain out of the file. */ - while (wolfSSL_PEM_read_bio_X509(bio, &cert, NULL, NULL) != NULL) { - /* Need a persistent copy of the subject name. */ - nameCopy = wolfSSL_X509_NAME_dup( - wolfSSL_X509_get_subject_name(cert)); - if (nameCopy == NULL) { - WOLFSSL_MSG("wolfSSL_X509_NAME_dup error"); - goto cleanup; - } - /* - * Original cert will be freed so make sure not to try to access - * it in the future. - */ - nameCopy->x509 = NULL; - - if (wolfSSL_sk_X509_NAME_push(list, nameCopy) <= 0) { - WOLFSSL_MSG("wolfSSL_sk_X509_NAME_push error"); - /* Do free in loop because nameCopy is now responsibility - * of list to free and adding jumps to cleanup after this - * might result in a double free. */ - wolfSSL_X509_NAME_free(nameCopy); - goto cleanup; - } - - wolfSSL_X509_free(cert); - cert = NULL; + else if (ret < 0) { + ret = WOLFSSL_ERROR_WANT_X509_LOOKUP; } - - CLEAR_ASN_NO_PEM_HEADER_ERROR(err); - - err = WOLFSSL_SUCCESS; -cleanup: - wolfSSL_X509_free(cert); - cert = NULL; - wolfSSL_BIO_free(bio); - if (err != WOLFSSL_SUCCESS) { - /* We failed so return NULL */ - wolfSSL_sk_X509_NAME_pop_free(list, NULL); - list = NULL; + else { + WOLFSSL_MSG("Unexpected user callback return"); + ret = CLIENT_CERT_CB_ERROR; } - return list; - #else - (void)fname; - return NULL; - #endif } - #endif - #endif /* !NO_BIO */ -#endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA */ + return ret; + } +#endif /* WOLFSSL_CERT_SETUP_CB */ #ifdef OPENSSL_EXTRA @@ -13215,130 +8617,6 @@ int wolfSSL_set_compression(WOLFSSL* ssl) } #endif /* OPENSSL_EXTRA */ -#if !defined(NO_CERTS) && (defined(OPENSSL_EXTRA) || \ - defined(WOLFSSL_WPAS_SMALL)) - - WOLFSSL_X509_STORE* wolfSSL_CTX_get_cert_store(const WOLFSSL_CTX* ctx) - { - if (ctx == NULL) { - return NULL; - } - - if (ctx->x509_store_pt != NULL) - return ctx->x509_store_pt; - return &((WOLFSSL_CTX*)ctx)->x509_store; - } - - void wolfSSL_CTX_set_cert_store(WOLFSSL_CTX* ctx, WOLFSSL_X509_STORE* str) - { - WOLFSSL_ENTER("wolfSSL_CTX_set_cert_store"); - if (ctx == NULL || str == NULL || ctx->cm == str->cm) { - return; - } - - if (wolfSSL_CertManager_up_ref(str->cm) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_CertManager_up_ref error"); - return; - } - /* free cert manager if have one */ - if (ctx->cm != NULL) { - wolfSSL_CertManagerFree(ctx->cm); - } - ctx->cm = str->cm; - ctx->x509_store.cm = str->cm; - - /* free existing store if it exists */ - wolfSSL_X509_STORE_free(ctx->x509_store_pt); - ctx->x509_store.cache = str->cache; - ctx->x509_store_pt = str; /* take ownership of store and free it - with CTX free */ - ctx->cm->x509_store_p = ctx->x509_store_pt;/* CTX has ownership - and free it with CTX free*/ - } - -#ifdef OPENSSL_ALL - int wolfSSL_CTX_set1_verify_cert_store(WOLFSSL_CTX* ctx, - WOLFSSL_X509_STORE* str) - { - WOLFSSL_ENTER("wolfSSL_CTX_set1_verify_cert_store"); - - if (ctx == NULL || str == NULL) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } - - /* NO-OP when setting existing store */ - if (str == CTX_STORE(ctx)) - return WOLFSSL_SUCCESS; - - if (wolfSSL_X509_STORE_up_ref(str) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_X509_STORE_up_ref error"); - return WOLFSSL_FAILURE; - } - - /* free existing store if it exists */ - wolfSSL_X509_STORE_free(ctx->x509_store_pt); - ctx->x509_store_pt = str; /* take ownership of store and free it - with CTX free */ - return WOLFSSL_SUCCESS; - } -#endif - - int wolfSSL_set0_verify_cert_store(WOLFSSL *ssl, WOLFSSL_X509_STORE* str) - { - WOLFSSL_ENTER("wolfSSL_set0_verify_cert_store"); - - if (ssl == NULL || str == NULL) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } - - /* NO-OP when setting existing store */ - if (str == SSL_STORE(ssl)) - return WOLFSSL_SUCCESS; - - /* free existing store if it exists */ - wolfSSL_X509_STORE_free(ssl->x509_store_pt); - if (str == ssl->ctx->x509_store_pt) - ssl->x509_store_pt = NULL; /* if setting ctx store then just revert - to using that instead */ - else - ssl->x509_store_pt = str; /* take ownership of store and free it - with SSL free */ - return WOLFSSL_SUCCESS; - } - - - int wolfSSL_set1_verify_cert_store(WOLFSSL *ssl, WOLFSSL_X509_STORE* str) - { - WOLFSSL_ENTER("wolfSSL_set1_verify_cert_store"); - - if (ssl == NULL || str == NULL) { - WOLFSSL_MSG("Bad parameter"); - return WOLFSSL_FAILURE; - } - - /* NO-OP when setting existing store */ - if (str == SSL_STORE(ssl)) - return WOLFSSL_SUCCESS; - - if (wolfSSL_X509_STORE_up_ref(str) != WOLFSSL_SUCCESS) { - WOLFSSL_MSG("wolfSSL_X509_STORE_up_ref error"); - return WOLFSSL_FAILURE; - } - - /* free existing store if it exists */ - wolfSSL_X509_STORE_free(ssl->x509_store_pt); - if (str == ssl->ctx->x509_store_pt) - ssl->x509_store_pt = NULL; /* if setting ctx store then just revert - to using that instead */ - else - ssl->x509_store_pt = str; /* take ownership of store and free it - with SSL free */ - return WOLFSSL_SUCCESS; - } -#endif /* !NO_CERTS && (OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL) */ - #ifdef WOLFSSL_ENCRYPTED_KEYS void wolfSSL_CTX_set_default_passwd_cb_userdata(WOLFSSL_CTX* ctx, @@ -14975,78 +10253,6 @@ WOLF_STACK_OF(WOLFSSL_X509) *wolfSSL_get0_verified_chain(const WOLFSSL *ssl) #endif /* KEEP_PEER_CERT */ #endif /* SESSION_CERTS && OPENSSL_EXTRA */ -#ifndef NO_CERTS - -/* OPENSSL_EXTRA is needed for wolfSSL_X509_d21 function - KEEP_OUR_CERT is to insure ability for returning ssl certificate */ -#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ - defined(KEEP_OUR_CERT) -WOLFSSL_X509* wolfSSL_get_certificate(WOLFSSL* ssl) -{ - if (ssl == NULL) { - return NULL; - } - - if (ssl->buffers.weOwnCert) { - if (ssl->ourCert == NULL) { - if (ssl->buffers.certificate == NULL) { - WOLFSSL_MSG("Certificate buffer not set!"); - return NULL; - } - #ifndef WOLFSSL_X509_STORE_CERTS - ssl->ourCert = wolfSSL_X509_d2i_ex(NULL, - ssl->buffers.certificate->buffer, - (int)ssl->buffers.certificate->length, - ssl->heap); - #endif - } - return ssl->ourCert; - } - else { /* if cert not owned get parent ctx cert or return null */ - if (ssl->ctx) { - if (ssl->ctx->ourCert == NULL) { - if (ssl->ctx->certificate == NULL) { - WOLFSSL_MSG("Ctx Certificate buffer not set!"); - return NULL; - } - #ifndef WOLFSSL_X509_STORE_CERTS - ssl->ctx->ourCert = wolfSSL_X509_d2i_ex(NULL, - ssl->ctx->certificate->buffer, - (int)ssl->ctx->certificate->length, - ssl->heap); - #endif - ssl->ctx->ownOurCert = 1; - } - return ssl->ctx->ourCert; - } - } - - return NULL; -} - -WOLFSSL_X509* wolfSSL_CTX_get0_certificate(WOLFSSL_CTX* ctx) -{ - if (ctx) { - if (ctx->ourCert == NULL) { - if (ctx->certificate == NULL) { - WOLFSSL_MSG("Ctx Certificate buffer not set!"); - return NULL; - } - #ifndef WOLFSSL_X509_STORE_CERTS - ctx->ourCert = wolfSSL_X509_d2i_ex(NULL, - ctx->certificate->buffer, - (int)ctx->certificate->length, - ctx->heap); - #endif - ctx->ownOurCert = 1; - } - return ctx->ourCert; - } - return NULL; -} -#endif /* OPENSSL_EXTRA && KEEP_OUR_CERT */ -#endif /* NO_CERTS */ - #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) void wolfSSL_set_connect_state(WOLFSSL* ssl) { @@ -16299,201 +11505,6 @@ void wolfSSL_set_dynlock_destroy_callback( } -#endif /* OPENSSL_EXTRA */ - -#ifdef OPENSSL_EXTRA -#ifndef NO_CERTS - -#if !defined(NO_ASN) && !defined(NO_PWDBASED) -/* Copies unencrypted DER key buffer into "der". If "der" is null then the size - * of buffer needed is returned. If *der == NULL then it allocates a buffer. - * NOTE: This also advances the "der" pointer to be at the end of buffer. - * - * Returns size of key buffer on success - */ -int wolfSSL_i2d_PrivateKey(const WOLFSSL_EVP_PKEY* key, unsigned char** der) -{ - return wolfSSL_EVP_PKEY_get_der(key, der); -} - -int wolfSSL_i2d_PrivateKey_bio(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key) -{ - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - int derSz = 0; - byte* der = NULL; - - if (bio == NULL || key == NULL) { - return WOLFSSL_FAILURE; - } - - derSz = wolfSSL_i2d_PrivateKey(key, NULL); - if (derSz <= 0) { - WOLFSSL_MSG("wolfSSL_i2d_PrivateKey (for getting size) failed"); - return WOLFSSL_FAILURE; - } - - der = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (!der) { - WOLFSSL_MSG("malloc failed"); - return WOLFSSL_FAILURE; - } - - derSz = wolfSSL_i2d_PrivateKey(key, &der); - if (derSz <= 0) { - WOLFSSL_MSG("wolfSSL_i2d_PrivateKey failed"); - goto cleanup; - } - - if (wolfSSL_BIO_write(bio, der, derSz) != derSz) { - goto cleanup; - } - - ret = WOLFSSL_SUCCESS; - -cleanup: - XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); - return ret; -} - -int wolfSSL_i2d_PublicKey(const WOLFSSL_EVP_PKEY *key, unsigned char **der) -{ -#if !defined(NO_RSA) || defined(HAVE_ECC) -#ifdef HAVE_ECC - unsigned char *local_der = NULL; - word32 local_derSz = 0; - unsigned char *pub_der = NULL; - ecc_key *eccKey = NULL; - word32 inOutIdx = 0; -#endif - word32 pub_derSz = 0; - int ret; - int key_type = 0; - - if (key == NULL) { - return WOLFSSL_FATAL_ERROR; - } - - key_type = key->type; - if ((key_type != WC_EVP_PKEY_EC) && (key_type != WC_EVP_PKEY_RSA)) { - return WOLFSSL_FATAL_ERROR; - } - -#ifndef NO_RSA - if (key_type == WC_EVP_PKEY_RSA) { - return wolfSSL_i2d_RSAPublicKey(key->rsa, der); - } -#endif - - /* Now that RSA is taken care of, we only need to consider the ECC case. */ - -#ifdef HAVE_ECC - - /* We need to get the DER, then convert it to a public key. But what we get - * might be a buffered private key so we need to decode it and then encode - * the public part. */ - ret = wolfSSL_EVP_PKEY_get_der(key, &local_der); - if (ret <= 0) { - /* In this case, there was no buffered DER at all. This could be the - * case where the key that was passed in was generated. So now we - * have to create the local DER. */ - local_derSz = (word32)wolfSSL_i2d_ECPrivateKey(key->ecc, &local_der); - if (local_derSz == 0) { - ret = WOLFSSL_FATAL_ERROR; - } - } else { - local_derSz = (word32)ret; - ret = 0; - } - - if (ret == 0) { - eccKey = (ecc_key *)XMALLOC(sizeof(*eccKey), NULL, DYNAMIC_TYPE_ECC); - if (eccKey == NULL) { - WOLFSSL_MSG("Failed to allocate key buffer."); - ret = WOLFSSL_FATAL_ERROR; - } - } - - if (ret == 0) { - ret = wc_ecc_init(eccKey); - } - - if (ret == 0) { - ret = wc_EccPublicKeyDecode(local_der, &inOutIdx, eccKey, local_derSz); - if (ret < 0) { - /* We now try again as x.963 [point type][x][opt y]. */ - ret = wc_ecc_import_x963(local_der, local_derSz, eccKey); - } - } - - if (ret == 0) { - pub_derSz = (word32)wc_EccPublicKeyDerSize(eccKey, 1); - if ((int)pub_derSz <= 0) { - ret = WOLFSSL_FAILURE; - } - } - - if (ret == 0) { - pub_der = (unsigned char*)XMALLOC(pub_derSz, NULL, - DYNAMIC_TYPE_PUBLIC_KEY); - if (pub_der == NULL) { - WOLFSSL_MSG("Failed to allocate output buffer."); - ret = WOLFSSL_FATAL_ERROR; - } - } - - if (ret == 0) { - pub_derSz = (word32)wc_EccPublicKeyToDer(eccKey, pub_der, pub_derSz, 1); - if ((int)pub_derSz <= 0) { - ret = WOLFSSL_FATAL_ERROR; - } - } - - /* This block is for actually returning the DER of the public key */ - if ((ret == 0) && (der != NULL)) { - if (*der == NULL) { - *der = (unsigned char*)XMALLOC(pub_derSz, NULL, - DYNAMIC_TYPE_PUBLIC_KEY); - if (*der == NULL) { - WOLFSSL_MSG("Failed to allocate output buffer."); - ret = WOLFSSL_FATAL_ERROR; - } - - if (ret == 0) { - XMEMCPY(*der, pub_der, pub_derSz); - } - } - else { - XMEMCPY(*der, pub_der, pub_derSz); - *der += pub_derSz; - } - } - - XFREE(pub_der, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - XFREE(local_der, NULL, DYNAMIC_TYPE_PUBLIC_KEY); - - wc_ecc_free(eccKey); - XFREE(eccKey, NULL, DYNAMIC_TYPE_ECC); - -#else - ret = WOLFSSL_FATAL_ERROR; -#endif /* HAVE_ECC */ - - if (ret == 0) { - return (int)pub_derSz; - } - - return ret; -#else - return WOLFSSL_FATAL_ERROR; -#endif /* !NO_RSA || HAVE_ECC */ -} -#endif /* !NO_ASN && !NO_PWDBASED */ - -#endif /* !NO_CERTS */ -#endif /* OPENSSL_EXTRA */ - -#ifdef OPENSSL_EXTRA - /* Sets the DNS hostname to name. * Hostname is cleared if name is NULL or empty. */ int wolfSSL_set1_host(WOLFSSL * ssl, const char* name) @@ -17317,55 +12328,23 @@ int wolfSSL_SSL_renegotiate_pending(WOLFSSL *s) long wolfSSL_clear_options(WOLFSSL* ssl, long opt) { WOLFSSL_ENTER("wolfSSL_clear_options"); - if(ssl == NULL) - return WOLFSSL_FAILURE; - ssl->options.mask &= (unsigned long)~opt; - return (long)ssl->options.mask; -} - -#ifdef HAVE_PK_CALLBACKS -long wolfSSL_set_tlsext_debug_arg(WOLFSSL* ssl, void *arg) -{ - if (ssl == NULL) { - return WOLFSSL_FAILURE; - } - - ssl->loggingCtx = arg; - return WOLFSSL_SUCCESS; -} -#endif /* HAVE_PK_CALLBACKS */ - -#ifdef HAVE_CERTIFICATE_STATUS_REQUEST -long wolfSSL_set_tlsext_status_type(WOLFSSL *s, int type) -{ - WOLFSSL_ENTER("wolfSSL_set_tlsext_status_type"); - - if (s == NULL){ - return BAD_FUNC_ARG; - } - - if (type == WOLFSSL_TLSEXT_STATUSTYPE_ocsp){ - int r = TLSX_UseCertificateStatusRequest(&s->extensions, (byte)type, 0, - s, s->heap, s->devId); - return (long)r; - } else { - WOLFSSL_MSG( - "SSL_set_tlsext_status_type only supports TLSEXT_STATUSTYPE_ocsp type."); + if(ssl == NULL) return WOLFSSL_FAILURE; - } - + ssl->options.mask &= (unsigned long)~opt; + return (long)ssl->options.mask; } -long wolfSSL_get_tlsext_status_type(WOLFSSL *s) +#ifdef HAVE_PK_CALLBACKS +long wolfSSL_set_tlsext_debug_arg(WOLFSSL* ssl, void *arg) { - TLSX* extension; + if (ssl == NULL) { + return WOLFSSL_FAILURE; + } - if (s == NULL) - return WOLFSSL_FATAL_ERROR; - extension = TLSX_Find(s->extensions, TLSX_STATUS_REQUEST); - return extension != NULL ? WOLFSSL_TLSEXT_STATUSTYPE_ocsp : WOLFSSL_FATAL_ERROR; + ssl->loggingCtx = arg; + return WOLFSSL_SUCCESS; } -#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ +#endif /* HAVE_PK_CALLBACKS */ #ifndef NO_WOLFSSL_STUB long wolfSSL_get_tlsext_status_exts(WOLFSSL *s, void *arg) @@ -18747,399 +13726,31 @@ int wolfSSL_get_chain_cert_pem(WOLFSSL_X509_CHAIN* chain, int idx, return WOLFSSL_FATAL_ERROR; *outLen += headerLen + footerLen; - return WOLFSSL_SUCCESS; -#else - (void)chain; - (void)idx; - (void)buf; - (void)inLen; - (void)outLen; - return WOLFSSL_FAILURE; -#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ -} - -#endif /* SESSION_CERTS */ - -#ifdef HAVE_FUZZER -void wolfSSL_SetFuzzerCb(WOLFSSL* ssl, CallbackFuzzer cbf, void* fCtx) -{ - if (ssl) { - ssl->fuzzerCb = cbf; - ssl->fuzzerCtx = fCtx; - } -} -#endif - -#ifndef NO_CERTS -#ifdef HAVE_PK_CALLBACKS - -#ifdef HAVE_ECC -void wolfSSL_CTX_SetEccKeyGenCb(WOLFSSL_CTX* ctx, CallbackEccKeyGen cb) -{ - if (ctx) - ctx->EccKeyGenCb = cb; -} -void wolfSSL_SetEccKeyGenCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->EccKeyGenCtx = ctx; -} -void* wolfSSL_GetEccKeyGenCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->EccKeyGenCtx; - - return NULL; -} -void wolfSSL_CTX_SetEccSignCtx(WOLFSSL_CTX* ctx, void *userCtx) -{ - if (ctx) - ctx->EccSignCtx = userCtx; -} -void* wolfSSL_CTX_GetEccSignCtx(WOLFSSL_CTX* ctx) -{ - if (ctx) - return ctx->EccSignCtx; - - return NULL; -} - -WOLFSSL_ABI -void wolfSSL_CTX_SetEccSignCb(WOLFSSL_CTX* ctx, CallbackEccSign cb) -{ - if (ctx) - ctx->EccSignCb = cb; -} -void wolfSSL_SetEccSignCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->EccSignCtx = ctx; -} -void* wolfSSL_GetEccSignCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->EccSignCtx; - - return NULL; -} - -void wolfSSL_CTX_SetEccVerifyCb(WOLFSSL_CTX* ctx, CallbackEccVerify cb) -{ - if (ctx) - ctx->EccVerifyCb = cb; -} -void wolfSSL_SetEccVerifyCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->EccVerifyCtx = ctx; -} -void* wolfSSL_GetEccVerifyCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->EccVerifyCtx; - - return NULL; -} - -void wolfSSL_CTX_SetEccSharedSecretCb(WOLFSSL_CTX* ctx, - CallbackEccSharedSecret cb) -{ - if (ctx) - ctx->EccSharedSecretCb = cb; -} -void wolfSSL_SetEccSharedSecretCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->EccSharedSecretCtx = ctx; -} -void* wolfSSL_GetEccSharedSecretCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->EccSharedSecretCtx; - - return NULL; -} -#endif /* HAVE_ECC */ - -#ifdef HAVE_ED25519 -void wolfSSL_CTX_SetEd25519SignCb(WOLFSSL_CTX* ctx, CallbackEd25519Sign cb) -{ - if (ctx) - ctx->Ed25519SignCb = cb; -} -void wolfSSL_SetEd25519SignCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->Ed25519SignCtx = ctx; -} -void* wolfSSL_GetEd25519SignCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->Ed25519SignCtx; - - return NULL; -} - -void wolfSSL_CTX_SetEd25519VerifyCb(WOLFSSL_CTX* ctx, CallbackEd25519Verify cb) -{ - if (ctx) - ctx->Ed25519VerifyCb = cb; -} -void wolfSSL_SetEd25519VerifyCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->Ed25519VerifyCtx = ctx; -} -void* wolfSSL_GetEd25519VerifyCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->Ed25519VerifyCtx; - - return NULL; -} -#endif /* HAVE_ED25519 */ - -#ifdef HAVE_CURVE25519 -void wolfSSL_CTX_SetX25519KeyGenCb(WOLFSSL_CTX* ctx, - CallbackX25519KeyGen cb) -{ - if (ctx) - ctx->X25519KeyGenCb = cb; -} -void wolfSSL_SetX25519KeyGenCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->X25519KeyGenCtx = ctx; -} -void* wolfSSL_GetX25519KeyGenCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->X25519KeyGenCtx; - - return NULL; -} - -void wolfSSL_CTX_SetX25519SharedSecretCb(WOLFSSL_CTX* ctx, - CallbackX25519SharedSecret cb) -{ - if (ctx) - ctx->X25519SharedSecretCb = cb; -} -void wolfSSL_SetX25519SharedSecretCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->X25519SharedSecretCtx = ctx; -} -void* wolfSSL_GetX25519SharedSecretCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->X25519SharedSecretCtx; - - return NULL; -} -#endif /* HAVE_CURVE25519 */ - -#ifdef HAVE_ED448 -void wolfSSL_CTX_SetEd448SignCb(WOLFSSL_CTX* ctx, CallbackEd448Sign cb) -{ - if (ctx) - ctx->Ed448SignCb = cb; -} -void wolfSSL_SetEd448SignCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->Ed448SignCtx = ctx; -} -void* wolfSSL_GetEd448SignCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->Ed448SignCtx; - - return NULL; -} - -void wolfSSL_CTX_SetEd448VerifyCb(WOLFSSL_CTX* ctx, CallbackEd448Verify cb) -{ - if (ctx) - ctx->Ed448VerifyCb = cb; -} -void wolfSSL_SetEd448VerifyCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->Ed448VerifyCtx = ctx; -} -void* wolfSSL_GetEd448VerifyCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->Ed448VerifyCtx; - - return NULL; -} -#endif /* HAVE_ED448 */ - -#ifdef HAVE_CURVE448 -void wolfSSL_CTX_SetX448KeyGenCb(WOLFSSL_CTX* ctx, - CallbackX448KeyGen cb) -{ - if (ctx) - ctx->X448KeyGenCb = cb; -} -void wolfSSL_SetX448KeyGenCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->X448KeyGenCtx = ctx; -} -void* wolfSSL_GetX448KeyGenCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->X448KeyGenCtx; - - return NULL; -} - -void wolfSSL_CTX_SetX448SharedSecretCb(WOLFSSL_CTX* ctx, - CallbackX448SharedSecret cb) -{ - if (ctx) - ctx->X448SharedSecretCb = cb; -} -void wolfSSL_SetX448SharedSecretCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->X448SharedSecretCtx = ctx; -} -void* wolfSSL_GetX448SharedSecretCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->X448SharedSecretCtx; - - return NULL; -} -#endif /* HAVE_CURVE448 */ - -#ifndef NO_RSA -void wolfSSL_CTX_SetRsaSignCb(WOLFSSL_CTX* ctx, CallbackRsaSign cb) -{ - if (ctx) - ctx->RsaSignCb = cb; -} -void wolfSSL_CTX_SetRsaSignCheckCb(WOLFSSL_CTX* ctx, CallbackRsaVerify cb) -{ - if (ctx) - ctx->RsaSignCheckCb = cb; -} -void wolfSSL_SetRsaSignCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->RsaSignCtx = ctx; -} -void* wolfSSL_GetRsaSignCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->RsaSignCtx; - - return NULL; -} - - -void wolfSSL_CTX_SetRsaVerifyCb(WOLFSSL_CTX* ctx, CallbackRsaVerify cb) -{ - if (ctx) - ctx->RsaVerifyCb = cb; -} -void wolfSSL_SetRsaVerifyCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->RsaVerifyCtx = ctx; -} -void* wolfSSL_GetRsaVerifyCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->RsaVerifyCtx; - - return NULL; -} - -#ifdef WC_RSA_PSS -void wolfSSL_CTX_SetRsaPssSignCb(WOLFSSL_CTX* ctx, CallbackRsaPssSign cb) -{ - if (ctx) - ctx->RsaPssSignCb = cb; -} -void wolfSSL_CTX_SetRsaPssSignCheckCb(WOLFSSL_CTX* ctx, - CallbackRsaPssVerify cb) -{ - if (ctx) - ctx->RsaPssSignCheckCb = cb; -} -void wolfSSL_SetRsaPssSignCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->RsaPssSignCtx = ctx; -} -void* wolfSSL_GetRsaPssSignCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->RsaPssSignCtx; - - return NULL; -} - -void wolfSSL_CTX_SetRsaPssVerifyCb(WOLFSSL_CTX* ctx, CallbackRsaPssVerify cb) -{ - if (ctx) - ctx->RsaPssVerifyCb = cb; -} -void wolfSSL_SetRsaPssVerifyCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->RsaPssVerifyCtx = ctx; -} -void* wolfSSL_GetRsaPssVerifyCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->RsaPssVerifyCtx; - - return NULL; -} -#endif /* WC_RSA_PSS */ - -void wolfSSL_CTX_SetRsaEncCb(WOLFSSL_CTX* ctx, CallbackRsaEnc cb) -{ - if (ctx) - ctx->RsaEncCb = cb; -} -void wolfSSL_SetRsaEncCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->RsaEncCtx = ctx; + return WOLFSSL_SUCCESS; +#else + (void)chain; + (void)idx; + (void)buf; + (void)inLen; + (void)outLen; + return WOLFSSL_FAILURE; +#endif /* WOLFSSL_PEM_TO_DER || WOLFSSL_DER_TO_PEM */ } -void* wolfSSL_GetRsaEncCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->RsaEncCtx; - return NULL; -} +#endif /* SESSION_CERTS */ -void wolfSSL_CTX_SetRsaDecCb(WOLFSSL_CTX* ctx, CallbackRsaDec cb) -{ - if (ctx) - ctx->RsaDecCb = cb; -} -void wolfSSL_SetRsaDecCtx(WOLFSSL* ssl, void *ctx) +#ifdef HAVE_FUZZER +void wolfSSL_SetFuzzerCb(WOLFSSL* ssl, CallbackFuzzer cbf, void* fCtx) { - if (ssl) - ssl->RsaDecCtx = ctx; + if (ssl) { + ssl->fuzzerCb = cbf; + ssl->fuzzerCtx = fCtx; + } } -void* wolfSSL_GetRsaDecCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->RsaDecCtx; +#endif - return NULL; -} -#endif /* NO_RSA */ +#ifndef NO_CERTS +#ifdef HAVE_PK_CALLBACKS /* callback for premaster secret generation */ void wolfSSL_CTX_SetGenPreMasterCb(WOLFSSL_CTX* ctx, CallbackGenPreMaster cb) @@ -19323,31 +13934,6 @@ void wolfSSL_CTX_SetPerformTlsRecordProcessingCb(WOLFSSL_CTX* ctx, #endif /* HAVE_PK_CALLBACKS */ #endif /* NO_CERTS */ -#if defined(HAVE_PK_CALLBACKS) && !defined(NO_DH) -void wolfSSL_CTX_SetDhGenerateKeyPair(WOLFSSL_CTX* ctx, - CallbackDhGenerateKeyPair cb) { - if (ctx) - ctx->DhGenerateKeyPairCb = cb; -} -void wolfSSL_CTX_SetDhAgreeCb(WOLFSSL_CTX* ctx, CallbackDhAgree cb) -{ - if (ctx) - ctx->DhAgreeCb = cb; -} -void wolfSSL_SetDhAgreeCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->DhAgreeCtx = ctx; -} -void* wolfSSL_GetDhAgreeCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->DhAgreeCtx; - - return NULL; -} -#endif /* HAVE_PK_CALLBACKS && !NO_DH */ - #if defined(HAVE_PK_CALLBACKS) && defined(HAVE_HKDF) void wolfSSL_CTX_SetHKDFExtractCb(WOLFSSL_CTX* ctx, CallbackHKDFExtract cb) @@ -20644,114 +15230,9 @@ VerifyCallback wolfSSL_get_verify_callback(WOLFSSL* ssl) return NULL; } -#ifndef NO_BIO -/* Converts EVP_PKEY data from a bio buffer to a WOLFSSL_EVP_PKEY structure. -Returns pointer to private EVP_PKEY struct upon success, NULL if there -is a failure.*/ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_bio(WOLFSSL_BIO* bio, - WOLFSSL_EVP_PKEY** out) -{ - unsigned char* mem = NULL; - int memSz = 0; - WOLFSSL_EVP_PKEY* key = NULL; - unsigned char* extraBioMem = NULL; - - WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_bio"); - - if (bio == NULL) { - return NULL; - } - (void)out; - - memSz = wolfSSL_BIO_get_len(bio); - if (memSz <= 0) { - WOLFSSL_MSG("wolfSSL_BIO_get_len() failure"); - return NULL; - } - - mem = (unsigned char*)XMALLOC((size_t)memSz, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (mem == NULL) { - WOLFSSL_MSG("Malloc failure"); - return NULL; - } - - if (wolfSSL_BIO_read(bio, (unsigned char*)mem, memSz) == memSz) { - int extraBioMemSz; - int derLength; - - /* Determines key type and returns the new private EVP_PKEY object */ - if ((key = wolfSSL_d2i_PrivateKey_EVP(NULL, &mem, (long)memSz)) == - NULL) { - WOLFSSL_MSG("wolfSSL_d2i_PrivateKey_EVP() failure"); - XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - return NULL; - } - - /* Write extra data back into bio object if necessary. */ - derLength = key->pkey_sz; - extraBioMemSz = (memSz - derLength); - if (extraBioMemSz > 0) { - int i; - int j = 0; - - extraBioMem = (unsigned char *)XMALLOC((size_t)extraBioMemSz, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (extraBioMem == NULL) { - WOLFSSL_MSG("Malloc failure"); - XFREE((unsigned char*)extraBioMem, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER); - XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - return NULL; - } - - for (i = derLength; i < memSz; i++) { - *(extraBioMem + j) = *(mem + i); - j++; - } - - wolfSSL_BIO_write(bio, extraBioMem, extraBioMemSz); - if (wolfSSL_BIO_get_len(bio) <= 0) { - WOLFSSL_MSG("Failed to write memory to bio"); - XFREE((unsigned char*)extraBioMem, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER); - XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - return NULL; - } - XFREE((unsigned char*)extraBioMem, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER); - } - - if (out != NULL) { - *out = key; - } - } - XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); - return key; -} -#endif /* !NO_BIO */ - #endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT */ -#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \ - defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) || \ - defined(WOLFSSL_QT) || defined(WOLFSSL_WPAS_SMALL) - -/* Converts a DER encoded private key to a WOLFSSL_EVP_PKEY structure. - * returns a pointer to a new WOLFSSL_EVP_PKEY structure on success and NULL - * on fail */ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_EVP(WOLFSSL_EVP_PKEY** out, - unsigned char** in, long inSz) -{ - WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_EVP"); - return d2iGenericKey(out, (const unsigned char**)in, inSz, 1); -} - -#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT || - * WOLFSSL_WPAS_SMALL*/ - - /* stunnel compatibility functions*/ #if defined(OPENSSL_ALL) || (defined(OPENSSL_EXTRA) && \ (defined(HAVE_STUNNEL) || defined(WOLFSSL_NGINX) || \ @@ -22046,182 +16527,6 @@ long wolfSSL_CTX_set_tlsext_ticket_keys(WOLFSSL_CTX *ctx, } #endif -#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) -#ifdef HAVE_OCSP -/* Not an OpenSSL API. */ -int wolfSSL_get_ocsp_response(WOLFSSL* ssl, byte** response) -{ - *response = ssl->ocspCsrResp[0].buffer; - return ssl->ocspCsrResp[0].length; -} - -/* Not an OpenSSL API. */ -char* wolfSSL_get_ocsp_url(WOLFSSL* ssl) -{ - return ssl->url; -} - -/* Not an OpenSSL API. */ -int wolfSSL_set_ocsp_url(WOLFSSL* ssl, char* url) -{ - if (ssl == NULL) - return WOLFSSL_FAILURE; - - ssl->url = url; - return WOLFSSL_SUCCESS; -} -#endif /* OCSP */ -#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ - -#if defined(HAVE_OCSP) && !defined(NO_ASN_TIME) -int wolfSSL_get_ocsp_producedDate( - WOLFSSL *ssl, - byte *producedDate, - size_t producedDate_space, - int *producedDateFormat) -{ - if ((ssl->ocspProducedDateFormat != ASN_UTC_TIME) && - (ssl->ocspProducedDateFormat != ASN_GENERALIZED_TIME)) - return BAD_FUNC_ARG; - - if ((producedDate == NULL) || (producedDateFormat == NULL)) - return BAD_FUNC_ARG; - - if (XSTRLEN((char *)ssl->ocspProducedDate) >= producedDate_space) - return BUFFER_E; - - XSTRNCPY((char *)producedDate, (const char *)ssl->ocspProducedDate, - producedDate_space); - *producedDateFormat = ssl->ocspProducedDateFormat; - - return 0; -} - -int wolfSSL_get_ocsp_producedDate_tm(WOLFSSL *ssl, struct tm *produced_tm) { - int idx = 0; - - if ((ssl->ocspProducedDateFormat != ASN_UTC_TIME) && - (ssl->ocspProducedDateFormat != ASN_GENERALIZED_TIME)) - return BAD_FUNC_ARG; - - if (produced_tm == NULL) - return BAD_FUNC_ARG; - - if (ExtractDate(ssl->ocspProducedDate, - (unsigned char)ssl->ocspProducedDateFormat, produced_tm, &idx, - MAX_DATE_SZ)) - return 0; - else - return ASN_PARSE_E; -} -#endif - -#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ - || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) -int wolfSSL_CTX_get_tlsext_status_cb(WOLFSSL_CTX* ctx, tlsextStatusCb* cb) -{ - if (ctx == NULL || ctx->cm == NULL || cb == NULL) - return WOLFSSL_FAILURE; - -#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ - || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) - if (ctx->cm->ocsp_stapling == NULL) - return WOLFSSL_FAILURE; - - *cb = ctx->cm->ocsp_stapling->statusCb; -#else - (void)cb; - *cb = NULL; -#endif - - return WOLFSSL_SUCCESS; - -} - -int wolfSSL_CTX_set_tlsext_status_cb(WOLFSSL_CTX* ctx, tlsextStatusCb cb) -{ - if (ctx == NULL || ctx->cm == NULL) - return WOLFSSL_FAILURE; - -#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ - || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) - /* Ensure stapling is on for callback to be used. */ - wolfSSL_CTX_EnableOCSPStapling(ctx); - - if (ctx->cm->ocsp_stapling == NULL) - return WOLFSSL_FAILURE; - - ctx->cm->ocsp_stapling->statusCb = cb; -#else - (void)cb; -#endif - - return WOLFSSL_SUCCESS; -} - -long wolfSSL_CTX_set_tlsext_status_arg(WOLFSSL_CTX* ctx, void* arg) -{ - if (ctx == NULL || ctx->cm == NULL) - return WOLFSSL_FAILURE; - -#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ - || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) - /* Ensure stapling is on for callback to be used. */ - wolfSSL_CTX_EnableOCSPStapling(ctx); - - if (ctx->cm->ocsp_stapling == NULL) - return WOLFSSL_FAILURE; - - ctx->cm->ocsp_stapling->statusCbArg = arg; -#else - (void)arg; -#endif - - return WOLFSSL_SUCCESS; -} - -long wolfSSL_get_tlsext_status_ocsp_resp(WOLFSSL *ssl, unsigned char **resp) -{ - if (ssl == NULL || resp == NULL) - return 0; - - *resp = ssl->ocspCsrResp[0].buffer; - return (long)ssl->ocspCsrResp[0].length; -} - -long wolfSSL_set_tlsext_status_ocsp_resp(WOLFSSL *ssl, unsigned char *resp, - int len) -{ - return wolfSSL_set_tlsext_status_ocsp_resp_multi(ssl, resp, len, 0); -} - -int wolfSSL_set_tlsext_status_ocsp_resp_multi(WOLFSSL* ssl, unsigned char *resp, - int len, word32 idx) -{ - if (ssl == NULL || idx >= XELEM_CNT(ssl->ocspCsrResp) || len < 0) - return WOLFSSL_FAILURE; - if (!((resp == NULL) ^ (len > 0))) - return WOLFSSL_FAILURE; - - XFREE(ssl->ocspCsrResp[idx].buffer, NULL, 0); - ssl->ocspCsrResp[idx].buffer = resp; - ssl->ocspCsrResp[idx].length = (word32)len; - - return WOLFSSL_SUCCESS; -} - -#ifndef NO_WOLFSSL_SERVER -void wolfSSL_CTX_set_ocsp_status_verify_cb(WOLFSSL_CTX* ctx, - ocspVerifyStatusCb cb, void* cbArg) -{ - if (ctx != NULL) { - ctx->ocspStatusVerifyCb = cb; - ctx->ocspStatusVerifyCbArg = cbArg; - } -} -#endif -#endif - #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) int wolfSSL_CTX_get_extra_chain_certs(WOLFSSL_CTX* ctx, @@ -23745,144 +18050,6 @@ void wolfSSL_ERR_remove_state(unsigned long id) #endif /* OPENSSL_EXTRA */ -#ifdef OPENSSL_ALL - -#if !defined(NO_BIO) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8) - -static int bio_get_data(WOLFSSL_BIO* bio, byte** data) -{ - int ret = 0; - byte* mem = NULL; - - ret = wolfSSL_BIO_get_len(bio); - if (ret > 0) { - mem = (byte*)XMALLOC((size_t)ret, bio->heap, DYNAMIC_TYPE_OPENSSL); - if (mem == NULL) { - WOLFSSL_MSG("Memory error"); - ret = MEMORY_E; - } - if (ret >= 0) { - if ((ret = wolfSSL_BIO_read(bio, mem, ret)) <= 0) { - XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); - ret = MEMORY_E; - mem = NULL; - } - } - } - - *data = mem; - - return ret; -} - -/* DER data is PKCS#8 encrypted. */ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_PKCS8PrivateKey_bio(WOLFSSL_BIO* bio, - WOLFSSL_EVP_PKEY** pkey, - wc_pem_password_cb* cb, - void* ctx) -{ - int ret; - byte* der; - int len; - byte* p; - word32 algId; - WOLFSSL_EVP_PKEY* key; - - if ((len = bio_get_data(bio, &der)) < 0) - return NULL; - - if (cb != NULL) { - char password[NAME_SZ]; - int passwordSz = cb(password, sizeof(password), PEM_PASS_READ, ctx); - if (passwordSz < 0) { - XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); - return NULL; - } - #ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Add("wolfSSL_d2i_PKCS8PrivateKey_bio password", password, - passwordSz); - #endif - - ret = ToTraditionalEnc(der, (word32)len, password, passwordSz, &algId); - if (ret < 0) { - XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); - return NULL; - } - - ForceZero(password, (word32)passwordSz); - #ifdef WOLFSSL_CHECK_MEM_ZERO - wc_MemZero_Check(password, passwordSz); - #endif - } - - p = der; - key = wolfSSL_d2i_PrivateKey_EVP(pkey, &p, len); - XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); - return key; -} - -#endif /* !NO_BIO && !NO_PWDBASED && HAVE_PKCS8 */ - -/* Detect which type of key it is before decoding. */ -WOLFSSL_EVP_PKEY* wolfSSL_d2i_AutoPrivateKey(WOLFSSL_EVP_PKEY** pkey, - const unsigned char** pp, - long length) -{ - int ret; - WOLFSSL_EVP_PKEY* key = NULL; - const byte* der = *pp; - word32 idx = 0; - int len = 0; - int cnt = 0; - word32 algId; - word32 keyLen = (word32)length; - - /* Take off PKCS#8 wrapper if found. */ - if ((len = ToTraditionalInline_ex(der, &idx, keyLen, &algId)) >= 0) { - der += idx; - keyLen = (word32)len; - } - idx = 0; - len = 0; - - /* Use the number of elements in the outer sequence to determine key type. - */ - ret = GetSequence(der, &idx, &len, keyLen); - if (ret >= 0) { - word32 end = idx + (word32)len; - while (ret >= 0 && idx < end) { - /* Skip type */ - idx++; - /* Get length and skip over - keeping count */ - len = 0; - ret = GetLength(der, &idx, &len, keyLen); - if (ret >= 0) { - if (idx + (word32)len > end) - ret = ASN_PARSE_E; - else { - idx += (word32)len; - cnt++; - } - } - } - } - - if (ret >= 0) { - int type; - /* ECC includes version, private[, curve][, public key] */ - if (cnt >= 2 && cnt <= 4) - type = WC_EVP_PKEY_EC; - else - type = WC_EVP_PKEY_RSA; - - key = wolfSSL_d2i_PrivateKey(type, pkey, &der, keyLen); - *pp = der; - } - - return key; -} -#endif /* OPENSSL_ALL */ - #ifdef WOLFSSL_STATIC_EPHEMERAL int wolfSSL_StaticEphemeralKeyLoad(WOLFSSL* ssl, int keyAlgo, void* keyPtr) { diff --git a/src/ssl_api_cert.c b/src/ssl_api_cert.c new file mode 100644 index 0000000000..5871525dc4 --- /dev/null +++ b/src/ssl_api_cert.c @@ -0,0 +1,1740 @@ +/* ssl_api_cert.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 + +#if !defined(WOLFSSL_SSL_API_CERT_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_api_cert.c is not compiled separately from ssl.c + #endif +#else + +#ifndef NO_CERTS + +/* Set whether mutual authentication is required for connections. + * Server side only. + * + * @param [in] ctx The SSL/TLS CTX object. + * @param [in] req 1 to indicate required and 0 when not. + * @return 0 on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return SIDE_ERROR when not a server. + */ +int wolfSSL_CTX_mutual_auth(WOLFSSL_CTX* ctx, int req) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + if (ctx->method->side != WOLFSSL_SERVER_END) + return SIDE_ERROR; + + ctx->mutualAuth = (byte)req; + + return 0; +} + +/* Set whether mutual authentication is required for the connection. + * Server side only. + * + * @param [in] ssl The SSL/TLS object. + * @param [in] req 1 to indicate required and 0 when not. + * @return 0 on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return SIDE_ERROR when not a server + */ +int wolfSSL_mutual_auth(WOLFSSL* ssl, int req) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + if (ssl->options.side != WOLFSSL_SERVER_END) + return SIDE_ERROR; + + ssl->options.mutualAuth = (word16)req; + + return 0; +} + +/* Get the certificate manager from the WOLFSSL_CTX. + * + * @param [in] ctx SSL/TLS CTX object. + * @return Certificate manager object on success. + * @return NULL when ctx is NULL. + */ +WOLFSSL_CERT_MANAGER* wolfSSL_CTX_GetCertManager(WOLFSSL_CTX* ctx) +{ + WOLFSSL_CERT_MANAGER* cm = NULL; + + if (ctx) + cm = ctx->cm; + + return cm; +} + +/* Sets the max chain depth when verifying a certificate chain. + * + * Default depth is set to MAX_CHAIN_DEPTH. + * + * @param [in] ctx WOLFSSL_CTX structure to set depth in + * @param [in] depth max depth + */ +void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx, int depth) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_verify_depth"); + + if ((ctx == NULL) || (depth < 0) || (depth > MAX_CHAIN_DEPTH)) { + WOLFSSL_MSG("Bad depth argument, too large or less than 0"); + } + else { + ctx->verifyDepth = (byte)depth; + } +} + + +/* Get certificate chaining depth of SSL/TLS context object + * + * @param [in] ctx SSL/TLS context object. + * @return Verification depth on success. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +long wolfSSL_CTX_get_verify_depth(WOLFSSL_CTX* ctx) +{ + long ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + #ifndef OPENSSL_EXTRA + ret = MAX_CHAIN_DEPTH; + #else + ret = ctx->verifyDepth; + #endif + } + + return ret; +} + +/* Get certificate chaining depth of SSL/TLS object + * + * @param [in] ssl SSL/TLS object. + * @return Verification depth on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +long wolfSSL_get_verify_depth(WOLFSSL* ssl) +{ + long ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + #ifndef OPENSSL_EXTRA + ret = MAX_CHAIN_DEPTH; + #else + ret = ssl->options.verifyDepth; + #endif + } + + return ret; +} + +#if defined(HAVE_RPK) +/* TODO: Change this to use a bitfield. */ + +/* Confirm that all the byte data in the buffer is unique. + * + * @param [in] buf Buffer to check. + * @param [in] len Length of buffer in bytes. + * @return 1 if all the byte data in the buffer is unique. + * @return 0 otherwise. + */ +static int isArrayUnique(const char* buf, size_t len) +{ + size_t i; + /* check the array is unique */ + for (i = 0; i < len - 1; ++i) { + size_t j; + for (j = i + 1; j < len; ++j) { + if (buf[i] == buf[j]) { + return 0; + } + } + } + return 1; +} +/* Set user preference for the {client,server}_cert_type extension. + * + * Takes byte array containing cert types the caller can provide to its peer. + * Cert types are in preferred order in the array. + * + * @param [in] cfg Raw Public Key configuration. + * @param [in] client Indicates whether this is the client side. + * @param [in] buf List of certificate types. + * @param [in] len Length of certificate types. + * @return 1 on success. + * @return BAD_FUNC_ARG when cfg is NULL. + * @return BAD_FUNC_ARG when len is too long. + * @return BAD_FUNC_ARG when buffer values are not unique. + * @return BAD_FUNC_ARG when buffer contains unrecognized certificate type. + */ +static int set_cert_type(RpkConfig* cfg, int client, const char* buf, + int len) +{ + int i; + byte* certTypeCnt; + byte* certTypes; + + /* Validate parameters. */ + if ((cfg == NULL) || (len > (client ? MAX_CLIENT_CERT_TYPE_CNT : + MAX_SERVER_CERT_TYPE_CNT))) { + return BAD_FUNC_ARG; + } + + /* Get preferred certificate types for side. */ + if (client) { + certTypeCnt = &cfg->preferred_ClientCertTypeCnt; + certTypes = cfg->preferred_ClientCertTypes; + } + else { + certTypeCnt = &cfg->preferred_ServerCertTypeCnt; + certTypes = cfg->preferred_ServerCertTypes; + } + /* If no buffer or empty buffer passed in, set the defaults. */ + if ((buf == NULL) || (len == 0)) { + *certTypeCnt = 1; + for (i = 0; i < 2; i++) { + certTypes[i] = WOLFSSL_CERT_TYPE_X509; + } + return 1; + } + + /* Check that the certificate types set are unique. */ + if (!isArrayUnique(buf, (size_t)len)) + return BAD_FUNC_ARG; + + /* Check that the certificate types being set are known and then set. */ + for (i = 0; i < len; i++) { + if ((buf[i] != WOLFSSL_CERT_TYPE_RPK) && + (buf[i] != WOLFSSL_CERT_TYPE_X509)) { + return BAD_FUNC_ARG; + } + certTypes[i] = (byte)buf[i]; + } + *certTypeCnt = len; + + return 1; +} +/* Set the client certificate types against the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] buf List of certificate types. + * @param [in] len Length of certificate types. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return BAD_FUNC_ARG when len is too long. + * @return BAD_FUNC_ARG when buffer values are not unique. + * @return BAD_FUNC_ARG when buffer contains unrecognized certificate type. + */ +int wolfSSL_CTX_set_client_cert_type(WOLFSSL_CTX* ctx, const char* buf, int len) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = set_cert_type(&ctx->rpkConfig, 1, buf, len); + } + + return ret; +} +/* Set the server certificate types against the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] buf List of certificate types. + * @param [in] len Length of certificate types. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx is NULL. + * @return BAD_FUNC_ARG when len is too long. + * @return BAD_FUNC_ARG when buffer values are not unique. + * @return BAD_FUNC_ARG when buffer contains unrecognized certificate type. + */ +int wolfSSL_CTX_set_server_cert_type(WOLFSSL_CTX* ctx, const char* buf, int len) +{ + int ret; + + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = set_cert_type(&ctx->rpkConfig, 0, buf, len); + } + + return ret; +} +/* Set the client certificate types against the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] buf List of certificate types. + * @param [in] len Length of certificate types. + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return BAD_FUNC_ARG when len is too long. + * @return BAD_FUNC_ARG when buffer values are not unique. + * @return BAD_FUNC_ARG when buffer contains unrecognized certificate type. + */ +int wolfSSL_set_client_cert_type(WOLFSSL* ssl, const char* buf, int len) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = set_cert_type(&ssl->options.rpkConfig, 1, buf, len); + } + + return ret; +} +/* Set the server certificate types against the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] buf List of certificate types. + * @param [in] len Length of certificate types. + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return BAD_FUNC_ARG when len is too long. + * @return BAD_FUNC_ARG when buffer values are not unique. + * @return BAD_FUNC_ARG when buffer contains unrecognized certificate type. + */ +int wolfSSL_set_server_cert_type(WOLFSSL* ssl, const char* buf, int len) +{ + int ret; + + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = set_cert_type(&ssl->options.rpkConfig, 0, buf, len); + } + + return ret; +} + +/* Get negotiated client certificate type value. + * + * WOLFSSL_CERT_TYPE_UNKNOWN returned when no negotiation has been performed. + * + * @param [in] ssl SSL/TLS object. + * @param [out] tp Certificate type. One of: + * -1: WOLFSSL_CERT_TYPE_UNKNOWN + * 0: WOLFSSL_CERT_TYPE_X509 + * 2: WOLFSSL_CERT_TYPE_RPK + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl or tp is NULL. + */ +int wolfSSL_get_negotiated_client_cert_type(WOLFSSL* ssl, int* tp) +{ + int ret = 1; + + /* Validate parameters. */ + if ((ssl == NULL) || (tp == NULL)) { + ret = BAD_FUNC_ARG; + } + /* Check side. */ + else if (ssl->options.side == WOLFSSL_CLIENT_END) { + /* Check certificate type negotiated. */ + if (ssl->options.rpkState.received_ClientCertTypeCnt == 1) { + *tp = ssl->options.rpkState.received_ClientCertTypes[0]; + } + else { + *tp = WOLFSSL_CERT_TYPE_UNKNOWN; + } + } + /* Check certificate type negotiated. */ + else if (ssl->options.rpkState.sending_ClientCertTypeCnt == 1) { + *tp = ssl->options.rpkState.sending_ClientCertTypes[0]; + } + else { + *tp = WOLFSSL_CERT_TYPE_UNKNOWN; + } + + return ret; +} + +/* Get negotiated server certificate type value. + * + * WOLFSSL_CERT_TYPE_UNKNOWN returned when no negotiation has been performed. + * + * @param [in] ssl SSL/TLS object. + * @param [out] tp Certificate type. One of: + * -1: WOLFSSL_CERT_TYPE_UNKNOWN + * 0: WOLFSSL_CERT_TYPE_X509 + * 2: WOLFSSL_CERT_TYPE_RPK + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl or tp is NULL. + */ +int wolfSSL_get_negotiated_server_cert_type(WOLFSSL* ssl, int* tp) +{ + int ret = 1; + + /* Validate parameters. */ + if ((ssl == NULL) || (tp == NULL)) { + ret = BAD_FUNC_ARG; + } + /* Check side. */ + else if (ssl->options.side == WOLFSSL_CLIENT_END) { + /* Check certificate type negotiated. */ + if (ssl->options.rpkState.received_ServerCertTypeCnt == 1) { + *tp = ssl->options.rpkState.received_ServerCertTypes[0]; + } + else { + *tp = WOLFSSL_CERT_TYPE_UNKNOWN; + } + } + /* Check certificate type negotiated. */ + else if (ssl->options.rpkState.sending_ServerCertTypeCnt == 1) { + *tp = ssl->options.rpkState.sending_ServerCertTypes[0]; + } + else { + *tp = WOLFSSL_CERT_TYPE_UNKNOWN; + } + return ret; +} +#endif /* HAVE_RPK */ + +/* Certificate verification options. */ +typedef struct { + /* Verify the peer certificate. */ + byte verifyPeer:1; + /* No peer certificate verification. */ + byte verifyNone:1; + /* Fail when no peer certificate seen. */ + byte failNoCert:1; + /* Fail when no peer certificate except when PSK handshake performed. */ + byte failNoCertxPSK:1; +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + /* Verify peer certificate post handshake. */ + byte verifyPostHandshake:1; +#endif +} SetVerifyOptions; + +/* Convert the mode flags into certificate verification options. + * + * @param [in] mode Certificate verification mode flags. + * @return Certificate verification options. + */ +static SetVerifyOptions ModeToVerifyOptions(int mode) +{ + SetVerifyOptions opts; + + /* Set the options to the default - none set. */ + XMEMSET(&opts, 0, sizeof(SetVerifyOptions)); + + /* When the mode is not default - set the options. */ + if (mode != WOLFSSL_VERIFY_DEFAULT) { + opts.verifyNone = (mode == WOLFSSL_VERIFY_NONE); + /* When not no verification, set the chosen options. */ + if (!opts.verifyNone) { + opts.verifyPeer = + (mode & WOLFSSL_VERIFY_PEER) != 0; + opts.failNoCertxPSK = + (mode & WOLFSSL_VERIFY_FAIL_EXCEPT_PSK) != 0; + opts.failNoCert = + (mode & WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT) != 0; +#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + opts.verifyPostHandshake = + (mode & WOLFSSL_VERIFY_POST_HANDSHAKE) != 0; +#endif + } + } + + return opts; +} + +/* Set the verification options against the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] mode Verification mode options. + * @param [in] verify_callback Verification callback. + */ +WOLFSSL_ABI void wolfSSL_CTX_set_verify(WOLFSSL_CTX* ctx, int mode, + VerifyCallback verify_callback) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_verify"); + + /* Ensure we have an SSL/TLS context to work with. */ + if (ctx != NULL) { + SetVerifyOptions opts = ModeToVerifyOptions(mode); + + /* Set the bitfield options. */ + ctx->verifyNone = opts.verifyNone; + ctx->verifyPeer = opts.verifyPeer; + ctx->failNoCert = opts.failNoCert; + ctx->failNoCertxPSK = opts.failNoCertxPSK; + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + ctx->verifyPostHandshake = opts.verifyPostHandshake; + #endif + + /* Store the user verification callback against the context. */ + ctx->verifyCallback = verify_callback; + } +} + +#ifdef OPENSSL_ALL +/* Set certificate verification callback and context against SSL/TLS context. + * + * @param [in] ctx SSL/TLS context object. + * @param [in] cb Certificate verification callback. + * @param [in] arg Context for certification verification callback. + */ +void wolfSSL_CTX_set_cert_verify_callback(WOLFSSL_CTX* ctx, + CertVerifyCallback cb, void* arg) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_cert_verify_callback"); + + /* Ensure we have an SSL/TLS context to work with. */ + if (ctx != NULL) { + ctx->verifyCertCb = cb; + ctx->verifyCertCbArg = arg; + } +} +#endif + +/* Set the verification options against the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] mode Verification mode options. + * @param [in] verify_callback Verification callback. + */ +void wolfSSL_set_verify(WOLFSSL* ssl, int mode, VerifyCallback verify_callback) +{ + WOLFSSL_ENTER("wolfSSL_set_verify"); + + /* Ensure we have an SSL/TLS object to work with. */ + if (ssl != NULL) { + SetVerifyOptions opts = ModeToVerifyOptions(mode); + + /* Set the bitfield options. */ + ssl->options.verifyNone = opts.verifyNone; + ssl->options.verifyPeer = opts.verifyPeer; + ssl->options.failNoCert = opts.failNoCert; + ssl->options.failNoCertxPSK = opts.failNoCertxPSK; + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) + ssl->options.verifyPostHandshake = opts.verifyPostHandshake; + #endif + + /* Store the user verification callback against the object. */ + ssl->verifyCallback = verify_callback; + } +} + +/* Set the certificate verification result for the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] v Verification result. + */ +void wolfSSL_set_verify_result(WOLFSSL *ssl, long v) +{ + WOLFSSL_ENTER("wolfSSL_set_verify_result"); + + /* Ensure we have an SSL/TLS object to work with. */ + if (ssl != NULL) { + #if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + ssl->peerVerifyRet = (unsigned long)v; + #else + WOLFSSL_STUB("wolfSSL_set_verify_result"); + (void)v; + #endif + } +} + +/* Store user ctx for verify callback into SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] userCtx User context for verify callback. + */ +void wolfSSL_CTX_SetCertCbCtx(WOLFSSL_CTX* ctx, void* userCtx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_SetCertCbCtx"); + + /* Validate parameters. */ + if (ctx != NULL) { + ctx->verifyCbCtx = userCtx; + } +} + +/* Store user ctx for verify callback into SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx User context for verify callback. + */ +void wolfSSL_SetCertCbCtx(WOLFSSL* ssl, void* ctx) +{ + WOLFSSL_ENTER("wolfSSL_SetCertCbCtx"); + + /* Validate parameters. */ + if (ssl != NULL) { + ssl->verifyCbCtx = ctx; + } +} + + + +/* Store context CA Cache addition callback into SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] userCtx User context for verify callback. + */ +void wolfSSL_CTX_SetCACb(WOLFSSL_CTX* ctx, CallbackCACache cb) +{ + /* Validate parameters. */ + if ((ctx != NULL) && (ctx->cm != NULL)) { + ctx->cm->caCacheCallback = cb; + } +} + +#if defined(OPENSSL_EXTRA) && defined(WOLFSSL_TLS13) && \ + defined(WOLFSSL_POST_HANDSHAKE_AUTH) +/* For TLS v1.3, send authentication messages after handshake completes. + * + * @return 1 on success. + * @return UNSUPPORTED_PROTO_VERSION when not a TLSv1.3 handshake. + * @return 0 on other failure. + */ +int wolfSSL_verify_client_post_handshake(WOLFSSL* ssl) +{ + int ret; + + /* Do request of certificate. */ + ret = wolfSSL_request_certificate(ssl); + if (ret != 1) { + /* Special logging for wrong protocol version. */ + if ((ssl != NULL) && !IsAtLeastTLSv1_3(ssl->version)) { + WOLFSSL_ERROR(UNSUPPORTED_PROTO_VERSION); + } + else { + /* Other errors - return 0. */ + WOLFSSL_ERROR(ret); + } + ret = 0; + } + + return ret; +} + +/* Set whether handshakes from this SSL/TLS context allow auth post handshake. + * + * @param [in] ctx SSL/TLS context. + * @param [in] val Whether to allow post handshake authentication. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_set_post_handshake_auth(WOLFSSL_CTX* ctx, int val) +{ + int ret; + + /* Try to allow - really just checking conditions. */ + if (wolfSSL_CTX_allow_post_handshake_auth(ctx) == 0) { + /* Set value as a bit. */ + ctx->postHandshakeAuth = (val != 0); + ret = 1; + } + else { + ret = 0; + } + + return ret; +} +/* Set whether handshakes with this SSL/TLS object allow auth post handshake. + * + * @param [in] ctx SSL/TLS context. + * @param [in] val Whether to allow post handshake authentication. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_set_post_handshake_auth(WOLFSSL* ssl, int val) +{ + int ret; + + /* Try to allow - really just checking conditions. */ + if (wolfSSL_allow_post_handshake_auth(ssl) == 0) { + /* Set value as a bit. */ + ssl->options.postHandshakeAuth = (val != 0); + ret = 1; + } + else { + ret = 0; + } + + return ret; +} +#endif /* OPENSSL_EXTRA && WOLFSSL_TLS13 && WOLFSSL_POST_HANDSHAKE_AUTH */ + +#if defined(PERSIST_CERT_CACHE) + +#if !defined(NO_FILESYSTEM) + +/* Persist certificate cache in SSL/TLS context to file. + * + * @param [in] ctx SSL/TLS context. + * @param [in] fname Filename so store certificate cache to. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx or fname is NULL. + * @return Other values on failure. + */ +int wolfSSL_CTX_save_cert_cache(WOLFSSL_CTX* ctx, const char* fname) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_save_cert_cache"); + + /* Validate parameters. */ + if ((ctx == NULL) || (fname == NULL)) { + ret = BAD_FUNC_ARG; + } + else { + /* Save certificate cache. */ + ret = CM_SaveCertCache(ctx->cm, fname); + } + + return ret; +} + + +/* Load certificate cache into SSL/TLS context from file. + * + * @param [in] ctx SSL/TLS context. + * @param [in] fname Filename so store certificate cache to. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx or fname is NULL. + * @return Other values on failure. + */ +int wolfSSL_CTX_restore_cert_cache(WOLFSSL_CTX* ctx, const char* fname) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_restore_cert_cache"); + + /* Validate parameters. */ + if ((ctx == NULL) || (fname == NULL)) { + ret = BAD_FUNC_ARG; + } + else { + /* Restore certificate cache. */ + ret = CM_RestoreCertCache(ctx->cm, fname); + } + + return ret; +} + +#endif /* NO_FILESYSTEM */ + +/* Persist certificate cache in SSL/TLS context to memory. + * + * @param [in] ctx SSL/TLS context. + * @param [in] mem Memory to fill with certificate cache. + * @param [in] sz Size of memory to fill in bytes. + * @param [out] used The number of bytes of memory used. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx, mem or used is NULL. + * @return BAD_FUNC_ARG when sz is less than or equal to zero. + * @return Other values on failure. + */ +int wolfSSL_CTX_memsave_cert_cache(WOLFSSL_CTX* ctx, void* mem, + int sz, int* used) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_memsave_cert_cache"); + + /* Validate parameters. */ + if ((ctx == NULL) || (mem == NULL) || (used == NULL) || (sz <= 0)) { + ret = BAD_FUNC_ARG; + } + else { + /* Persist certificate change to memory. */ + ret = CM_MemSaveCertCache(ctx->cm, mem, sz, used); + } + + return ret; +} + + +/* Load certificate cache into SSL/TLS context from memory. + * + * @param [in] ctx SSL/TLS context. + * @param [in] mem Memory with certificate cache. + * @param [in] sz Size of certificate cache in bytes + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx or mem is NULL. + * @return BAD_FUNC_ARG when sz is less than or equal to zero. + * @return Other values on failure. + */ +int wolfSSL_CTX_memrestore_cert_cache(WOLFSSL_CTX* ctx, const void* mem, int sz) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_memrestore_cert_cache"); + + /* Validate parameters. */ + if ((ctx == NULL) || (mem == NULL) || (sz <= 0)) { + ret = BAD_FUNC_ARG; + } + else { + /* Restore certificate cache. */ + ret = CM_MemRestoreCertCache(ctx->cm, mem, sz); + } + + return ret; +} + + +/* Get size of certificate cache when persisted. + * + * @param [in] ctx SSL/TLS context. + * @return Size of certificate cache when pesisted in bytes. + * @return BAD_FUNC_ARG when ctx is NULL. + */ +int wolfSSL_CTX_get_cert_cache_memsize(WOLFSSL_CTX* ctx) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_get_cert_cache_memsize"); + + /* Validate parameter. */ + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + /* Get size. */ + ret = CM_GetCertCacheMemSize(ctx->cm); + } + + return ret; +} + +#endif /* PERSIST_CERT_CACHE */ + +/* Unload certificates and keys that the SSL/TLS object owns. + * + * The WOLFSSL_CTX referenced is untouched. + * + * @param [in] ssl SSL/TLS object. + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl is NULL. + */ +int wolfSSL_UnloadCertsKeys(WOLFSSL* ssl) +{ + int ret = 1; + + /* Validate parameter. */ + if (ssl == NULL) { + WOLFSSL_MSG("Null function arg"); + ret = BAD_FUNC_ARG; + } + else { + if (ssl->buffers.weOwnCert && !ssl->keepCert) { + WOLFSSL_MSG("Unloading cert"); + FreeDer(&ssl->buffers.certificate); + #ifdef KEEP_OUR_CERT + wolfSSL_X509_free(ssl->ourCert); + ssl->ourCert = NULL; + #endif + ssl->buffers.weOwnCert = 0; + } + + if (ssl->buffers.weOwnCertChain) { + WOLFSSL_MSG("Unloading cert chain"); + FreeDer(&ssl->buffers.certChain); + ssl->buffers.weOwnCertChain = 0; + } + + if (ssl->buffers.weOwnKey) { + WOLFSSL_MSG("Unloading key"); + ForceZero(ssl->buffers.key->buffer, ssl->buffers.key->length); + FreeDer(&ssl->buffers.key); + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + FreeDer(&ssl->buffers.keyMask); + #endif + ssl->buffers.weOwnKey = 0; + } + + #ifdef WOLFSSL_DUAL_ALG_CERTS + if (ssl->buffers.weOwnAltKey) { + WOLFSSL_MSG("Unloading alt key"); + ForceZero(ssl->buffers.altKey->buffer, ssl->buffers.altKey->length); + FreeDer(&ssl->buffers.altKey); + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + FreeDer(&ssl->buffers.altKeyMask); + #endif + ssl->buffers.weOwnAltKey = 0; + } + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + } + + return ret; +} + +/* Unload CAs from the certificate manager of the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx or ctx->cm is NULL. + * @return BAD_MUTEX_E when locking fails. + */ +int wolfSSL_CTX_UnloadCAs(WOLFSSL_CTX* ctx) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_UnloadCAs"); + + /* Validate parameter. */ + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = wolfSSL_CertManagerUnloadCAs(ctx->cm); + } + + return ret; +} + +/* Unload Intermediate CAs from the certificate manager of the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx or ctx->cm is NULL. + * @return BAD_MUTEX_E when locking fails. + */ +int wolfSSL_CTX_UnloadIntermediateCerts(WOLFSSL_CTX* ctx) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_UnloadIntermediateCerts"); + + /* Validate parameter. */ + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + /* Lock reference count. */ + else if ((ret = wolfSSL_RefWithMutexLock(&ctx->ref)) == 0) { + /* Must not have another reference for this operation to be done. */ + if (ctx->ref.count > 1) { + WOLFSSL_MSG("ctx object must have a ref count of 1 before " + "unloading intermediate certs"); + ret = BAD_STATE_E; + } + else { + ret = wolfSSL_CertManagerUnloadIntermediateCerts(ctx->cm); + } + + /* Unlock reference count. */ + if (wolfSSL_RefWithMutexUnlock(&ctx->ref) != 0) { + WOLFSSL_MSG("Failed to unlock mutex!"); + } + } + + return ret; +} + + +#ifdef WOLFSSL_TRUST_PEER_CERT +/* Unload trusted peers from the certificate manager of the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx or ctx->cm is NULL. + * @return BAD_MUTEX_E when locking fails. + */ +int wolfSSL_CTX_Unload_trust_peers(WOLFSSL_CTX* ctx) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_Unload_trust_peers"); + + /* Validate parameter. */ + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = wolfSSL_CertManagerUnload_trust_peers(ctx->cm); + } + + return ret; +} + +#ifdef WOLFSSL_LOCAL_X509_STORE +/* Unload trusted peers from the certificate manager of the SSL/TLS object. + * + * @param [in] ctx SSL/TLS context. + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl is NULL. + * @return BAD_MUTEX_E when locking fails. + */ +int wolfSSL_Unload_trust_peers(WOLFSSL* ssl) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_Unload_trust_peers"); + + /* Validate parameter. */ + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + else { + /* Output message when certificate manager for object. */ + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerUnload_trust_peers(SSL_CM(ssl)); + } + + return ret; +} +#endif /* WOLFSSL_LOCAL_X509_STORE */ +#endif /* WOLFSSL_TRUST_PEER_CERT */ + +#ifndef WOLFSSL_NO_CA_NAMES +/* Add a CA certificate to the list of CA names. + * + * @param [in, out] ca_names List of CA certificate subject names. + * @param [in] x509 X509 certificate. + * @return 1 on success. + * @return 0 on failure. + */ +static int add_to_ca_names_list(WOLFSSL_STACK* ca_names, WOLFSSL_X509* x509) +{ + int ret = 1; + WOLFSSL_X509_NAME *nameCopy = NULL; + + nameCopy = wolfSSL_X509_NAME_dup(wolfSSL_X509_get_subject_name(x509)); + if (nameCopy == NULL) { + WOLFSSL_MSG("wolfSSL_X509_NAME_dup error"); + ret = 0; + } + else if (wolfSSL_sk_X509_NAME_push(ca_names, nameCopy) <= 0) { + WOLFSSL_MSG("wolfSSL_sk_X509_NAME_push error"); + wolfSSL_X509_NAME_free(nameCopy); + ret = 0; + } + + return ret; +} + +/* Add a client's CA to SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] x509 X509 certificate. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_add_client_CA(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_CTX_add_client_CA"); + + /* Validate parameters. */ + if ((ctx == NULL) || (x509 == NULL)) { + WOLFSSL_MSG("Bad argument"); + ret = 0; + } + /* Create a stack of names if not present. */ + else if (ctx->client_ca_names == NULL) { + ctx->client_ca_names = wolfSSL_sk_X509_NAME_new(NULL); + if (ctx->client_ca_names == NULL) { + WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); + ret = 0; + } + } + if (ret == 1) { + /* Add certificate's subject name to client CA name list. */ + ret = add_to_ca_names_list(ctx->client_ca_names, x509); + } + + return ret; +} + +/* Add a client's CA to SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] x509 X509 certificate. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_add_client_CA(WOLFSSL* ssl, WOLFSSL_X509* x509) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_add_client_CA"); + + /* Validate parameters. */ + if ((ssl == NULL) || (x509 == NULL)) { + WOLFSSL_MSG("Bad argument"); + ret = 0; + } + /* Create a stack of names if not present. */ + else if (ssl->client_ca_names == NULL) { + ssl->client_ca_names = wolfSSL_sk_X509_NAME_new(NULL); + if (ssl->client_ca_names == NULL) { + WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); + ret = 0; + } + } + if (ret == 1) { + /* Add certificate's subject name to client CA name list. */ + ret = add_to_ca_names_list(ssl->client_ca_names, x509); + } + + return ret; +} + +/* Add a CA to SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] x509 X509 certificate. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_CTX_add1_to_CA_list(WOLFSSL_CTX* ctx, WOLFSSL_X509* x509) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_CTX_add1_to_CA_list"); + + /* Validate parameters. */ + if ((ctx == NULL) || (x509 == NULL)) { + WOLFSSL_MSG("Bad argument"); + ret = 0; + } + /* Create a stack of names if not present. */ + else if (ctx->ca_names == NULL) { + ctx->ca_names = wolfSSL_sk_X509_NAME_new(NULL); + if (ctx->ca_names == NULL) { + WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); + ret = 0; + } + } + if (ret == 1) { + /* Add certificate's subject name to CA name list. */ + ret = add_to_ca_names_list(ctx->ca_names, x509); + } + + return ret; +} + +/* Add a CA to SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] x509 X509 certificate. + * @return 1 on success. + * @return 0 on failure. + */ +int wolfSSL_add1_to_CA_list(WOLFSSL* ssl, WOLFSSL_X509* x509) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_add1_to_CA_list"); + + /* Validate parameters. */ + if ((ssl == NULL) || (x509 == NULL)) { + WOLFSSL_MSG("Bad argument"); + ret = 0; + } + /* Create a stack of names if not present. */ + else if (ssl->ca_names == NULL) { + ssl->ca_names = wolfSSL_sk_X509_NAME_new(NULL); + if (ssl->ca_names == NULL) { + WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); + ret = 0; + } + } + if (ret == 1) { + /* Add certificate's subject name to CA name list. */ + ret = add_to_ca_names_list(ssl->ca_names, x509); + } + + return ret; +} + +/* Set the client CA list into SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] names List of CA subject names. + */ +void wolfSSL_CTX_set_client_CA_list(WOLFSSL_CTX* ctx, + WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_client_CA_list"); + + /* Validate parameters. */ + if (ctx != NULL) { + /* Dispose of any existing list. */ + wolfSSL_sk_X509_NAME_pop_free(ctx->client_ca_names, NULL); + /* Take ownership of names list. */ + ctx->client_ca_names = names; + } +} + +/* Set the client CA list into SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] names List of CA subject names. + */ +void wolfSSL_set_client_CA_list(WOLFSSL* ssl, + WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) +{ + WOLFSSL_ENTER("wolfSSL_set_client_CA_list"); + + /* Validate parameters. */ + if (ssl != NULL) { + /* Dispose of any existing list if the object owns it. */ + if (ssl->client_ca_names != ssl->ctx->client_ca_names) { + wolfSSL_sk_X509_NAME_pop_free(ssl->client_ca_names, NULL); + } + /* Take ownership of names list. */ + ssl->client_ca_names = names; + } +} + +/* Set the CA list into SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] names List of CA subject names. + */ +void wolfSSL_CTX_set0_CA_list(WOLFSSL_CTX* ctx, + WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set0_CA_list"); + + /* Validate parameters. */ + if (ctx != NULL) { + /* Dispose of any existing list. */ + wolfSSL_sk_X509_NAME_pop_free(ctx->ca_names, NULL); + /* Take ownership of names list. */ + ctx->ca_names = names; + } +} + +/* Set the client CA list into SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] names List of CA subject names. + */ +void wolfSSL_set0_CA_list(WOLFSSL* ssl, + WOLF_STACK_OF(WOLFSSL_X509_NAME)* names) +{ + WOLFSSL_ENTER("wolfSSL_set0_CA_list"); + + /* Validate parameters. */ + if (ssl != NULL) { + /* Dispose of any existing list if the object owns it. */ + if (ssl->ca_names != ssl->ctx->ca_names) { + wolfSSL_sk_X509_NAME_pop_free(ssl->ca_names, NULL); + } + /* Take ownership of names list. */ + ssl->ca_names = names; + } +} + +/* Get the list of client CA subject names from the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return List of CA subject names on success. + * @return NULL when ctx is NULL or no names set. + */ +WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_CTX_get_client_CA_list( + const WOLFSSL_CTX *ctx) +{ + WOLF_STACK_OF(WOLFSSL_X509_NAME)* ret; + + WOLFSSL_ENTER("wolfSSL_CTX_get_client_CA_list"); + + /* Validate parameter. */ + if (ctx == NULL) { + WOLFSSL_MSG("Bad argument passed to wolfSSL_CTX_get_client_CA_list"); + ret = NULL; + } + else { + ret = ctx->client_ca_names; + } + + return ret; +} + +/* Get the list of client CA subject names from the SSL/TLS object. + * + * On server side: returns the CAs set via *_set_client_CA_list(); + * On client side: returns the CAs received from server -- same as + * wolfSSL_get0_peer_CA_list(). + * + * @param [in] ssl SSL/TLS object. + * @return List of CA subject names on success. + * @return NULL when ssl is NULL or no names set. + */ +WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_get_client_CA_list(const WOLFSSL* ssl) +{ + WOLF_STACK_OF(WOLFSSL_X509_NAME)* ret; + + WOLFSSL_ENTER("wolfSSL_get_client_CA_list"); + + /* Validate parameter. */ + if (ssl == NULL) { + WOLFSSL_MSG("Bad argument passed to wolfSSL_get_client_CA_list"); + ret = NULL; + } + /* Client side return peer CA names. */ + else if (ssl->options.side == WOLFSSL_CLIENT_END) { + ret = ssl->peer_ca_names; + } + /* Server side return client CA names. */ + else { + ret = SSL_CLIENT_CA_NAMES(ssl); + } + + return ret; +} + +/* Get the list of CA subject names from the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return List of CA subject names on success. + * @return NULL when ctx is NULL or no names set. + */ +WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_CTX_get0_CA_list( + const WOLFSSL_CTX *ctx) +{ + WOLF_STACK_OF(WOLFSSL_X509_NAME)* ret; + + WOLFSSL_ENTER("wolfSSL_CTX_get0_CA_list"); + + /* Validate parameter. */ + if (ctx == NULL) { + WOLFSSL_MSG("Bad argument passed to wolfSSL_CTX_get0_CA_list"); + ret = NULL; + } + else { + /* Return list directly. */ + ret = ctx->ca_names; + } + + return ret; +} + +/* Get the list of CA subject names from the SSL/TLS object. + * + * Always returns the CA's set via *_set0_CA_list. + * + * @param [in] ssl SSL/TLS object. + * @return List of CA subject names on success. + * @return NULL when ssl is NULL or no names set. + */ +WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_get0_CA_list(const WOLFSSL *ssl) +{ + WOLF_STACK_OF(WOLFSSL_X509_NAME)* ret; + + WOLFSSL_ENTER("wolfSSL_get0_CA_list"); + + /* Validate parameter. */ + if (ssl == NULL) { + WOLFSSL_MSG("Bad argument passed to wolfSSL_get0_CA_list"); + ret = NULL; + } + else { + /* Return list directly from object, if available, or context. */ + ret = SSL_CA_NAMES(ssl); + } + + return ret; +} + +/* Get the list of peer CA subject names from the SSL/TLS object. + * + * Always returns the CA's received from the peer. + * + * @param [in] ssl SSL/TLS object. + * @return List of CA subject names on success. + * @return NULL when ssl is NULL or no names set. + */ +WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_get0_peer_CA_list(const WOLFSSL* ssl) +{ + WOLF_STACK_OF(WOLFSSL_X509_NAME)* ret; + + WOLFSSL_ENTER("wolfSSL_get0_peer_CA_list"); + + /* Validate parameter. */ + if (ssl == NULL) { + WOLFSSL_MSG("Bad argument passed to wolfSSL_get0_peer_CA_list"); + ret = NULL; + } + else { + /* Return list directly from object. */ + ret = ssl->peer_ca_names; + } + + return ret; +} + +#ifndef NO_BIO +/* Load the client CA subject names from file. + * + * @param [in] fname Name of file containing client CA certificates. + * @return A list of certificate names on success. + * @return NULL on error. + */ +WOLF_STACK_OF(WOLFSSL_X509_NAME)* wolfSSL_load_client_CA_file(const char* fname) +{ + /* The webserver build is using this to load a CA into the server + * for client authentication as an option. Have this return NULL in + * that case. If OPENSSL_EXTRA is enabled, go ahead and include + * the function. */ +#ifdef OPENSSL_EXTRA + WOLFSSL_STACK *list = NULL; + WOLFSSL_BIO* bio = NULL; + WOLFSSL_X509 *cert = NULL; + int err = 0; + unsigned long error; + + WOLFSSL_ENTER("wolfSSL_load_client_CA_file"); + + /* Create a file BIO to read. */ + bio = wolfSSL_BIO_new_file(fname, "rb"); + if (bio == NULL) { + WOLFSSL_MSG("wolfSSL_BIO_new_file error"); + err = 1; + } + + if (!err) { + /* Create an empty list of certificate names - default compare cb. */ + list = wolfSSL_sk_X509_NAME_new(NULL); + if (list == NULL) { + WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); + err = 1; + } + } + + /* Read each certificate in the chain out of the file. */ + while (!err && wolfSSL_PEM_read_bio_X509(bio, &cert, NULL, NULL) != NULL) { + WOLFSSL_X509_NAME *nameCopy; + + /* Need a persistent copy of the subject name. */ + nameCopy = wolfSSL_X509_NAME_dup(wolfSSL_X509_get_subject_name(cert)); + if (nameCopy == NULL) { + WOLFSSL_MSG("wolfSSL_X509_NAME_dup error"); + err = 1; + } + else { + /* Original certificate will be freed - clear reference to it. */ + nameCopy->x509 = NULL; + + if (wolfSSL_sk_X509_NAME_push(list, nameCopy) <= 0) { + WOLFSSL_MSG("wolfSSL_sk_X509_NAME_push error"); + /* Name not stored - free now as only place needing to. */ + wolfSSL_X509_NAME_free(nameCopy); + err = 1; + } + } + + /* Dispose of certificate read. */ + wolfSSL_X509_free(cert); + cert = NULL; + } + + /* Clear any error due to no more certificates. */ + CLEAR_ASN_NO_PEM_HEADER_ERROR(error); + + if (err) { + /* Error occurred so return NULL. */ + wolfSSL_sk_X509_NAME_pop_free(list, NULL); + list = NULL; + } + wolfSSL_BIO_free(bio); + return list; +#else + (void)fname; + return NULL; +#endif +} +#endif /* !NO_BIO */ +#endif /* WOLFSSL_NO_CA_NAMES */ + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +/* Get the certificate store of the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return X509 certificate store on success. + * @return NULL when ctx is NULL. + */ +WOLFSSL_X509_STORE* wolfSSL_CTX_get_cert_store(const WOLFSSL_CTX* ctx) +{ + WOLFSSL_X509_STORE* ret; + + /* Validate parameter. */ + if (ctx == NULL) { + ret = NULL; + } + /* Use pointer to external store if set. */ + else if (ctx->x509_store_pt != NULL) { + ret = ctx->x509_store_pt; + } + else { + /* Return reference to store that is part of the context. */ + ret = (WOLFSSL_X509_STORE*)&ctx->x509_store; + } + + return ret; +} + +/* Set the certificate store of the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return X509 certificate store on success. + * @return NULL when ctx is NULL. + */ +void wolfSSL_CTX_set_cert_store(WOLFSSL_CTX* ctx, WOLFSSL_X509_STORE* str) +{ + WOLFSSL_ENTER("wolfSSL_CTX_set_cert_store"); + + /* Validate parameters. */ + if ((ctx == NULL) || (str == NULL) || (ctx->cm == str->cm)) { + WOLFSSL_MSG("Invalid parameters"); + } + else if (wolfSSL_CertManager_up_ref(str->cm) != 1) { + WOLFSSL_MSG("wolfSSL_CertManager_up_ref error"); + } + else { + /* Free any cert manager. */ + wolfSSL_CertManagerFree(ctx->cm); + /* Free any external store. */ + wolfSSL_X509_STORE_free(ctx->x509_store_pt); + /* Set the certificate manager into context. */ + ctx->cm = str->cm; + ctx->x509_store.cm = str->cm; + ctx->x509_store.cache = str->cache; + /* Take ownership of store and free it with context free. */ + ctx->x509_store_pt = str; + /* Context has ownership and free it with context free. */ + ctx->cm->x509_store_p = ctx->x509_store_pt; + } +} + +#ifdef OPENSSL_ALL +/* Set certificate store into SSL/TLS context but don't take ownership. + * + * @param [in] ctx SSL/TLS context. + * @param [in] str Certificate store. + * @return 1 on success. + * @return 0 when ctx or str is NULL or on other error. + */ +int wolfSSL_CTX_set1_verify_cert_store(WOLFSSL_CTX* ctx, + WOLFSSL_X509_STORE* str) +{ + int ret; + + WOLFSSL_ENTER("wolfSSL_CTX_set1_verify_cert_store"); + + /* Validate parameters. */ + if ((ctx == NULL) || (str == NULL)) { + WOLFSSL_MSG("Bad parameter"); + ret = 0; + } + /* Nothing to do when store being set is the same as existing in context. */ + else if (str == CTX_STORE(ctx)) { + ret = 1; + } + /* Increase ref so we can store pointer and free it with context free. */ + else if (wolfSSL_X509_STORE_up_ref(str) != 1) { + WOLFSSL_MSG("wolfSSL_X509_STORE_up_ref error"); + ret = 0; + } + else { + /* Free any external store. */ + wolfSSL_X509_STORE_free(ctx->x509_store_pt); + /* Ref count increased - store pointer and free with context free. */ + ctx->x509_store_pt = str; + ret = 1; + } + + return ret; +} +#endif + + +/* Set certificate store into SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] str Certificate store. + * @param [in] ref Take a reference to passed in certificate store. + * @return 1 on success. + * @return 0 when ssl or str is NULL or on other error. + */ +static int wolfssl_set_verify_cert_store(WOLFSSL *ssl, WOLFSSL_X509_STORE* str, + int ref) +{ + int ret; + + WOLFSSL_ENTER("wolfssl_set_verify_cert_store"); + + /* Validate parameters. */ + if ((ssl == NULL) || (str == NULL)) { + WOLFSSL_MSG("Bad parameter"); + ret = 0; + } + /* Nothing to do when store being set is the same as existing in object. */ + else if (str == SSL_STORE(ssl)) { + ret = 1; + } + else if (ref && (wolfSSL_X509_STORE_up_ref(str) != 1)) { + WOLFSSL_MSG("wolfSSL_X509_STORE_up_ref error"); + ret = 0; + } + else { + /* Free any external store. */ + wolfSSL_X509_STORE_free(ssl->x509_store_pt); + if (str == ssl->ctx->x509_store_pt) { + /* Setting ctx store - just revert to using that instead. */ + ssl->x509_store_pt = NULL; + } + else { + /* Ref count increased - store pointer and free with object free. */ + ssl->x509_store_pt = str; + } + ret = 1; + } + + return ret; +} + +/* Set certificate store into SSL/TLS object and take ownership. + * + * @param [in] ssl SSL/TLS object. + * @param [in] str Certificate store. + * @return 1 on success. + * @return 0 when ssl or str is NULL or on other error. + */ +int wolfSSL_set0_verify_cert_store(WOLFSSL *ssl, WOLFSSL_X509_STORE* str) +{ + WOLFSSL_ENTER("wolfSSL_set0_verify_cert_store"); + + return wolfssl_set_verify_cert_store(ssl, str, 0); +} + +/* Set certificate store into SSL/TLS object but don't take ownership. + * + * @param [in] ssl SSL/TLS object. + * @param [in] str Certificate store. + * @return 1 on success. + * @return 0 when ssl or str is NULL or on other error. + */ +int wolfSSL_set1_verify_cert_store(WOLFSSL *ssl, WOLFSSL_X509_STORE* str) +{ + WOLFSSL_ENTER("wolfSSL_set1_verify_cert_store"); + + return wolfssl_set_verify_cert_store(ssl, str, 1); +} +#endif /* OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL */ + +/* OPENSSL_EXTRA is needed for wolfSSL_X509_d21 function + KEEP_OUR_CERT is to ensure ability to return ssl certificate */ +#if (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ + defined(KEEP_OUR_CERT) +/* Get the certificate in the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return Certificate being sent to peer. + * @return NULL when ctx is NULL, no certificate set or on other error. + */ +WOLFSSL_X509* wolfSSL_CTX_get0_certificate(WOLFSSL_CTX* ctx) +{ + WOLFSSL_X509* ret = NULL; + + /* Validate parameters. */ + if (ctx == NULL) { + WOLFSSL_MSG("Invalid parameter"); + } + else { + /* Check if we already have a certificate allocated. */ + if (ctx->ourCert == NULL) { + /* Check if there is a raw certificate. */ + if (ctx->certificate == NULL) { + WOLFSSL_MSG("Ctx Certificate buffer not set!"); + } + #ifndef WOLFSSL_X509_STORE_CERTS + else { + /* Create a certificate object from raw data. */ + ctx->ourCert = wolfSSL_X509_d2i_ex(NULL, + ctx->certificate->buffer, (int)ctx->certificate->length, + ctx->heap); + ctx->ownOurCert = 1; + } + #endif + } + /* Return certificate cached against SSL/TLS context. */ + ret = ctx->ourCert; + } + + return ret; +} + +/* Get the certificate in the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Certificate being sent to peer. + * @return NULL when ssl is NULL, no certificate set or on other error. + */ +WOLFSSL_X509* wolfSSL_get_certificate(WOLFSSL* ssl) +{ + WOLFSSL_X509* ret = NULL; + + /* Validate parameters. */ + if (ssl == NULL) { + WOLFSSL_MSG("Invalid parameter"); + } + /* Use certificate in SSL/TLS object if we own it. */ + else if (ssl->buffers.weOwnCert) { + /* Check if we already have a certificate allocated. */ + if (ssl->ourCert == NULL) { + /* We own certificate so this should never happen. */ + if (ssl->buffers.certificate == NULL) { + WOLFSSL_MSG("Certificate buffer not set!"); + } + #ifndef WOLFSSL_X509_STORE_CERTS + else { + /* Create a certificate object from raw data. */ + ssl->ourCert = wolfSSL_X509_d2i_ex(NULL, + ssl->buffers.certificate->buffer, + (int)ssl->buffers.certificate->length, ssl->heap); + } + #endif + } + /* Return certificate cached against SSL/TLS object. */ + ret = ssl->ourCert; + } + else { + /* Use any certificate in SSL/TLS context instead. */ + ret = wolfSSL_CTX_get0_certificate(ssl->ctx); + } + + return ret; +} +#endif /* (OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL) && KEEP_OUR_CERT */ + +#endif /* !NO_CERTS */ + +#endif /* !WOLFSSL_SSL_API_CERT_INCLUDED */ diff --git a/src/ssl_api_crl_ocsp.c b/src/ssl_api_crl_ocsp.c new file mode 100644 index 0000000000..b0791dc6a9 --- /dev/null +++ b/src/ssl_api_crl_ocsp.c @@ -0,0 +1,634 @@ +/* ssl_api_crl_ocsp.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 + +#if !defined(WOLFSSL_SSL_API_CRL_OCSP_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_api_crl_ocsp.c is not compiled separately from ssl.c + #endif +#else + +#ifndef NO_CERTS + +#ifdef HAVE_CRL + +int wolfSSL_CTX_LoadCRLBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, + long sz, int type) +{ + WOLFSSL_ENTER("wolfSSL_CTX_LoadCRLBuffer"); + + if (ctx == NULL) + return BAD_FUNC_ARG; + + return wolfSSL_CertManagerLoadCRLBuffer(ctx->cm, buff, sz, type); +} + + +int wolfSSL_LoadCRLBuffer(WOLFSSL* ssl, const unsigned char* buff, + long sz, int type) +{ + WOLFSSL_ENTER("wolfSSL_LoadCRLBuffer"); + + if (ssl == NULL || ssl->ctx == NULL) + return BAD_FUNC_ARG; + + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerLoadCRLBuffer(SSL_CM(ssl), buff, sz, type); +} + +int wolfSSL_EnableCRL(WOLFSSL* ssl, int options) +{ + WOLFSSL_ENTER("wolfSSL_EnableCRL"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerEnableCRL(SSL_CM(ssl), options); + } + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_DisableCRL(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_DisableCRL"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerDisableCRL(SSL_CM(ssl)); + } + else + return BAD_FUNC_ARG; +} + +#ifndef NO_FILESYSTEM +int wolfSSL_LoadCRL(WOLFSSL* ssl, const char* path, int type, int monitor) +{ + WOLFSSL_ENTER("wolfSSL_LoadCRL"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerLoadCRL(SSL_CM(ssl), path, type, monitor); + } + else + return BAD_FUNC_ARG; +} + +int wolfSSL_LoadCRLFile(WOLFSSL* ssl, const char* file, int type) +{ + WOLFSSL_ENTER("wolfSSL_LoadCRLFile"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerLoadCRLFile(SSL_CM(ssl), file, type); + } + else + return BAD_FUNC_ARG; +} +#endif + +int wolfSSL_SetCRL_Cb(WOLFSSL* ssl, CbMissingCRL cb) +{ + WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerSetCRL_Cb(SSL_CM(ssl), cb); + } + else + return BAD_FUNC_ARG; +} + +int wolfSSL_SetCRL_ErrorCb(WOLFSSL* ssl, crlErrorCb cb, void* ctx) +{ + WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerSetCRL_ErrorCb(SSL_CM(ssl), cb, ctx); + } + else + return BAD_FUNC_ARG; +} + +#ifdef HAVE_CRL_IO +int wolfSSL_SetCRL_IOCb(WOLFSSL* ssl, CbCrlIO cb) +{ + WOLFSSL_ENTER("wolfSSL_SetCRL_Cb"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerSetCRL_IOCb(SSL_CM(ssl), cb); + } + else + return BAD_FUNC_ARG; +} +#endif + +int wolfSSL_CTX_EnableCRL(WOLFSSL_CTX* ctx, int options) +{ + WOLFSSL_ENTER("wolfSSL_CTX_EnableCRL"); + if (ctx) + return wolfSSL_CertManagerEnableCRL(ctx->cm, options); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_CTX_DisableCRL(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_DisableCRL"); + if (ctx) + return wolfSSL_CertManagerDisableCRL(ctx->cm); + else + return BAD_FUNC_ARG; +} + + +#ifndef NO_FILESYSTEM +int wolfSSL_CTX_LoadCRL(WOLFSSL_CTX* ctx, const char* path, + int type, int monitor) +{ + WOLFSSL_ENTER("wolfSSL_CTX_LoadCRL"); + if (ctx) + return wolfSSL_CertManagerLoadCRL(ctx->cm, path, type, monitor); + else + return BAD_FUNC_ARG; +} + +int wolfSSL_CTX_LoadCRLFile(WOLFSSL_CTX* ctx, const char* file, + int type) +{ + WOLFSSL_ENTER("wolfSSL_CTX_LoadCRL"); + if (ctx) + return wolfSSL_CertManagerLoadCRLFile(ctx->cm, file, type); + else + return BAD_FUNC_ARG; +} +#endif + + +int wolfSSL_CTX_SetCRL_Cb(WOLFSSL_CTX* ctx, CbMissingCRL cb) +{ + WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_Cb"); + if (ctx) + return wolfSSL_CertManagerSetCRL_Cb(ctx->cm, cb); + else + return BAD_FUNC_ARG; +} + +int wolfSSL_CTX_SetCRL_ErrorCb(WOLFSSL_CTX* ctx, crlErrorCb cb, void* cbCtx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_ErrorCb"); + if (ctx) + return wolfSSL_CertManagerSetCRL_ErrorCb(ctx->cm, cb, cbCtx); + else + return BAD_FUNC_ARG; +} + +#ifdef HAVE_CRL_IO +int wolfSSL_CTX_SetCRL_IOCb(WOLFSSL_CTX* ctx, CbCrlIO cb) +{ + WOLFSSL_ENTER("wolfSSL_CTX_SetCRL_IOCb"); + if (ctx) + return wolfSSL_CertManagerSetCRL_IOCb(ctx->cm, cb); + else + return BAD_FUNC_ARG; +} +#endif + +#endif /* HAVE_CRL */ + + +#ifdef HAVE_OCSP +int wolfSSL_EnableOCSP(WOLFSSL* ssl, int options) +{ + WOLFSSL_ENTER("wolfSSL_EnableOCSP"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerEnableOCSP(SSL_CM(ssl), options); + } + else + return BAD_FUNC_ARG; +} + +int wolfSSL_DisableOCSP(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_DisableOCSP"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerDisableOCSP(SSL_CM(ssl)); + } + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_EnableOCSPStapling(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_EnableOCSPStapling"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerEnableOCSPStapling(SSL_CM(ssl)); + } + else + return BAD_FUNC_ARG; +} + +int wolfSSL_DisableOCSPStapling(WOLFSSL* ssl) +{ + WOLFSSL_ENTER("wolfSSL_DisableOCSPStapling"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerDisableOCSPStapling(SSL_CM(ssl)); + } + else + return BAD_FUNC_ARG; +} +int wolfSSL_SetOCSP_OverrideURL(WOLFSSL* ssl, const char* url) +{ + WOLFSSL_ENTER("wolfSSL_SetOCSP_OverrideURL"); + if (ssl) { + SSL_CM_WARNING(ssl); + return wolfSSL_CertManagerSetOCSPOverrideURL(SSL_CM(ssl), url); + } + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_SetOCSP_Cb(WOLFSSL* ssl, + CbOCSPIO ioCb, CbOCSPRespFree respFreeCb, void* ioCbCtx) +{ + WOLFSSL_ENTER("wolfSSL_SetOCSP_Cb"); + if (ssl) { + SSL_CM_WARNING(ssl); + ssl->ocspIOCtx = ioCbCtx; /* use SSL specific ioCbCtx */ + return wolfSSL_CertManagerSetOCSP_Cb(SSL_CM(ssl), + ioCb, respFreeCb, NULL); + } + else + return BAD_FUNC_ARG; +} + +int wolfSSL_CTX_EnableOCSP(WOLFSSL_CTX* ctx, int options) +{ + WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSP"); + if (ctx) + return wolfSSL_CertManagerEnableOCSP(ctx->cm, options); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_CTX_DisableOCSP(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSP"); + if (ctx) + return wolfSSL_CertManagerDisableOCSP(ctx->cm); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_CTX_SetOCSP_OverrideURL(WOLFSSL_CTX* ctx, const char* url) +{ + WOLFSSL_ENTER("wolfSSL_SetOCSP_OverrideURL"); + if (ctx) + return wolfSSL_CertManagerSetOCSPOverrideURL(ctx->cm, url); + else + return BAD_FUNC_ARG; +} + + +int wolfSSL_CTX_SetOCSP_Cb(WOLFSSL_CTX* ctx, CbOCSPIO ioCb, + CbOCSPRespFree respFreeCb, void* ioCbCtx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_SetOCSP_Cb"); + if (ctx) + return wolfSSL_CertManagerSetOCSP_Cb(ctx->cm, ioCb, + respFreeCb, ioCbCtx); + else + return BAD_FUNC_ARG; +} + +#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) +int wolfSSL_CTX_EnableOCSPStapling(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSPStapling"); + if (ctx) + return wolfSSL_CertManagerEnableOCSPStapling(ctx->cm); + else + return BAD_FUNC_ARG; +} + +int wolfSSL_CTX_DisableOCSPStapling(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSPStapling"); + if (ctx) + return wolfSSL_CertManagerDisableOCSPStapling(ctx->cm); + else + return BAD_FUNC_ARG; +} +int wolfSSL_CTX_EnableOCSPMustStaple(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_EnableOCSPMustStaple"); + if (ctx) + return wolfSSL_CertManagerEnableOCSPMustStaple(ctx->cm); + else + return BAD_FUNC_ARG; +} + +int wolfSSL_CTX_DisableOCSPMustStaple(WOLFSSL_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_CTX_DisableOCSPMustStaple"); + if (ctx) + return wolfSSL_CertManagerDisableOCSPMustStaple(ctx->cm); + else + return BAD_FUNC_ARG; +} +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST || \ + * HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) +/* Not an OpenSSL API. */ +int wolfSSL_get_ocsp_response(WOLFSSL* ssl, byte** response) +{ + *response = ssl->ocspCsrResp[0].buffer; + return ssl->ocspCsrResp[0].length; +} + +/* Not an OpenSSL API. */ +char* wolfSSL_get_ocsp_url(WOLFSSL* ssl) +{ + return ssl->url; +} + +/* Not an OpenSSL API. */ +int wolfSSL_set_ocsp_url(WOLFSSL* ssl, char* url) +{ + if (ssl == NULL) + return WOLFSSL_FAILURE; + + ssl->url = url; + return WOLFSSL_SUCCESS; +} +#endif /* OPENSSL_ALL || WOLFSSL_NGINX || WOLFSSL_HAPROXY */ + +#if !defined(NO_ASN_TIME) +int wolfSSL_get_ocsp_producedDate( + WOLFSSL *ssl, + byte *producedDate, + size_t producedDate_space, + int *producedDateFormat) +{ + if ((ssl->ocspProducedDateFormat != ASN_UTC_TIME) && + (ssl->ocspProducedDateFormat != ASN_GENERALIZED_TIME)) + return BAD_FUNC_ARG; + + if ((producedDate == NULL) || (producedDateFormat == NULL)) + return BAD_FUNC_ARG; + + if (XSTRLEN((char *)ssl->ocspProducedDate) >= producedDate_space) + return BUFFER_E; + + XSTRNCPY((char *)producedDate, (const char *)ssl->ocspProducedDate, + producedDate_space); + *producedDateFormat = ssl->ocspProducedDateFormat; + + return 0; +} + +int wolfSSL_get_ocsp_producedDate_tm(WOLFSSL *ssl, struct tm *produced_tm) { + int idx = 0; + + if ((ssl->ocspProducedDateFormat != ASN_UTC_TIME) && + (ssl->ocspProducedDateFormat != ASN_GENERALIZED_TIME)) + return BAD_FUNC_ARG; + + if (produced_tm == NULL) + return BAD_FUNC_ARG; + + if (ExtractDate(ssl->ocspProducedDate, + (unsigned char)ssl->ocspProducedDateFormat, produced_tm, &idx, + MAX_DATE_SZ)) + return 0; + else + return ASN_PARSE_E; +} +#endif /* !NO_ASN_TIME */ +#endif /* HAVE_OCSP */ + +#if !defined(NO_TLS) && !defined(NO_WOLFSSL_CLIENT) +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST + +int wolfSSL_UseOCSPStapling(WOLFSSL* ssl, byte status_type, byte options) +{ + WOLFSSL_ENTER("wolfSSL_UseOCSPStapling"); + + if (ssl == NULL || ssl->options.side != WOLFSSL_CLIENT_END) + return BAD_FUNC_ARG; + + return TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type, + options, NULL, ssl->heap, ssl->devId); +} + + +int wolfSSL_CTX_UseOCSPStapling(WOLFSSL_CTX* ctx, byte status_type, + byte options) +{ + WOLFSSL_ENTER("wolfSSL_CTX_UseOCSPStapling"); + + if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END) + return BAD_FUNC_ARG; + + return TLSX_UseCertificateStatusRequest(&ctx->extensions, status_type, + options, NULL, ctx->heap, ctx->devId); +} + +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ + +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 + +int wolfSSL_UseOCSPStaplingV2(WOLFSSL* ssl, byte status_type, byte options) +{ + if (ssl == NULL || ssl->options.side != WOLFSSL_CLIENT_END) + return BAD_FUNC_ARG; + + return TLSX_UseCertificateStatusRequestV2(&ssl->extensions, status_type, + options, ssl->heap, ssl->devId); +} + + +int wolfSSL_CTX_UseOCSPStaplingV2(WOLFSSL_CTX* ctx, byte status_type, + byte options) +{ + if (ctx == NULL || ctx->method->side != WOLFSSL_CLIENT_END) + return BAD_FUNC_ARG; + + return TLSX_UseCertificateStatusRequestV2(&ctx->extensions, status_type, + options, ctx->heap, ctx->devId); +} + +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ +#endif /* !NO_TLS && !NO_WOLFSSL_CLIENT */ + +#ifdef OPENSSL_EXTRA +#ifdef HAVE_CERTIFICATE_STATUS_REQUEST +long wolfSSL_set_tlsext_status_type(WOLFSSL *s, int type) +{ + WOLFSSL_ENTER("wolfSSL_set_tlsext_status_type"); + + if (s == NULL){ + return BAD_FUNC_ARG; + } + + if (type == WOLFSSL_TLSEXT_STATUSTYPE_ocsp){ + int r = TLSX_UseCertificateStatusRequest(&s->extensions, (byte)type, 0, + s, s->heap, s->devId); + return (long)r; + } else { + WOLFSSL_MSG( + "SSL_set_tlsext_status_type only supports TLSEXT_STATUSTYPE_ocsp type."); + return WOLFSSL_FAILURE; + } + +} + +long wolfSSL_get_tlsext_status_type(WOLFSSL *s) +{ + TLSX* extension; + + if (s == NULL) + return WOLFSSL_FATAL_ERROR; + extension = TLSX_Find(s->extensions, TLSX_STATUS_REQUEST); + return (extension != NULL) ? WOLFSSL_TLSEXT_STATUSTYPE_ocsp : + WOLFSSL_FATAL_ERROR; +} +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */ +#endif /* OPENSSL_EXTRA */ + +#if defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \ + defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) +int wolfSSL_CTX_get_tlsext_status_cb(WOLFSSL_CTX* ctx, tlsextStatusCb* cb) +{ + if (ctx == NULL || ctx->cm == NULL || cb == NULL) + return WOLFSSL_FAILURE; + +#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) + if (ctx->cm->ocsp_stapling == NULL) + return WOLFSSL_FAILURE; + + *cb = ctx->cm->ocsp_stapling->statusCb; +#else + (void)cb; + *cb = NULL; +#endif + + return WOLFSSL_SUCCESS; + +} + +int wolfSSL_CTX_set_tlsext_status_cb(WOLFSSL_CTX* ctx, tlsextStatusCb cb) +{ + if (ctx == NULL || ctx->cm == NULL) + return WOLFSSL_FAILURE; + +#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) + /* Ensure stapling is on for callback to be used. */ + wolfSSL_CTX_EnableOCSPStapling(ctx); + + if (ctx->cm->ocsp_stapling == NULL) + return WOLFSSL_FAILURE; + + ctx->cm->ocsp_stapling->statusCb = cb; +#else + (void)cb; +#endif + + return WOLFSSL_SUCCESS; +} + +long wolfSSL_CTX_set_tlsext_status_arg(WOLFSSL_CTX* ctx, void* arg) +{ + if (ctx == NULL || ctx->cm == NULL) + return WOLFSSL_FAILURE; + +#if !defined(NO_WOLFSSL_SERVER) && (defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) + /* Ensure stapling is on for callback to be used. */ + wolfSSL_CTX_EnableOCSPStapling(ctx); + + if (ctx->cm->ocsp_stapling == NULL) + return WOLFSSL_FAILURE; + + ctx->cm->ocsp_stapling->statusCbArg = arg; +#else + (void)arg; +#endif + + return WOLFSSL_SUCCESS; +} + +long wolfSSL_get_tlsext_status_ocsp_resp(WOLFSSL *ssl, unsigned char **resp) +{ + if (ssl == NULL || resp == NULL) + return 0; + + *resp = ssl->ocspCsrResp[0].buffer; + return (long)ssl->ocspCsrResp[0].length; +} + +long wolfSSL_set_tlsext_status_ocsp_resp(WOLFSSL *ssl, unsigned char *resp, + int len) +{ + return wolfSSL_set_tlsext_status_ocsp_resp_multi(ssl, resp, len, 0); +} + +int wolfSSL_set_tlsext_status_ocsp_resp_multi(WOLFSSL* ssl, unsigned char *resp, + int len, word32 idx) +{ + if (ssl == NULL || idx >= XELEM_CNT(ssl->ocspCsrResp) || len < 0) + return WOLFSSL_FAILURE; + if (!((resp == NULL) ^ (len > 0))) + return WOLFSSL_FAILURE; + + XFREE(ssl->ocspCsrResp[idx].buffer, NULL, 0); + ssl->ocspCsrResp[idx].buffer = resp; + ssl->ocspCsrResp[idx].length = (word32)len; + + return WOLFSSL_SUCCESS; +} + +#ifndef NO_WOLFSSL_SERVER +void wolfSSL_CTX_set_ocsp_status_verify_cb(WOLFSSL_CTX* ctx, + ocspVerifyStatusCb cb, void* cbArg) +{ + if (ctx != NULL) { + ctx->ocspStatusVerifyCb = cb; + ctx->ocspStatusVerifyCbArg = cbArg; + } +} +#endif /* NO_WOLFSSL_SERVER */ +#endif /* HAVE_CERTIFICATE_STATUS_REQUEST || + * HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ + +#endif /* !NO_CERTS */ + +#endif /* !WOLFSSL_SSL_API_CRL_OCSP_INCLUDED */ + diff --git a/src/ssl_api_pk.c b/src/ssl_api_pk.c new file mode 100644 index 0000000000..92bdd522c1 --- /dev/null +++ b/src/ssl_api_pk.c @@ -0,0 +1,1611 @@ +/* ssl_api_pk.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 + +#if !defined(WOLFSSL_SSL_API_PK_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_api_pk.c is not compiled separately from ssl.c + #endif +#else + +#ifndef NO_CERTS + +#ifndef NO_CHECK_PRIVATE_KEY + +#ifdef WOLF_PRIVATE_KEY_ID +/* Check priv against pub for match using external device with given devId + * + * @param [in] keyOID Public key OID. + * @param [in] privKey Private key data. + * @param [in] privSz Length of private key data in bytes. + * @param [in] pubKey Public key data. + * @param [in] pubSz Length of public key data in bytes. + * @param [in] label Key data is a hardware label. + * @param [in] id Key data is a hardware id. + * @param [in] heap Heap hint for dynamic memory allocation. + * @param [in] devId Device Id. + * @return 0 on success. + * @return MISSING_KEY when privKey is NULL. + * @return Other negative value on error. + */ +static int check_cert_key_dev(word32 keyOID, byte* privKey, word32 privSz, + const byte* pubKey, word32 pubSz, int label, int id, void* heap, int devId) +{ + int ret = 0; + int type; + void *pkey = NULL; + + if (privKey == NULL) { + ret = MISSING_KEY; + } + else { + switch (keyOID) { + #ifndef NO_RSA + case RSAk: + #ifdef WC_RSA_PSS + case RSAPSSk: + #endif + type = DYNAMIC_TYPE_RSA; + break; + #endif + #ifdef HAVE_ECC + case ECDSAk: + type = DYNAMIC_TYPE_ECC; + break; + #endif + #if defined(HAVE_DILITHIUM) + case ML_DSA_LEVEL2k: + case ML_DSA_LEVEL3k: + case ML_DSA_LEVEL5k: + #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT + case DILITHIUM_LEVEL2k: + case DILITHIUM_LEVEL3k: + case DILITHIUM_LEVEL5k: + #endif + type = DYNAMIC_TYPE_DILITHIUM; + break; + #endif + #if defined(HAVE_FALCON) + case FALCON_LEVEL1k: + case FALCON_LEVEL5k: + type = DYNAMIC_TYPE_FALCON; + break; + #endif + default: + type = 0; + } + + ret = CreateDevPrivateKey(&pkey, privKey, privSz, type, label, id, heap, + devId); + } +#ifdef WOLF_CRYPTO_CB + if (ret == 0) { + switch (keyOID) { + #ifndef NO_RSA + case RSAk: + #ifdef WC_RSA_PSS + case RSAPSSk: + #endif + ret = wc_CryptoCb_RsaCheckPrivKey((RsaKey*)pkey, pubKey, pubSz); + break; + #endif + #ifdef HAVE_ECC + case ECDSAk: + ret = wc_CryptoCb_EccCheckPrivKey((ecc_key*)pkey, pubKey, + pubSz); + break; + #endif + #if defined(HAVE_DILITHIUM) + case ML_DSA_LEVEL2k: + case ML_DSA_LEVEL3k: + case ML_DSA_LEVEL5k: + #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT + case DILITHIUM_LEVEL2k: + case DILITHIUM_LEVEL3k: + case DILITHIUM_LEVEL5k: + #endif + ret = wc_CryptoCb_PqcSignatureCheckPrivKey(pkey, + WC_PQC_SIG_TYPE_DILITHIUM, pubKey, pubSz); + break; + #endif + #if defined(HAVE_FALCON) + case FALCON_LEVEL1k: + case FALCON_LEVEL5k: + ret = wc_CryptoCb_PqcSignatureCheckPrivKey(pkey, + WC_PQC_SIG_TYPE_FALCON, pubKey, pubSz); + break; + #endif + default: + ret = 0; + } + } +#else + /* devId was set, don't check, for now */ + /* TODO: Add callback for private key check? */ + (void) pubKey; + (void) pubSz; +#endif + + switch (keyOID) { +#ifndef NO_RSA + case RSAk: + #ifdef WC_RSA_PSS + case RSAPSSk: + #endif + wc_FreeRsaKey((RsaKey*)pkey); + break; +#endif + #ifdef HAVE_ECC + case ECDSAk: + wc_ecc_free((ecc_key*)pkey); + break; + #endif +#if defined(HAVE_DILITHIUM) + case ML_DSA_LEVEL2k: + case ML_DSA_LEVEL3k: + case ML_DSA_LEVEL5k: + #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT + case DILITHIUM_LEVEL2k: + case DILITHIUM_LEVEL3k: + case DILITHIUM_LEVEL5k: + #endif + wc_dilithium_free((dilithium_key*)pkey); + break; +#endif + #if defined(HAVE_FALCON) + case FALCON_LEVEL1k: + case FALCON_LEVEL5k: + wc_falcon_free((falcon_key*)pkey); + break; + #endif + default: + WC_DO_NOTHING; + } + XFREE(pkey, heap, type); + + return ret; +} +#endif /* WOLF_PRIVATE_KEY_ID */ + +/* Check private against public in certificate for match. + * + * @param [in] cert DER encoded certificate. + * @param [in] key DER encoded private key. + * @param [in] altKey Alternative DER encoded key. + * @param [in] heap Heap hint for dynamic memory allocation. + * @param [in] devId Device Id. + * @param [in] isKeyLabel Whether key is label. + * @param [in] isKeyId Whether key is an id. + * @param [in] altDevId Alternative key's device id. + * @param [in] isAltKeyLabel Is alternative key a label. + * @param [in] isAltKeyId Is alternative key an id. + * @return 1 on success. + * @return 0 on failure. + * @return MEMORY_E when memory allocation fails. + */ +static int check_cert_key(const DerBuffer* cert, const DerBuffer* key, + const DerBuffer* altKey, void* heap, int devId, int isKeyLabel, int isKeyId, + int altDevId, int isAltKeyLabel, int isAltKeyId) +{ + WC_DECLARE_VAR(der, DecodedCert, 1, 0); + word32 size; + byte* buff; + int ret = 1; + + WOLFSSL_ENTER("check_cert_key"); + + /* Validate parameters. */ + if ((cert == NULL) || (key == NULL)) { + return 0; + } + if (ret == 1) { + /* Make a decoded certificate object available. */ + WC_ALLOC_VAR_EX(der, DecodedCert, 1, heap, DYNAMIC_TYPE_DCERT, + return MEMORY_E); + } + + if (ret == 1) { + /* Decode certificate. */ + InitDecodedCert_ex(der, cert->buffer, cert->length, heap, devId); + /* Parse certificate. */ + if (ParseCertRelative(der, CERT_TYPE, NO_VERIFY, NULL, NULL) != 0) { + WC_FREE_VAR_EX(der, heap, DYNAMIC_TYPE_DCERT); + ret = 0; + } + } + + if (ret == 1) { + buff = key->buffer; + size = key->length; + #ifdef WOLF_PRIVATE_KEY_ID + if (devId != INVALID_DEVID) { + ret = check_cert_key_dev(der->keyOID, buff, size, der->publicKey, + der->pubKeySize, isKeyLabel, isKeyId, heap, devId); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + ret = (ret == 0) ? WOLFSSL_SUCCESS: WOLFSSL_FAILURE; + } + } + else { + /* fall through if unavailable */ + ret = CRYPTOCB_UNAVAILABLE; + } + + if (ret == WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + #endif /* WOLF_PRIVATE_KEY_ID */ + { + ret = wc_CheckPrivateKeyCert(buff, size, der, 0, heap); + if (ret != 1) { + ret = 0; + } + } + + #ifdef WOLFSSL_DUAL_ALG_CERTS + if ((ret == 1) && der->extSapkiSet && (der->sapkiDer != NULL)) { + /* Certificate contains an alternative public key. Hence, we also + * need an alternative private key. */ + if (altKey == NULL) { + ret = MISSING_KEY; + buff = NULL; + size = 0; + } + else { + size = altKey->length; + buff = altKey->buffer; + } + #ifdef WOLF_PRIVATE_KEY_ID + if (altDevId != INVALID_DEVID) { + /* We have to decode the public key first */ + /* Default to max pub key size. */ + word32 pubKeyLen = MAX_PUBLIC_KEY_SZ; + byte* decodedPubKey = (byte*)XMALLOC(pubKeyLen, heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (decodedPubKey == NULL) { + ret = MEMORY_E; + } + if (ret == WOLFSSL_SUCCESS) { + if ((der->sapkiOID == RSAk) || (der->sapkiOID == ECDSAk)) { + /* Simply copy the data */ + XMEMCPY(decodedPubKey, der->sapkiDer, der->sapkiLen); + pubKeyLen = der->sapkiLen; + ret = 0; + } + else { + #if defined(WC_ENABLE_ASYM_KEY_IMPORT) + word32 idx = 0; + ret = DecodeAsymKeyPublic(der->sapkiDer, &idx, + der->sapkiLen, decodedPubKey, + &pubKeyLen, der->sapkiOID); + #else + ret = NOT_COMPILED_IN; + #endif /* WC_ENABLE_ASYM_KEY_IMPORT */ + } + } + if (ret == 0) { + ret = check_cert_key_dev(der->sapkiOID, buff, size, + decodedPubKey, pubKeyLen, isAltKeyLabel, isAltKeyId, + heap, altDevId); + } + XFREE(decodedPubKey, heap, DYNAMIC_TYPE_PUBLIC_KEY); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + ret = (ret == 0) ? 1: 0; + } + } + else { + /* fall through if unavailable */ + ret = CRYPTOCB_UNAVAILABLE; + } + + if (ret == WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + #else + if (ret == 1) + #endif /* WOLF_PRIVATE_KEY_ID */ + { + ret = wc_CheckPrivateKeyCert(buff, size, der, 1, heap); + if (ret != 1) { + ret = 0; + } + } + } + #endif /* WOLFSSL_DUAL_ALG_CERTS */ + } + + FreeDecodedCert(der); + WC_FREE_VAR_EX(der, heap, DYNAMIC_TYPE_DCERT); + + (void)devId; + (void)isKeyLabel; + (void)isKeyId; + (void)altKey; + (void)altDevId; + (void)isAltKeyLabel; + (void)isAltKeyId; + + return ret; +} + +/* Check private against public in certificate for match + * + * @param [in] ctx SSL/TLS context with a private key and certificate. + * + * @return 1 on good private key + * @return 0 if mismatched. + */ +int wolfSSL_CTX_check_private_key(const WOLFSSL_CTX* ctx) +{ + int res = 1; +#ifdef WOLFSSL_BLIND_PRIVATE_KEY + DerBuffer *privateKey; +#ifdef WOLFSSL_DUAL_ALG_CERTS + DerBuffer *altPrivateKey; +#endif +#else + const DerBuffer *privateKey; +#ifdef WOLFSSL_DUAL_ALG_CERTS + const DerBuffer *altPrivateKey; +#endif +#endif + + /* Validate parameter. */ + if (ctx == NULL) { + res = 0; + } + else { +#ifdef WOLFSSL_DUAL_ALG_CERTS + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Unblind private keys. */ + privateKey = wolfssl_priv_der_unblind(ctx->privateKey, + ctx->privateKeyMask); + if (privateKey == NULL) { + res = 0; + } + if (ctx->altPrivateKey != NULL) { + altPrivateKey = wolfssl_priv_der_unblind(ctx->altPrivateKey, + ctx->altPrivateKeyMask); + if (altPrivateKey == NULL) { + res = 0; + } + } + else { + altPrivateKey = NULL; + } + #else + privateKey = ctx->privateKey; + altPrivateKey = ctx->altPrivateKey; + #endif + if (res == 1) { + /* Check certificate and private keys. */ + res = check_cert_key(ctx->certificate, privateKey, altPrivateKey, + ctx->heap, ctx->privateKeyDevId, ctx->privateKeyLabel, + ctx->privateKeyId, ctx->altPrivateKeyDevId, + ctx->altPrivateKeyLabel, ctx->altPrivateKeyId) != 0; + } + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Dispose of the unblinded buffers. */ + wolfssl_priv_der_unblind_free(privateKey); + wolfssl_priv_der_unblind_free(altPrivateKey); + #endif +#else + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Unblind private key. */ + privateKey = wolfssl_priv_der_unblind(ctx->privateKey, + ctx->privateKeyMask); + if (privateKey == NULL) { + res = 0; + } + #else + privateKey = ctx->privateKey; + #endif + if (res == WOLFSSL_SUCCESS) { + /* Check certificate and private key. */ + res = check_cert_key(ctx->certificate, privateKey, NULL, ctx->heap, + ctx->privateKeyDevId, ctx->privateKeyLabel, ctx->privateKeyId, + INVALID_DEVID, 0, 0); + } + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Dispose of the unblinded buffer. */ + wolfssl_priv_der_unblind_free(privateKey); + #endif +#endif + } + + /* Place error into queue for Python port. */ + if (res != 1) { + WOLFSSL_ERROR(WC_KEY_MISMATCH_E); + } + + return res; +} + +#ifdef OPENSSL_EXTRA +/* Check private against public in certificate for match. + * + * @param [in] ssl SSL/TLS object with a private key and certificate. + * + * @return 1 on good private key + * @return 0 if mismatched. + */ +int wolfSSL_check_private_key(const WOLFSSL* ssl) +{ + int res = 1; +#ifdef WOLFSSL_BLIND_PRIVATE_KEY + DerBuffer *privateKey; +#ifdef WOLFSSL_DUAL_ALG_CERTS + DerBuffer *altPrivateKey; +#endif +#else + const DerBuffer *privateKey; +#ifdef WOLFSSL_DUAL_ALG_CERTS + const DerBuffer *altPrivateKey; +#endif +#endif + + /* Validate parameter. */ + if (ssl == NULL) { + res = 0; + } + else { +#ifdef WOLFSSL_DUAL_ALG_CERTS + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Unblind private keys. */ + privateKey = wolfssl_priv_der_unblind(ssl->buffers.key, + ssl->buffers.keyMask); + if (privateKey == NULL) { + res = 0; + } + if (ssl->buffers.altKey != NULL) { + altPrivateKey = wolfssl_priv_der_unblind(ssl->buffers.altKey, + ssl->buffers.altKeyMask); + if (altPrivateKey == NULL) { + res = 0; + } + } + else { + altPrivateKey = NULL; + } + #else + privateKey = ssl->buffers.key; + altPrivateKey = ssl->buffers.altKey; + #endif + if (res == 1) { + /* Check certificate and private keys. */ + res = check_cert_key(ssl->buffers.certificate, privateKey, + altPrivateKey, ssl->heap, ssl->buffers.keyDevId, + ssl->buffers.keyLabel, ssl->buffers.keyId, + ssl->buffers.altKeyDevId, ssl->buffers.altKeyLabel, + ssl->buffers.altKeyId); + } + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Dispose of the unblinded buffers. */ + wolfssl_priv_der_unblind_free(privateKey); + wolfssl_priv_der_unblind_free(altPrivateKey); + #endif +#else + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Unblind private key. */ + privateKey = wolfssl_priv_der_unblind(ssl->buffers.key, + ssl->buffers.keyMask); + if (privateKey == NULL) { + res = 0; + } + #else + privateKey = ssl->buffers.key; + #endif + if (res == 1) { + /* Check certificate and private key. */ + res = check_cert_key(ssl->buffers.certificate, privateKey, NULL, + ssl->heap, ssl->buffers.keyDevId, ssl->buffers.keyLabel, + ssl->buffers.keyId, INVALID_DEVID, 0, 0); + } + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + /* Dispose of the unblinded buffer. */ + wolfssl_priv_der_unblind_free(privateKey); + #endif +#endif + } + + return res; +} +#endif /* OPENSSL_EXTRA */ +#endif /* !NO_CHECK_PRIVATE_KEY */ + + +#ifdef OPENSSL_ALL +/** + * Return the private key of the SSL/TLS context. + * + * The caller doesn *NOT*` free the returned object. + * + * Note, even though the supplied ctx pointer is designated const, on success + * ctx->privateKeyPKey is changed by this call. The change is done safely using + * a hardware-synchronized store. + * + * @param [in] ctx SSL/TLS context. + * @return A WOFLSSL_EVP_PKEY on success. + * @return NULL on error. + */ +WOLFSSL_EVP_PKEY* wolfSSL_CTX_get0_privatekey(const WOLFSSL_CTX* ctx) +{ + WOLFSSL_EVP_PKEY* res = NULL; + const unsigned char *key; + int type = WC_EVP_PKEY_NONE; + + WOLFSSL_ENTER("wolfSSL_CTX_get0_privatekey"); + + if ((ctx == NULL) || (ctx->privateKey == NULL) || + (ctx->privateKey->buffer == NULL)) { + WOLFSSL_MSG("Bad parameter or key not set"); + } + else { + switch (ctx->privateKeyType) { + #ifndef NO_RSA + case rsa_sa_algo: + type = WC_EVP_PKEY_RSA; + break; + #endif + #ifdef HAVE_ECC + case ecc_dsa_sa_algo: + type = WC_EVP_PKEY_EC; + break; + #endif + #ifdef WOLFSSL_SM2 + case sm2_sa_algo: + type = WC_EVP_PKEY_EC; + break; + #endif + default: + /* Other key types not supported either as ssl private keys + * or in the EVP layer */ + WOLFSSL_MSG("Unsupported key type"); + } + } + + if (type != WC_EVP_PKEY_NONE) { + if (ctx->privateKeyPKey != NULL) { + res = ctx->privateKeyPKey; + } + else { + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + DerBuffer* unblinded_privateKey = wolfssl_priv_der_unblind( + ctx->privateKey, ctx->privateKeyMask); + if (unblinded_privateKey != NULL) { + key = unblinded_privateKey->buffer; + } + else { + key = NULL; + } + #else + key = ctx->privateKey->buffer; + #endif + if (key != NULL) { + res = wolfSSL_d2i_PrivateKey(type, NULL, &key, + (long)ctx->privateKey->length); + #ifdef WOLFSSL_BLIND_PRIVATE_KEY + wolfssl_priv_der_unblind_free(unblinded_privateKey); + #endif + } + if (res != NULL) { + #ifdef WOLFSSL_ATOMIC_OPS + WOLFSSL_EVP_PKEY *current_pkey = NULL; + if (!wolfSSL_Atomic_Ptr_CompareExchange( + (void * volatile *)&ctx->privateKeyPKey, + (void **)¤t_pkey, res)) { + wolfSSL_EVP_PKEY_free(res); + res = current_pkey; + } + #else + ((WOLFSSL_CTX *)ctx)->privateKeyPKey = res; + #endif + } + } + } + + return res; +} +#endif /* OPENSSL_ALL */ + +#ifdef HAVE_ECC + +/* Set size, in bytes, of temporary ECDHE key into SSL/TLS context. + * + * Values can be: 14 - 66 (112 - 521 bit) + * Uses the private key length if sz is 0. + * + * @param [in] ctx SSL/TLS context. + * @param [in] sz Size of EC key in bytes. + * @return 1 on success. + * @return BAD_FUNC_ARG when ctx is NULL or sz is invalid. + */ +int wolfSSL_CTX_SetTmpEC_DHE_Sz(WOLFSSL_CTX* ctx, word16 sz) +{ + int ret = 0; + + WOLFSSL_ENTER("wolfSSL_CTX_SetTmpEC_DHE_Sz"); + + /* Validate parameters. */ + if (ctx == NULL) { + ret = BAD_FUNC_ARG; + } + /* If size is 0 then get value from loaded private key. */ + else if (sz == 0) { + /* Applies only to ECDSA. */ + if (ctx->privateKeyType != ecc_dsa_sa_algo) { + ret = 1; + } + /* Must have a key set. */ + else if (ctx->privateKeySz == 0) { + WOLFSSL_MSG("Must set private key/cert first"); + ret = BAD_FUNC_ARG; + } + else { + sz = (word16)ctx->privateKeySz; + } + } + if (ret == 0) { + /* Check size against bounds. */ + #if ECC_MIN_KEY_SZ > 0 + if (sz < ECC_MINSIZE) { + ret = BAD_FUNC_ARG; + } + #endif + else if (sz > ECC_MAXSIZE) { + ret = BAD_FUNC_ARG; + } + else { + /* Store the size requested. */ + ctx->eccTempKeySz = sz; + ret = 1; + } + } + + return ret; +} + + +/* Set size, in bytes, of temporary ECDHE key into SSL/TLS object. + * + * Values can be: 14 - 66 (112 - 521 bit) + * Uses the private key length if sz is 0. + * + * @param [in] ssl SSL/TLS object. + * @param [in] sz Size of EC key in bytes. + * @return 1 on success. + * @return BAD_FUNC_ARG when ssl is NULL or sz is invalid. + */ +int wolfSSL_SetTmpEC_DHE_Sz(WOLFSSL* ssl, word16 sz) +{ + int ret = 1; + + WOLFSSL_ENTER("wolfSSL_SetTmpEC_DHE_Sz"); + + /* Validate parameters. */ + if (ssl == NULL) { + ret = BAD_FUNC_ARG; + } + /* Check size against bounds. */ +#if ECC_MIN_KEY_SZ > 0 + else if (sz < ECC_MINSIZE) { + ret = BAD_FUNC_ARG; + } +#endif + else if (sz > ECC_MAXSIZE) { + ret = BAD_FUNC_ARG; + } + else { + /* Store the size requested. */ + ssl->eccTempKeySz = sz; + } + + return ret; +} + +#endif /* HAVE_ECC */ + +#ifdef HAVE_PK_CALLBACKS + +#ifdef HAVE_ECC +/* Set the ECC key generation callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb ECC key generation callback. + */ +void wolfSSL_CTX_SetEccKeyGenCb(WOLFSSL_CTX* ctx, CallbackEccKeyGen cb) +{ + if (ctx != NULL) { + ctx->EccKeyGenCb = cb; + } +} +/* Set the context for ECC key generation callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for ECC key generation callback. + */ +void wolfSSL_SetEccKeyGenCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->EccKeyGenCtx = ctx; + } +} +/* Get the context for ECC key generation callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for ECC key generation callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEccKeyGenCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->EccKeyGenCtx; + } + + return ret; +} +/* Set the context for ECC sign callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] userCtx Context for ECC sign callback. + */ +void wolfSSL_CTX_SetEccSignCtx(WOLFSSL_CTX* ctx, void *userCtx) +{ + if (ctx != NULL) { + ctx->EccSignCtx = userCtx; + } +} +/* Get the context for ECC sign callback from the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @return Context for ECC sign for callback. + * @return NULL when ctx is NULL. + */ +void* wolfSSL_CTX_GetEccSignCtx(WOLFSSL_CTX* ctx) +{ + void* ret; + + if (ctx == NULL) { + ret = NULL; + } + else { + ret = ctx->EccSignCtx; + } + + return ret; +} + +/* Set the ECC sign callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb ECC sign callback. + */ +WOLFSSL_ABI void wolfSSL_CTX_SetEccSignCb(WOLFSSL_CTX* ctx, CallbackEccSign cb) +{ + if (ctx != NULL) { + ctx->EccSignCb = cb; + } +} +/* Set the context for ECC sign callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for ECC sign callback. + */ +void wolfSSL_SetEccSignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->EccSignCtx = ctx; + } +} +/* Get the context for ECC sign callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for ECC sign for callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEccSignCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->EccSignCtx; + } + + return ret; +} + +/* Set the ECC verify callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb ECC verify callback. + */ +void wolfSSL_CTX_SetEccVerifyCb(WOLFSSL_CTX* ctx, CallbackEccVerify cb) +{ + if (ctx != NULL) { + ctx->EccVerifyCb = cb; + } +} +/* Set the context for ECC verify callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for ECC verify callback. + */ +void wolfSSL_SetEccVerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->EccVerifyCtx = ctx; + } +} +/* Get the context for ECC verify callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for ECC verify for callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEccVerifyCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->EccVerifyCtx; + } + + return ret; +} + +/* Set the ECC shared secret callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb ECC shared secret callback. + */ +void wolfSSL_CTX_SetEccSharedSecretCb(WOLFSSL_CTX* ctx, + CallbackEccSharedSecret cb) +{ + if (ctx != NULL) { + ctx->EccSharedSecretCb = cb; + } +} +/* Set the context for ECC shared secret callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for ECC shared secret callback. + */ +void wolfSSL_SetEccSharedSecretCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->EccSharedSecretCtx = ctx; + } +} +/* Get the context for ECC shared secret callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for ECC shared secret callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEccSharedSecretCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->EccSharedSecretCtx; + } + + return ret; +} +#endif /* HAVE_ECC */ + +#ifdef HAVE_ED25519 +/* Set the Ed25519 sign callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb Ed25519 sign callback. + */ +void wolfSSL_CTX_SetEd25519SignCb(WOLFSSL_CTX* ctx, CallbackEd25519Sign cb) +{ + if (ctx != NULL) { + ctx->Ed25519SignCb = cb; + } +} +/* Set the context for Ed25519 sign callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for Ed25519 sign callback. + */ +void wolfSSL_SetEd25519SignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->Ed25519SignCtx = ctx; + } +} +/* Get the context for Ed25519 sign callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for Ed25519 sign callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEd25519SignCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->Ed25519SignCtx; + } + + return ret; +} + +/* Set the Ed25519 verify callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb Ed25519 verify callback. + */ +void wolfSSL_CTX_SetEd25519VerifyCb(WOLFSSL_CTX* ctx, CallbackEd25519Verify cb) +{ + if (ctx != NULL) { + ctx->Ed25519VerifyCb = cb; + } +} +/* Set the context for Ed25519 verify callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for Ed25519 verify callback. + */ +void wolfSSL_SetEd25519VerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->Ed25519VerifyCtx = ctx; + } +} +/* Get the context for Ed25519 verify callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for Ed25519 verify callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEd25519VerifyCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->Ed25519VerifyCtx; + } + + return ret; +} +#endif /* HAVE_ED25519 */ + +#ifdef HAVE_CURVE25519 +/* Set the X25519 key generation callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb X25519 key generation callback. + */ +void wolfSSL_CTX_SetX25519KeyGenCb(WOLFSSL_CTX* ctx, CallbackX25519KeyGen cb) +{ + if (ctx != NULL) { + ctx->X25519KeyGenCb = cb; + } +} +/* Set the context for X25519 key generation callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for X25519 key generation callback. + */ +void wolfSSL_SetX25519KeyGenCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->X25519KeyGenCtx = ctx; + } +} +/* Get the context for X25519 key generation callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for X25519 key generation callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetX25519KeyGenCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->X25519KeyGenCtx; + } + + return ret; +} + +/* Set the X25519 shared secret callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb X25519 shared secret callback. + */ +void wolfSSL_CTX_SetX25519SharedSecretCb(WOLFSSL_CTX* ctx, + CallbackX25519SharedSecret cb) +{ + if (ctx != NULL) { + ctx->X25519SharedSecretCb = cb; + } +} +/* Set the context for X25519 shared secret callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for X25519 shared secret callback. + */ +void wolfSSL_SetX25519SharedSecretCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->X25519SharedSecretCtx = ctx; + } +} +/* Get the context for X25519 shared secret callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for X25519 shared secret callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetX25519SharedSecretCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->X25519SharedSecretCtx; + } + + return ret; +} +#endif /* HAVE_CURVE25519 */ + +#ifdef HAVE_ED448 +/* Set the Ed448 sign callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb Ed448 sign callback. + */ +void wolfSSL_CTX_SetEd448SignCb(WOLFSSL_CTX* ctx, CallbackEd448Sign cb) +{ + if (ctx != NULL) { + ctx->Ed448SignCb = cb; + } +} +/* Set the context for Ed448 sign callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for Ed448 sign callback. + */ +void wolfSSL_SetEd448SignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->Ed448SignCtx = ctx; + } +} +/* Get the context for Ed448 sign callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for Ed448 sign callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEd448SignCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->Ed448SignCtx; + } + + return ret; +} + +/* Set the Ed448 verify callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb Ed448 verify callback. + */ +void wolfSSL_CTX_SetEd448VerifyCb(WOLFSSL_CTX* ctx, CallbackEd448Verify cb) +{ + if (ctx != NULL) { + ctx->Ed448VerifyCb = cb; + } +} +/* Set the context for Ed448 verify callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for Ed448 verify callback. + */ +void wolfSSL_SetEd448VerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->Ed448VerifyCtx = ctx; + } +} +/* Get the context for Ed448 verify callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for Ed448 verify callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetEd448VerifyCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->Ed448VerifyCtx; + } + + return ret; +} +#endif /* HAVE_ED448 */ + +#ifdef HAVE_CURVE448 +/* Set the X448 key generation callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb X448 key generation callback. + */ +void wolfSSL_CTX_SetX448KeyGenCb(WOLFSSL_CTX* ctx, + CallbackX448KeyGen cb) +{ + if (ctx != NULL) { + ctx->X448KeyGenCb = cb; + } +} +/* Set the context for X448 key generation callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for X448 key generation callback. + */ +void wolfSSL_SetX448KeyGenCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->X448KeyGenCtx = ctx; + } +} +/* Get the context for X448 key generation callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for X448 key generation callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetX448KeyGenCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->X448KeyGenCtx; + } + + return ret; +} + +/* Set the X448 shared secret callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb X448 shared secret callback. + */ +void wolfSSL_CTX_SetX448SharedSecretCb(WOLFSSL_CTX* ctx, + CallbackX448SharedSecret cb) +{ + if (ctx != NULL) { + ctx->X448SharedSecretCb = cb; + } +} +/* Set the context for X448 shared secret callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for X448 shared secret callback. + */ +void wolfSSL_SetX448SharedSecretCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->X448SharedSecretCtx = ctx; + } +} +/* Get the context for X448 shared secret callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for X448 shared secret callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetX448SharedSecretCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->X448SharedSecretCtx; + } + + return ret; +} +#endif /* HAVE_CURVE448 */ + +#ifndef NO_RSA +/* Set the RSA sign callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA sign callback. + */ +void wolfSSL_CTX_SetRsaSignCb(WOLFSSL_CTX* ctx, CallbackRsaSign cb) +{ + if (ctx != NULL) { + ctx->RsaSignCb = cb; + } +} +/* Set the RSA sign check callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA sign check callback. + */ +void wolfSSL_CTX_SetRsaSignCheckCb(WOLFSSL_CTX* ctx, CallbackRsaVerify cb) +{ + if (ctx != NULL) { + ctx->RsaSignCheckCb = cb; + } +} +/* Set the context for RSA sign callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for RSA sign callback. + */ +void wolfSSL_SetRsaSignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->RsaSignCtx = ctx; + } +} +/* Get the context for RSA sign callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for RSA sign callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetRsaSignCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->RsaSignCtx; + } + + return ret; +} + +/* Set the RSA verify callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA verify callback. + */ +void wolfSSL_CTX_SetRsaVerifyCb(WOLFSSL_CTX* ctx, CallbackRsaVerify cb) +{ + if (ctx != NULL) { + ctx->RsaVerifyCb = cb; + } +} +/* Set the context for RSA verify callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for RSA verify callback. + */ +void wolfSSL_SetRsaVerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->RsaVerifyCtx = ctx; + } +} +/* Get the context for RSA verify callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for RSA verify callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetRsaVerifyCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->RsaVerifyCtx; + } + + return ret; +} + +#ifdef WC_RSA_PSS +/* Set the RSA PSS sign callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA PSS sign callback. + */ +void wolfSSL_CTX_SetRsaPssSignCb(WOLFSSL_CTX* ctx, CallbackRsaPssSign cb) +{ + if (ctx != NULL) { + ctx->RsaPssSignCb = cb; + } +} +/* Set the RSA PSS sign check callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA PSS sign check callback. + */ +void wolfSSL_CTX_SetRsaPssSignCheckCb(WOLFSSL_CTX* ctx, + CallbackRsaPssVerify cb) +{ + if (ctx != NULL) { + ctx->RsaPssSignCheckCb = cb; + } +} +/* Set the context for RSA PSS sign callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for RSA PSS sign callback. + */ +void wolfSSL_SetRsaPssSignCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->RsaPssSignCtx = ctx; + } +} +/* Get the context for RSA PSS sign callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for RSA PSS sign callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetRsaPssSignCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->RsaPssSignCtx; + } + + return ret; +} + +/* Set the RSA PSS verify callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA PSS verify callback. + */ +void wolfSSL_CTX_SetRsaPssVerifyCb(WOLFSSL_CTX* ctx, CallbackRsaPssVerify cb) +{ + if (ctx != NULL) { + ctx->RsaPssVerifyCb = cb; + } +} +/* Set the context for RSA PSS verify callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for RSA PSS verify callback. + */ +void wolfSSL_SetRsaPssVerifyCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->RsaPssVerifyCtx = ctx; + } +} +/* Get the context for RSA PSS verify callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for RSA PSS verify callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetRsaPssVerifyCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->RsaPssVerifyCtx; + } + + return ret; +} +#endif /* WC_RSA_PSS */ + +/* Set the RSA encrypt callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA encrypt callback. + */ +void wolfSSL_CTX_SetRsaEncCb(WOLFSSL_CTX* ctx, CallbackRsaEnc cb) +{ + if (ctx != NULL) { + ctx->RsaEncCb = cb; + } +} +/* Set the context for RSA encrypt callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for RSA encrypt callback. + */ +void wolfSSL_SetRsaEncCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->RsaEncCtx = ctx; + } +} +/* Get the context for RSA encrypt callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for RSA encrypt callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetRsaEncCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->RsaEncCtx; + } + + return ret; +} + +/* Set the RSA decrypt callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb RSA decrypt callback. + */ +void wolfSSL_CTX_SetRsaDecCb(WOLFSSL_CTX* ctx, CallbackRsaDec cb) +{ + if (ctx != NULL) { + ctx->RsaDecCb = cb; + } +} +/* Set the context for RSA decrypt callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for RSA decrypt callback. + */ +void wolfSSL_SetRsaDecCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->RsaDecCtx = ctx; + } +} +/* Get the context for RSA decrypt callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for RSA decrypt callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetRsaDecCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->RsaDecCtx; + } + + return ret; +} +#endif /* NO_RSA */ + +#endif /* HAVE_PK_CALLBACKS */ + +#endif /* !NO_CERTS */ + +#if defined(HAVE_PK_CALLBACKS) && !defined(NO_DH) +/* Set the DH key pair generation callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb DH key pair generation callback. + */ +void wolfSSL_CTX_SetDhGenerateKeyPair(WOLFSSL_CTX* ctx, + CallbackDhGenerateKeyPair cb) +{ + if (ctx != NULL) { + ctx->DhGenerateKeyPairCb = cb; + } +} +/* Set the DH key agree callback into the SSL/TLS context. + * + * @param [in] ctx SSL/TLS context. + * @param [in] cb DH key agree callback. + */ +void wolfSSL_CTX_SetDhAgreeCb(WOLFSSL_CTX* ctx, CallbackDhAgree cb) +{ + if (ctx != NULL) { + ctx->DhAgreeCb = cb; + } +} +/* Set the context for DH key agree callback into the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @param [in] ctx Context for DH key agree callback. + */ +void wolfSSL_SetDhAgreeCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl != NULL) { + ssl->DhAgreeCtx = ctx; + } +} +/* Get the context for DH key ageww callback from the SSL/TLS object. + * + * @param [in] ssl SSL/TLS object. + * @return Context for DH key agree callback. + * @return NULL when ssl is NULL. + */ +void* wolfSSL_GetDhAgreeCtx(WOLFSSL* ssl) +{ + void* ret; + + if (ssl == NULL) { + ret = NULL; + } + else { + ret = ssl->DhAgreeCtx; + } + + return ret; +} +#endif /* HAVE_PK_CALLBACKS && !NO_DH */ + +#endif /* !WOLFSSL_SSL_API_PK_INCLUDED */ diff --git a/src/ssl_asn1.c b/src/ssl_asn1.c index 2fe3cab470..e9c43ca53e 100644 --- a/src/ssl_asn1.c +++ b/src/ssl_asn1.c @@ -3334,7 +3334,8 @@ const char* wolfSSL_ASN1_tag2str(int tag) const char* str = "(unknown)"; /* Clear negative flag. */ - if ((tag == WOLFSSL_V_ASN1_NEG_INTEGER) || (tag == WOLFSSL_V_ASN1_NEG_ENUMERATED)) { + if ((tag == WOLFSSL_V_ASN1_NEG_INTEGER) || + (tag == WOLFSSL_V_ASN1_NEG_ENUMERATED)) { tag &= ~WOLFSSL_V_ASN1_NEG; } /* Check for known basic types. */ @@ -4194,7 +4195,8 @@ char* wolfSSL_ASN1_TIME_to_string(WOLFSSL_ASN1_TIME* t, char* buf, int len) } /* Get time as human readable string. */ - if ((buf != NULL) && !GetTimeString(t->data, t->type, buf, len, t->length)) { + if ((buf != NULL) && !GetTimeString(t->data, t->type, buf, len, + t->length)) { buf = NULL; } @@ -4717,9 +4719,11 @@ void wolfSSL_ASN1_TYPE_set(WOLFSSL_ASN1_TYPE *a, int type, void *value) int wolfSSL_ASN1_TYPE_get(const WOLFSSL_ASN1_TYPE *a) { - if (a != NULL && (a->type == WOLFSSL_V_ASN1_BOOLEAN || a->type == WOLFSSL_V_ASN1_NULL - || a->value.ptr != NULL)) + if (a != NULL && (a->type == WOLFSSL_V_ASN1_BOOLEAN || + a->type == WOLFSSL_V_ASN1_NULL || + a->value.ptr != NULL)) { return a->type; + } return 0; } diff --git a/src/ssl_certman.c b/src/ssl_certman.c index 2fbab23fc4..5073ba044c 100644 --- a/src/ssl_certman.c +++ b/src/ssl_certman.c @@ -25,7 +25,7 @@ #if !defined(WOLFSSL_SSL_CERTMAN_INCLUDED) #ifndef WOLFSSL_IGNORE_FILE_WARN - #warning ssl_certman.c does not need to be compiled separately from ssl.c + #warning ssl_certman.c not to be compiled separately from ssl.c #endif #else @@ -2142,8 +2142,8 @@ int wolfSSL_CertManagerEnableOCSP(WOLFSSL_CERT_MANAGER* cm, int options) /* Initialize the OCSP object. */ if (InitOCSP(cm->ocsp, cm) != 0) { WOLFSSL_MSG("Init OCSP failed"); - /* Dispose of OCSP object - indicating dynamically allocated. - */ + /* Dispose of OCSP object - indicating dynamically + * allocated. */ FreeOCSP(cm->ocsp, 1); cm->ocsp = NULL; ret = 0; @@ -2533,6 +2533,821 @@ int wolfSSL_CertManagerSetOCSP_Cb(WOLFSSL_CERT_MANAGER* cm, CbOCSPIO ioCb, #endif /* HAVE_OCSP */ +/****************************************************************************** + * Internal APIs that use WOLFSSL_CERT_MANAGER + ******************************************************************************/ + +/* hash is the SHA digest of name, just use first 32 bits as hash */ +static WC_INLINE word32 HashSigner(const byte* hash) +{ + return MakeWordFromHash(hash) % CA_TABLE_SIZE; +} + + +/* does CA already exist on signer list */ +int AlreadySigner(WOLFSSL_CERT_MANAGER* cm, byte* hash) +{ + Signer* signers; + int ret = 0; + word32 row; + + if (cm == NULL || hash == NULL) { + return ret; + } + + row = HashSigner(hash); + + if (wc_LockMutex(&cm->caLock) != 0) { + return ret; + } + signers = cm->caTable[row]; + while (signers) { + byte* subjectHash; + + #ifndef NO_SKID + subjectHash = signers->subjectKeyIdHash; + #else + subjectHash = signers->subjectNameHash; + #endif + + if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { + ret = 1; /* success */ + break; + } + signers = signers->next; + } + wc_UnLockMutex(&cm->caLock); + + return ret; +} + +#ifdef WOLFSSL_TRUST_PEER_CERT +/* hash is the SHA digest of name, just use first 32 bits as hash */ +static WC_INLINE word32 TrustedPeerHashSigner(const byte* hash) +{ + return MakeWordFromHash(hash) % TP_TABLE_SIZE; +} + +/* does trusted peer already exist on signer list */ +int AlreadyTrustedPeer(WOLFSSL_CERT_MANAGER* cm, DecodedCert* cert) +{ + TrustedPeerCert* tp; + int ret = 0; + word32 row = TrustedPeerHashSigner(cert->subjectHash); + + if (wc_LockMutex(&cm->tpLock) != 0) + return ret; + tp = cm->tpTable[row]; + while (tp) { + if ((XMEMCMP(cert->subjectHash, tp->subjectNameHash, + SIGNER_DIGEST_SIZE) == 0) + #ifndef WOLFSSL_NO_ISSUERHASH_TDPEER + && (XMEMCMP(cert->issuerHash, tp->issuerHash, + SIGNER_DIGEST_SIZE) == 0) + #endif + ) + ret = 1; + #ifndef NO_SKID + if (cert->extSubjKeyIdSet) { + /* Compare SKID as well if available */ + if (ret == 1 && XMEMCMP(cert->extSubjKeyId, tp->subjectKeyIdHash, + SIGNER_DIGEST_SIZE) != 0) + ret = 0; + } + #endif + if (ret == 1) + break; + tp = tp->next; + } + wc_UnLockMutex(&cm->tpLock); + + return ret; +} + +/* return Trusted Peer if found, otherwise NULL + type is what to match on + */ +TrustedPeerCert* GetTrustedPeer(void* vp, DecodedCert* cert) +{ + WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; + TrustedPeerCert* ret = NULL; + TrustedPeerCert* tp = NULL; + word32 row; + + if (cm == NULL || cert == NULL) + return NULL; + + row = TrustedPeerHashSigner(cert->subjectHash); + + if (wc_LockMutex(&cm->tpLock) != 0) + return ret; + + tp = cm->tpTable[row]; + while (tp) { + if ((XMEMCMP(cert->subjectHash, tp->subjectNameHash, + SIGNER_DIGEST_SIZE) == 0) + #ifndef WOLFSSL_NO_ISSUERHASH_TDPEER + && (XMEMCMP(cert->issuerHash, tp->issuerHash, + SIGNER_DIGEST_SIZE) == 0) + #endif + ) + ret = tp; + #ifndef NO_SKID + if (cert->extSubjKeyIdSet) { + /* Compare SKID as well if available */ + if (ret != NULL && XMEMCMP(cert->extSubjKeyId, tp->subjectKeyIdHash, + SIGNER_DIGEST_SIZE) != 0) + ret = NULL; + } + #endif + if (ret != NULL) + break; + tp = tp->next; + } + wc_UnLockMutex(&cm->tpLock); + + return ret; +} + + +int MatchTrustedPeer(TrustedPeerCert* tp, DecodedCert* cert) +{ + if (tp == NULL || cert == NULL) + return BAD_FUNC_ARG; + + /* subject key id or subject hash has been compared when searching + tpTable for the cert from function GetTrustedPeer */ + + /* compare signatures */ + if (tp->sigLen == cert->sigLength) { + if (XMEMCMP(tp->sig, cert->signature, cert->sigLength)) { + return WOLFSSL_FAILURE; + } + } + else { + return WOLFSSL_FAILURE; + } + + return WOLFSSL_SUCCESS; +} +#endif /* WOLFSSL_TRUST_PEER_CERT */ + +/* return CA if found, otherwise NULL */ +Signer* GetCA(void* vp, byte* hash) +{ + WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; + Signer* ret = NULL; + Signer* signers; + word32 row = 0; + + if (cm == NULL || hash == NULL) + return NULL; + + row = HashSigner(hash); + + if (wc_LockMutex(&cm->caLock) != 0) + return ret; + + signers = cm->caTable[row]; + while (signers) { + byte* subjectHash; + #ifndef NO_SKID + subjectHash = signers->subjectKeyIdHash; + #else + subjectHash = signers->subjectNameHash; + #endif + if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { + ret = signers; + break; + } + signers = signers->next; + } + wc_UnLockMutex(&cm->caLock); + + return ret; +} + +#if defined(HAVE_OCSP) +Signer* GetCAByKeyHash(void* vp, const byte* keyHash) +{ + WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; + Signer* ret = NULL; + Signer* signers; + int row; + + if (cm == NULL || keyHash == NULL) + return NULL; + + /* try lookup using keyHash as subjKeyID first */ + ret = GetCA(vp, (byte*)keyHash); + if (ret != NULL && XMEMCMP(ret->subjectKeyHash, keyHash, KEYID_SIZE) == 0) { + return ret; + } + + /* if we can't find the cert, we have to scan the full table */ + if (wc_LockMutex(&cm->caLock) != 0) + return NULL; + + /* Unfortunately we need to look through the entire table */ + for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) { + for (signers = cm->caTable[row]; signers != NULL; + signers = signers->next) { + if (XMEMCMP(signers->subjectKeyHash, keyHash, KEYID_SIZE) == 0) { + ret = signers; + break; + } + } + } + + wc_UnLockMutex(&cm->caLock); + return ret; +} +#endif +#ifdef WOLFSSL_AKID_NAME +Signer* GetCAByAKID(void* vp, const byte* issuer, word32 issuerSz, + const byte* serial, word32 serialSz) +{ + WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; + Signer* ret = NULL; + Signer* signers; + byte nameHash[SIGNER_DIGEST_SIZE]; + byte serialHash[SIGNER_DIGEST_SIZE]; + word32 row; + + if (cm == NULL || issuer == NULL || issuerSz == 0 || + serial == NULL || serialSz == 0) + return NULL; + + if (CalcHashId(issuer, issuerSz, nameHash) != 0 || + CalcHashId(serial, serialSz, serialHash) != 0) + return NULL; + + if (wc_LockMutex(&cm->caLock) != 0) + return ret; + + /* Unfortunately we need to look through the entire table */ + for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) { + for (signers = cm->caTable[row]; signers != NULL; + signers = signers->next) { + if (XMEMCMP(signers->issuerNameHash, nameHash, SIGNER_DIGEST_SIZE) + == 0 && XMEMCMP(signers->serialHash, serialHash, + SIGNER_DIGEST_SIZE) == 0) { + ret = signers; + break; + } + } + } + + wc_UnLockMutex(&cm->caLock); + + return ret; +} +#endif + +#ifndef NO_SKID +/* return CA if found, otherwise NULL. Walk through hash table. */ +Signer* GetCAByName(void* vp, byte* hash) +{ + WOLFSSL_CERT_MANAGER* cm = (WOLFSSL_CERT_MANAGER*)vp; + Signer* ret = NULL; + Signer* signers; + word32 row; + + if (cm == NULL) + return NULL; + + if (wc_LockMutex(&cm->caLock) != 0) + return ret; + + for (row = 0; row < CA_TABLE_SIZE && ret == NULL; row++) { + signers = cm->caTable[row]; + while (signers && ret == NULL) { + if (XMEMCMP(hash, signers->subjectNameHash, + SIGNER_DIGEST_SIZE) == 0) { + ret = signers; + } + signers = signers->next; + } + } + wc_UnLockMutex(&cm->caLock); + + return ret; +} +#endif + +#ifdef WOLFSSL_TRUST_PEER_CERT +/* add a trusted peer cert to linked list */ +int AddTrustedPeer(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int verify) +{ + int ret = 0; + int row = 0; + TrustedPeerCert* peerCert; + DecodedCert* cert; + DerBuffer* der = *pDer; + + WOLFSSL_MSG("Adding a Trusted Peer Cert"); + + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), cm->heap, + DYNAMIC_TYPE_DCERT); + if (cert == NULL) { + FreeDer(&der); + return MEMORY_E; + } + + InitDecodedCert(cert, der->buffer, der->length, cm->heap); + if ((ret = ParseCert(cert, TRUSTED_PEER_TYPE, verify, cm)) != 0) { + FreeDecodedCert(cert); + XFREE(cert, NULL, DYNAMIC_TYPE_DCERT); + FreeDer(&der); + return ret; + } + WOLFSSL_MSG("\tParsed new trusted peer cert"); + + peerCert = (TrustedPeerCert*)XMALLOC(sizeof(TrustedPeerCert), cm->heap, + DYNAMIC_TYPE_CERT); + if (peerCert == NULL) { + FreeDecodedCert(cert); + XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); + FreeDer(&der); + return MEMORY_E; + } + XMEMSET(peerCert, 0, sizeof(TrustedPeerCert)); + + #ifndef IGNORE_NAME_CONSTRAINTS + if (peerCert->permittedNames) + FreeNameSubtrees(peerCert->permittedNames, cm->heap); + if (peerCert->excludedNames) + FreeNameSubtrees(peerCert->excludedNames, cm->heap); + #endif + + if (AlreadyTrustedPeer(cm, cert)) { + WOLFSSL_MSG("\tAlready have this CA, not adding again"); + FreeTrustedPeer(peerCert, cm->heap); + (void)ret; + } + else { + /* add trusted peer signature */ + peerCert->sigLen = cert->sigLength; + peerCert->sig = (byte *)XMALLOC(cert->sigLength, cm->heap, + DYNAMIC_TYPE_SIGNATURE); + if (peerCert->sig == NULL) { + FreeDecodedCert(cert); + XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); + FreeTrustedPeer(peerCert, cm->heap); + FreeDer(&der); + return MEMORY_E; + } + XMEMCPY(peerCert->sig, cert->signature, cert->sigLength); + + /* add trusted peer name */ + peerCert->nameLen = cert->subjectCNLen; + peerCert->name = cert->subjectCN; + #ifndef IGNORE_NAME_CONSTRAINTS + peerCert->permittedNames = cert->permittedNames; + peerCert->excludedNames = cert->excludedNames; + #endif + + /* add SKID when available and hash of name */ + #ifndef NO_SKID + XMEMCPY(peerCert->subjectKeyIdHash, cert->extSubjKeyId, + SIGNER_DIGEST_SIZE); + #endif + XMEMCPY(peerCert->subjectNameHash, cert->subjectHash, + SIGNER_DIGEST_SIZE); + #ifndef WOLFSSL_NO_ISSUERHASH_TDPEER + XMEMCPY(peerCert->issuerHash, cert->issuerHash, + SIGNER_DIGEST_SIZE); + #endif + /* If Key Usage not set, all uses valid. */ + peerCert->next = NULL; + cert->subjectCN = 0; + #ifndef IGNORE_NAME_CONSTRAINTS + cert->permittedNames = NULL; + cert->excludedNames = NULL; + #endif + + row = (int)TrustedPeerHashSigner(peerCert->subjectNameHash); + + if (wc_LockMutex(&cm->tpLock) == 0) { + peerCert->next = cm->tpTable[row]; + cm->tpTable[row] = peerCert; /* takes ownership */ + wc_UnLockMutex(&cm->tpLock); + } + else { + WOLFSSL_MSG("\tTrusted Peer Cert Mutex Lock failed"); + FreeDecodedCert(cert); + XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); + FreeTrustedPeer(peerCert, cm->heap); + FreeDer(&der); + return BAD_MUTEX_E; + } + } + + WOLFSSL_MSG("\tFreeing parsed trusted peer cert"); + FreeDecodedCert(cert); + XFREE(cert, cm->heap, DYNAMIC_TYPE_DCERT); + WOLFSSL_MSG("\tFreeing der trusted peer cert"); + FreeDer(&der); + WOLFSSL_MSG("\t\tOK Freeing der trusted peer cert"); + WOLFSSL_LEAVE("AddTrustedPeer", ret); + + return WOLFSSL_SUCCESS; +} +#endif /* WOLFSSL_TRUST_PEER_CERT */ + +int AddSigner(WOLFSSL_CERT_MANAGER* cm, Signer *s) +{ + byte* subjectHash; + Signer* signers; + word32 row; + + if (cm == NULL || s == NULL) + return BAD_FUNC_ARG; + +#ifndef NO_SKID + subjectHash = s->subjectKeyIdHash; +#else + subjectHash = s->subjectNameHash; +#endif + + if (AlreadySigner(cm, subjectHash)) { + FreeSigner(s, cm->heap); + return 0; + } + + row = HashSigner(subjectHash); + + if (wc_LockMutex(&cm->caLock) != 0) + return BAD_MUTEX_E; + + signers = cm->caTable[row]; + s->next = signers; + cm->caTable[row] = s; + + wc_UnLockMutex(&cm->caLock); + return 0; +} + +/* owns der, internal now uses too */ +/* type flag ids from user or from chain received during verify + don't allow chain ones to be added w/o isCA extension */ +int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) +{ + int ret; + Signer* signer = NULL; + word32 row; + byte* subjectHash; + WC_DECLARE_VAR(cert, DecodedCert, 1, 0); + DerBuffer* der = *pDer; + + WOLFSSL_MSG_CERT_LOG("Adding a CA"); + + if (cm == NULL) { + FreeDer(pDer); + return BAD_FUNC_ARG; + } + + #ifdef WOLFSSL_SMALL_STACK + cert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); + if (cert == NULL) { + FreeDer(pDer); + return MEMORY_E; + } + #endif + + InitDecodedCert(cert, der->buffer, der->length, cm->heap); + +#ifdef WC_ASN_UNKNOWN_EXT_CB + if (cm->unknownExtCallback != NULL) { + wc_SetUnknownExtCallback(cert, cm->unknownExtCallback); + } +#endif + + WOLFSSL_MSG_CERT("\tParsing new CA"); + ret = ParseCert(cert, CA_TYPE, verify, cm); + + WOLFSSL_MSG("\tParsed new CA"); +#ifdef WOLFSSL_DEBUG_CERTS + { + const char* err_msg; + if (ret == 0) { + WOLFSSL_MSG_CERT_EX(WOLFSSL_MSG_CERT_INDENT "issuer: '%s'", + cert->issuer); + WOLFSSL_MSG_CERT_EX(WOLFSSL_MSG_CERT_INDENT "subject: '%s'", + cert->subject); + } + else { + WOLFSSL_MSG_CERT( + WOLFSSL_MSG_CERT_INDENT "Failed during parse of new CA"); + err_msg = wc_GetErrorString(ret); + WOLFSSL_MSG_CERT_EX(WOLFSSL_MSG_CERT_INDENT "error ret: %d; %s", + ret, err_msg); + } + } +#endif /* WOLFSSL_DEBUG_CERTS */ + +#ifndef NO_SKID + subjectHash = cert->extSubjKeyId; +#else + subjectHash = cert->subjectHash; +#endif + + /* check CA key size */ + if (verify && (ret == 0 )) { + switch (cert->keyOID) { + #ifndef NO_RSA + #ifdef WC_RSA_PSS + case RSAPSSk: + #endif + case RSAk: + if (cm->minRsaKeySz < 0 || + cert->pubKeySize < (word16)cm->minRsaKeySz) { + ret = RSA_KEY_SIZE_E; + WOLFSSL_MSG_CERT_LOG("\tCA RSA key size error"); + WOLFSSL_MSG_CERT_EX("\tCA RSA pubKeySize = %d; " + "minRsaKeySz = %d", + cert->pubKeySize, cm->minRsaKeySz); + } + break; + #endif /* !NO_RSA */ + #ifdef HAVE_ECC + case ECDSAk: + if (cm->minEccKeySz < 0 || + cert->pubKeySize < (word16)cm->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG_CERT_LOG("\tCA ECC key size error"); + WOLFSSL_MSG_CERT_EX("\tCA ECC pubKeySize = %d; " + "minEccKeySz = %d", + cert->pubKeySize, cm->minEccKeySz); + } + break; + #endif /* HAVE_ECC */ + #ifdef HAVE_ED25519 + case ED25519k: + if (cm->minEccKeySz < 0 || + ED25519_KEY_SIZE < (word16)cm->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("\tCA ECC key size error"); + } + break; + #endif /* HAVE_ED25519 */ + #ifdef HAVE_ED448 + case ED448k: + if (cm->minEccKeySz < 0 || + ED448_KEY_SIZE < (word16)cm->minEccKeySz) { + ret = ECC_KEY_SIZE_E; + WOLFSSL_MSG("\tCA ECC key size error"); + } + break; + #endif /* HAVE_ED448 */ + #if defined(HAVE_FALCON) + case FALCON_LEVEL1k: + if (cm->minFalconKeySz < 0 || + FALCON_LEVEL1_KEY_SIZE < (word16)cm->minFalconKeySz) { + ret = FALCON_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Falcon level 1 key size error"); + } + break; + case FALCON_LEVEL5k: + if (cm->minFalconKeySz < 0 || + FALCON_LEVEL5_KEY_SIZE < (word16)cm->minFalconKeySz) { + ret = FALCON_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Falcon level 5 key size error"); + } + break; + #endif /* HAVE_FALCON */ + #if defined(HAVE_DILITHIUM) + #ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT + case DILITHIUM_LEVEL2k: + if (cm->minDilithiumKeySz < 0 || + DILITHIUM_LEVEL2_KEY_SIZE < (word16)cm->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Dilithium level 2 key size error"); + } + break; + case DILITHIUM_LEVEL3k: + if (cm->minDilithiumKeySz < 0 || + DILITHIUM_LEVEL3_KEY_SIZE < (word16)cm->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Dilithium level 3 key size error"); + } + break; + case DILITHIUM_LEVEL5k: + if (cm->minDilithiumKeySz < 0 || + DILITHIUM_LEVEL5_KEY_SIZE < (word16)cm->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Dilithium level 5 key size error"); + } + break; + #endif /* WOLFSSL_DILITHIUM_FIPS204_DRAFT */ + case ML_DSA_LEVEL2k: + if (cm->minDilithiumKeySz < 0 || + ML_DSA_LEVEL2_KEY_SIZE < (word16)cm->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Dilithium level 2 key size error"); + } + break; + case ML_DSA_LEVEL3k: + if (cm->minDilithiumKeySz < 0 || + ML_DSA_LEVEL3_KEY_SIZE < (word16)cm->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Dilithium level 3 key size error"); + } + break; + case ML_DSA_LEVEL5k: + if (cm->minDilithiumKeySz < 0 || + ML_DSA_LEVEL5_KEY_SIZE < (word16)cm->minDilithiumKeySz) { + ret = DILITHIUM_KEY_SIZE_E; + WOLFSSL_MSG("\tCA Dilithium level 5 key size error"); + } + break; + #endif /* HAVE_DILITHIUM */ + + default: + WOLFSSL_MSG("\tNo key size check done on CA"); + break; /* no size check if key type is not in switch */ + } + } + + if (ret == 0 && cert->isCA == 0 && type != WOLFSSL_USER_CA && + type != WOLFSSL_TEMP_CA) { + WOLFSSL_MSG("\tCan't add as CA if not actually one"); + ret = NOT_CA_ERROR; + } +#ifndef ALLOW_INVALID_CERTSIGN + else if (ret == 0 && cert->isCA == 1 && type != WOLFSSL_USER_CA && + type != WOLFSSL_TEMP_CA && !cert->selfSigned && + (cert->extKeyUsage & KEYUSE_KEY_CERT_SIGN) == 0) { + /* Intermediate CA certs are required to have the keyCertSign + * extension set. User loaded root certs are not. */ + WOLFSSL_MSG("\tDoesn't have key usage certificate signing"); + ret = NOT_CA_ERROR; + } +#endif + else if (ret == 0 && AlreadySigner(cm, subjectHash)) { + WOLFSSL_MSG("\tAlready have this CA, not adding again"); + (void)ret; + } + else if (ret == 0) { + /* take over signer parts */ + signer = MakeSigner(cm->heap); + if (!signer) + ret = MEMORY_ERROR; + } + if (ret == 0 && signer != NULL) { + ret = FillSigner(signer, cert, type, der); + + if (ret == 0){ + #ifndef NO_SKID + row = HashSigner(signer->subjectKeyIdHash); + #else + row = HashSigner(signer->subjectNameHash); + #endif + } + + #if defined(WOLFSSL_RENESAS_TSIP_TLS) || defined(WOLFSSL_RENESAS_FSPSM_TLS) + /* Verify CA by TSIP so that generated tsip key is going to */ + /* be able to be used for peer's cert verification */ + /* TSIP is only able to handle USER CA, and only one CA. */ + /* Therefore, it doesn't need to call TSIP again if there is already */ + /* verified CA. */ + if ( ret == 0 && signer != NULL ) { + signer->cm_idx = row; + if (type == WOLFSSL_USER_CA) { + if ((ret = wc_Renesas_cmn_RootCertVerify(cert->source, + cert->maxIdx, + cert->sigCtx.CertAtt.pubkey_n_start, + cert->sigCtx.CertAtt.pubkey_n_len - 1, + cert->sigCtx.CertAtt.pubkey_e_start, + cert->sigCtx.CertAtt.pubkey_e_len - 1, + row/* cm index */)) + < 0) + WOLFSSL_MSG("Renesas_RootCertVerify() failed"); + else + WOLFSSL_MSG("Renesas_RootCertVerify() succeed or skipped"); + } + } + #endif /* TSIP or SCE */ + + if (ret == 0 && wc_LockMutex(&cm->caLock) == 0) { + signer->next = cm->caTable[row]; + cm->caTable[row] = signer; /* takes ownership */ + wc_UnLockMutex(&cm->caLock); + if (cm->caCacheCallback) + cm->caCacheCallback(der->buffer, (int)der->length, type); + } + else { + WOLFSSL_MSG("\tCA Mutex Lock failed"); + ret = BAD_MUTEX_E; + } + } + + WOLFSSL_MSG("\tFreeing Parsed CA"); + FreeDecodedCert(cert); + if (ret != 0 && signer != NULL) + FreeSigner(signer, cm->heap); + WC_FREE_VAR_EX(cert, NULL, DYNAMIC_TYPE_DCERT); + WOLFSSL_MSG("\tFreeing der CA"); + FreeDer(pDer); + WOLFSSL_MSG("\t\tOK Freeing der CA"); + + WOLFSSL_LEAVE("AddCA", ret); + + return ret == 0 ? WOLFSSL_SUCCESS : ret; +} + +/* Removes the CA with the passed in subject hash from the + cert manager's CA cert store. */ +int RemoveCA(WOLFSSL_CERT_MANAGER* cm, byte* hash, int type) +{ + Signer* current; + Signer** prev; + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + word32 row; + + WOLFSSL_MSG("Removing a CA"); + + if (cm == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + + row = HashSigner(hash); + + if (wc_LockMutex(&cm->caLock) != 0) { + return BAD_MUTEX_E; + } + current = cm->caTable[row]; + prev = &cm->caTable[row]; + while (current) { + byte* subjectHash; + + #ifndef NO_SKID + subjectHash = current->subjectKeyIdHash; + #else + subjectHash = current->subjectNameHash; + #endif + + if ((current->type == type) && + (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0)) { + *prev = current->next; + FreeSigner(current, cm->heap); + ret = WOLFSSL_SUCCESS; + break; + } + prev = ¤t->next; + current = current->next; + } + wc_UnLockMutex(&cm->caLock); + + WOLFSSL_LEAVE("RemoveCA", ret); + + return ret; +} + +/* Sets the CA with the passed in subject hash + to the provided type. */ +int SetCAType(WOLFSSL_CERT_MANAGER* cm, byte* hash, int type) +{ + Signer* current; + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + word32 row; + + WOLFSSL_MSG_EX("Setting CA to type %d", type); + + if (cm == NULL || hash == NULL || + type < WOLFSSL_USER_CA || type > WOLFSSL_USER_INTER) { + return ret; + } + + row = HashSigner(hash); + + if (wc_LockMutex(&cm->caLock) != 0) { + return ret; + } + current = cm->caTable[row]; + while (current) { + byte* subjectHash; + + #ifndef NO_SKID + subjectHash = current->subjectKeyIdHash; + #else + subjectHash = current->subjectNameHash; + #endif + + if (XMEMCMP(hash, subjectHash, SIGNER_DIGEST_SIZE) == 0) { + current->type = (byte)type; + ret = WOLFSSL_SUCCESS; + break; + } + current = current->next; + } + wc_UnLockMutex(&cm->caLock); + + WOLFSSL_LEAVE("SetCAType", ret); + + return ret; +} + #endif /* NO_CERTS */ #endif /* !WOLFSSL_SSL_CERTMAN_INCLUDED */ diff --git a/src/ssl_crypto.c b/src/ssl_crypto.c index 167f71cc88..477c9a9971 100644 --- a/src/ssl_crypto.c +++ b/src/ssl_crypto.c @@ -3071,8 +3071,8 @@ void wolfSSL_AES_decrypt(const unsigned char* input, unsigned char* output, WOLFSSL_MSG("Null argument passed in"); } else -#if !defined(HAVE_SELFTEST) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION3_GE(5,3,0))) +#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \ + (defined(FIPS_VERSION_GE) && FIPS_VERSION3_GE(5,3,0))) /* Decrypt a block with wolfCrypt AES. */ if (wc_AesDecryptDirect((Aes*)key, output, input) != 0) { WOLFSSL_MSG("wc_AesDecryptDirect failed"); @@ -3203,7 +3203,8 @@ void wolfSSL_AES_cbc_encrypt(const unsigned char *in, unsigned char* out, * AES_ENCRPT for encryption, AES_DECRYPTION for decryption. */ void wolfSSL_AES_cfb128_encrypt(const unsigned char *in, unsigned char* out, - size_t len, WOLFSSL_AES_KEY *key, unsigned char* iv, int* num, const int enc) + size_t len, WOLFSSL_AES_KEY *key, unsigned char* iv, int* num, + const int enc) { #ifndef WOLFSSL_AES_CFB WOLFSSL_MSG("CFB mode not enabled please use macro WOLFSSL_AES_CFB"); @@ -3435,13 +3436,15 @@ size_t wolfSSL_CRYPTO_cts128_decrypt(const unsigned char *in, * Use 0 buffer as IV to do straight decryption. * This places the Cn-1 block at lastBlk */ XMEMSET(lastBlk, 0, WOLFSSL_CTS128_BLOCK_SZ); - (*cbc)(in, prevBlk, WOLFSSL_CTS128_BLOCK_SZ, key, lastBlk, AES_DECRYPTION); + (*cbc)(in, prevBlk, WOLFSSL_CTS128_BLOCK_SZ, key, lastBlk, + AES_DECRYPTION); /* RFC2040: Append the tail (BB minus Ln) bytes of Xn to Cn * to create En. */ XMEMCPY(prevBlk, in + WOLFSSL_CTS128_BLOCK_SZ, lastBlkLen); /* Cn and Cn-1 can now be decrypted */ (*cbc)(prevBlk, out, WOLFSSL_CTS128_BLOCK_SZ, key, iv, AES_DECRYPTION); - (*cbc)(lastBlk, lastBlk, WOLFSSL_CTS128_BLOCK_SZ, key, iv, AES_DECRYPTION); + (*cbc)(lastBlk, lastBlk, WOLFSSL_CTS128_BLOCK_SZ, key, iv, + AES_DECRYPTION); XMEMCPY(out + WOLFSSL_CTS128_BLOCK_SZ, lastBlk, lastBlkLen); } diff --git a/src/ssl_ech.c b/src/ssl_ech.c new file mode 100644 index 0000000000..d27522c862 --- /dev/null +++ b/src/ssl_ech.c @@ -0,0 +1,738 @@ +/* ssl_ech.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 + +#if !defined(WOLFSSL_SSL_ECH_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning ssl_ech.c does not need to be compiled separately from ssl.c + #endif +#else + +#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH) + +/* create the hpke key and ech config to send to clients */ +int wolfSSL_CTX_GenerateEchConfig(WOLFSSL_CTX* ctx, const char* publicName, + word16 kemId, word16 kdfId, word16 aeadId) +{ + int ret = 0; + word16 encLen = DHKEM_X25519_ENC_LEN; + WOLFSSL_EchConfig* newConfig; + WOLFSSL_EchConfig* parentConfig; +#ifdef WOLFSSL_SMALL_STACK + Hpke* hpke = NULL; + WC_RNG* rng; +#else + Hpke hpke[1]; + WC_RNG rng[1]; +#endif + + if (ctx == NULL || publicName == NULL) + return BAD_FUNC_ARG; + + WC_ALLOC_VAR_EX(rng, WC_RNG, 1, ctx->heap, DYNAMIC_TYPE_RNG, + return MEMORY_E); + ret = wc_InitRng(rng); + if (ret != 0) { + WC_FREE_VAR_EX(rng, ctx->heap, DYNAMIC_TYPE_RNG); + return ret; + } + + newConfig = (WOLFSSL_EchConfig*)XMALLOC(sizeof(WOLFSSL_EchConfig), + ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (newConfig == NULL) + ret = MEMORY_E; + else + XMEMSET(newConfig, 0, sizeof(WOLFSSL_EchConfig)); + + /* set random config id */ + if (ret == 0) + ret = wc_RNG_GenerateByte(rng, &newConfig->configId); + + /* if 0 is selected for algorithms use default, may change with draft */ + if (kemId == 0) + kemId = DHKEM_X25519_HKDF_SHA256; + + if (kdfId == 0) + kdfId = HKDF_SHA256; + + if (aeadId == 0) + aeadId = HPKE_AES_128_GCM; + + if (ret == 0) { + /* set the kem id */ + newConfig->kemId = kemId; + + /* set the cipher suite, only 1 for now */ + newConfig->numCipherSuites = 1; + newConfig->cipherSuites = + (EchCipherSuite*)XMALLOC(sizeof(EchCipherSuite), ctx->heap, + DYNAMIC_TYPE_TMP_BUFFER); + + if (newConfig->cipherSuites == NULL) { + ret = MEMORY_E; + } + else { + newConfig->cipherSuites[0].kdfId = kdfId; + newConfig->cipherSuites[0].aeadId = aeadId; + } + } + +#ifdef WOLFSSL_SMALL_STACK + if (ret == 0) { + hpke = (Hpke*)XMALLOC(sizeof(Hpke), ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (hpke == NULL) + ret = MEMORY_E; + } +#endif + + if (ret == 0) + ret = wc_HpkeInit(hpke, kemId, kdfId, aeadId, ctx->heap); + + /* generate the receiver private key */ + if (ret == 0) + ret = wc_HpkeGenerateKeyPair(hpke, &newConfig->receiverPrivkey, rng); + + /* done with RNG */ + wc_FreeRng(rng); + + /* serialize the receiver key */ + if (ret == 0) + ret = wc_HpkeSerializePublicKey(hpke, newConfig->receiverPrivkey, + newConfig->receiverPubkey, &encLen); + + if (ret == 0) { + newConfig->publicName = (char*)XMALLOC(XSTRLEN(publicName) + 1, + ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (newConfig->publicName == NULL) { + ret = MEMORY_E; + } + else { + XMEMCPY(newConfig->publicName, publicName, + XSTRLEN(publicName) + 1); + } + } + + if (ret != 0) { + if (newConfig) { + XFREE(newConfig->cipherSuites, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(newConfig->publicName, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(newConfig, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + } + } + else { + parentConfig = ctx->echConfigs; + + if (parentConfig == NULL) { + ctx->echConfigs = newConfig; + } + else { + while (parentConfig->next != NULL) { + parentConfig = parentConfig->next; + } + + parentConfig->next = newConfig; + } + } + + if (ret == 0) + ret = WOLFSSL_SUCCESS; + + WC_FREE_VAR_EX(hpke, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + WC_FREE_VAR_EX(rng, ctx->heap, DYNAMIC_TYPE_RNG); + + return ret; +} + +int wolfSSL_CTX_SetEchConfigsBase64(WOLFSSL_CTX* ctx, const char* echConfigs64, + word32 echConfigs64Len) +{ + int ret = 0; + word32 decodedLen = echConfigs64Len * 3 / 4 + 1; + byte* decodedConfigs; + + if (ctx == NULL || echConfigs64 == NULL || echConfigs64Len == 0) + return BAD_FUNC_ARG; + + decodedConfigs = (byte*)XMALLOC(decodedLen, ctx->heap, + DYNAMIC_TYPE_TMP_BUFFER); + + if (decodedConfigs == NULL) + return MEMORY_E; + + decodedConfigs[decodedLen - 1] = 0; + + /* decode the echConfigs */ + ret = Base64_Decode((const byte*)echConfigs64, echConfigs64Len, + decodedConfigs, &decodedLen); + + if (ret != 0) { + XFREE(decodedConfigs, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + ret = wolfSSL_CTX_SetEchConfigs(ctx, decodedConfigs, decodedLen); + + XFREE(decodedConfigs, ctx->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +int wolfSSL_CTX_SetEchConfigs(WOLFSSL_CTX* ctx, const byte* echConfigs, + word32 echConfigsLen) +{ + int ret; + + if (ctx == NULL || echConfigs == NULL || echConfigsLen == 0) + return BAD_FUNC_ARG; + + FreeEchConfigs(ctx->echConfigs, ctx->heap); + ctx->echConfigs = NULL; + ret = SetEchConfigsEx(&ctx->echConfigs, ctx->heap, echConfigs, + echConfigsLen); + + if (ret == 0) + return WOLFSSL_SUCCESS; + + return ret; +} + +/* get the ech configs that the server context is using */ +int wolfSSL_CTX_GetEchConfigs(WOLFSSL_CTX* ctx, byte* output, + word32* outputLen) { + if (ctx == NULL || outputLen == NULL) + return BAD_FUNC_ARG; + + /* if we don't have ech configs */ + if (ctx->echConfigs == NULL) + return WOLFSSL_FATAL_ERROR; + + return GetEchConfigsEx(ctx->echConfigs, output, outputLen); +} + +void wolfSSL_CTX_SetEchEnable(WOLFSSL_CTX* ctx, byte enable) +{ + if (ctx != NULL) { + ctx->disableECH = !enable; + if (ctx->disableECH) { + TLSX_Remove(&ctx->extensions, TLSX_ECH, ctx->heap); + FreeEchConfigs(ctx->echConfigs, ctx->heap); + ctx->echConfigs = NULL; + } + } +} + +/* set the ech config from base64 for our client ssl object, base64 is the + * format ech configs are sent using dns records */ +int wolfSSL_SetEchConfigsBase64(WOLFSSL* ssl, char* echConfigs64, + word32 echConfigs64Len) +{ + int ret = 0; + word32 decodedLen = echConfigs64Len * 3 / 4 + 1; + byte* decodedConfigs; + + if (ssl == NULL || echConfigs64 == NULL || echConfigs64Len == 0) + return BAD_FUNC_ARG; + + /* already have ech configs */ + if (ssl->options.useEch == 1) { + return WOLFSSL_FATAL_ERROR; + } + + decodedConfigs = (byte*)XMALLOC(decodedLen, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + + if (decodedConfigs == NULL) + return MEMORY_E; + + decodedConfigs[decodedLen - 1] = 0; + + /* decode the echConfigs */ + ret = Base64_Decode((byte*)echConfigs64, echConfigs64Len, + decodedConfigs, &decodedLen); + + if (ret != 0) { + XFREE(decodedConfigs, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + return ret; + } + + ret = wolfSSL_SetEchConfigs(ssl, decodedConfigs, decodedLen); + + XFREE(decodedConfigs, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +/* set the ech config from a raw buffer, this is the format ech configs are + * sent using retry_configs from the ech server */ +int wolfSSL_SetEchConfigs(WOLFSSL* ssl, const byte* echConfigs, + word32 echConfigsLen) +{ + int ret; + + if (ssl == NULL || echConfigs == NULL || echConfigsLen == 0) + return BAD_FUNC_ARG; + + /* already have ech configs */ + if (ssl->options.useEch == 1) { + return WOLFSSL_FATAL_ERROR; + } + + ret = SetEchConfigsEx(&ssl->echConfigs, ssl->heap, echConfigs, + echConfigsLen); + + /* if we found valid configs */ + if (ret == 0) { + ssl->options.useEch = 1; + return WOLFSSL_SUCCESS; + } + + return ret; +} + +/* get the raw ech config from our struct */ +int GetEchConfig(WOLFSSL_EchConfig* config, byte* output, word32* outputLen) +{ + int i; + word16 totalLen = 0; + + if (config == NULL || (output == NULL && outputLen == NULL)) + return BAD_FUNC_ARG; + + /* 2 for version */ + totalLen += 2; + /* 2 for length */ + totalLen += 2; + /* 1 for configId */ + totalLen += 1; + /* 2 for kemId */ + totalLen += 2; + /* 2 for hpke_len */ + totalLen += 2; + + /* hpke_pub_key */ + switch (config->kemId) { + case DHKEM_P256_HKDF_SHA256: + totalLen += DHKEM_P256_ENC_LEN; + break; + case DHKEM_P384_HKDF_SHA384: + totalLen += DHKEM_P384_ENC_LEN; + break; + case DHKEM_P521_HKDF_SHA512: + totalLen += DHKEM_P521_ENC_LEN; + break; + case DHKEM_X25519_HKDF_SHA256: + totalLen += DHKEM_X25519_ENC_LEN; + break; + case DHKEM_X448_HKDF_SHA512: + totalLen += DHKEM_X448_ENC_LEN; + break; + } + + /* cipherSuitesLen */ + totalLen += 2; + /* cipherSuites */ + totalLen += config->numCipherSuites * 4; + /* public name len */ + totalLen += 2; + + /* public name */ + totalLen += XSTRLEN(config->publicName); + /* trailing zeros */ + totalLen += 2; + + if (output == NULL) { + *outputLen = totalLen; + return WC_NO_ERR_TRACE(LENGTH_ONLY_E); + } + + if (totalLen > *outputLen) { + *outputLen = totalLen; + return INPUT_SIZE_E; + } + + /* version */ + c16toa(TLSX_ECH, output); + output += 2; + + /* length - 4 for version and length itself */ + c16toa(totalLen - 4, output); + output += 2; + + /* configId */ + *output = config->configId; + output++; + /* kemId */ + c16toa(config->kemId, output); + output += 2; + + /* length and key itself */ + switch (config->kemId) { + case DHKEM_P256_HKDF_SHA256: + c16toa(DHKEM_P256_ENC_LEN, output); + output += 2; + XMEMCPY(output, config->receiverPubkey, DHKEM_P256_ENC_LEN); + output += DHKEM_P256_ENC_LEN; + break; + case DHKEM_P384_HKDF_SHA384: + c16toa(DHKEM_P384_ENC_LEN, output); + output += 2; + XMEMCPY(output, config->receiverPubkey, DHKEM_P384_ENC_LEN); + output += DHKEM_P384_ENC_LEN; + break; + case DHKEM_P521_HKDF_SHA512: + c16toa(DHKEM_P521_ENC_LEN, output); + output += 2; + XMEMCPY(output, config->receiverPubkey, DHKEM_P521_ENC_LEN); + output += DHKEM_P521_ENC_LEN; + break; + case DHKEM_X25519_HKDF_SHA256: + c16toa(DHKEM_X25519_ENC_LEN, output); + output += 2; + XMEMCPY(output, config->receiverPubkey, DHKEM_X25519_ENC_LEN); + output += DHKEM_X25519_ENC_LEN; + break; + case DHKEM_X448_HKDF_SHA512: + c16toa(DHKEM_X448_ENC_LEN, output); + output += 2; + XMEMCPY(output, config->receiverPubkey, DHKEM_X448_ENC_LEN); + output += DHKEM_X448_ENC_LEN; + break; + } + + /* cipherSuites len */ + c16toa(config->numCipherSuites * 4, output); + output += 2; + + /* cipherSuites */ + for (i = 0; i < config->numCipherSuites; i++) { + c16toa(config->cipherSuites[i].kdfId, output); + output += 2; + c16toa(config->cipherSuites[i].aeadId, output); + output += 2; + } + + /* set maximum name length to 0 */ + *output = 0; + output++; + + /* publicName len */ + *output = XSTRLEN(config->publicName); + output++; + + /* publicName */ + XMEMCPY(output, config->publicName, + XSTRLEN(config->publicName)); + output += XSTRLEN(config->publicName); + + /* terminating zeros */ + c16toa(0, output); + /* output += 2; */ + + *outputLen = totalLen; + + return 0; +} + +/* wrapper function to get ech configs from application code */ +int wolfSSL_GetEchConfigs(WOLFSSL* ssl, byte* output, word32* outputLen) +{ + if (ssl == NULL || outputLen == NULL) + return BAD_FUNC_ARG; + + /* if we don't have ech configs */ + if (ssl->options.useEch != 1) { + return WOLFSSL_FATAL_ERROR; + } + + return GetEchConfigsEx(ssl->echConfigs, output, outputLen); +} + +void wolfSSL_SetEchEnable(WOLFSSL* ssl, byte enable) +{ + if (ssl != NULL) { + ssl->options.disableECH = !enable; + if (ssl->options.disableECH) { + TLSX_Remove(&ssl->extensions, TLSX_ECH, ssl->heap); + FreeEchConfigs(ssl->echConfigs, ssl->heap); + ssl->echConfigs = NULL; + } + } +} + +int SetEchConfigsEx(WOLFSSL_EchConfig** outputConfigs, void* heap, + const byte* echConfigs, word32 echConfigsLen) +{ + int ret = 0; + int i; + int j; + word16 totalLength; + word16 version; + word16 length; + word16 hpkePubkeyLen; + word16 cipherSuitesLen; + word16 publicNameLen; + WOLFSSL_EchConfig* configList = NULL; + WOLFSSL_EchConfig* workingConfig = NULL; + WOLFSSL_EchConfig* lastConfig = NULL; + byte* echConfig = NULL; + + if (outputConfigs == NULL || echConfigs == NULL || echConfigsLen == 0) + return BAD_FUNC_ARG; + + /* check that the total length is well formed */ + ato16(echConfigs, &totalLength); + + if (totalLength != echConfigsLen - 2) { + return WOLFSSL_FATAL_ERROR; + } + + /* skip the total length uint16_t */ + i = 2; + + do { + echConfig = (byte*)echConfigs + i; + ato16(echConfig, &version); + ato16(echConfig + 2, &length); + + /* if the version does not match */ + if (version != TLSX_ECH) { + /* we hit the end of the configs */ + if ( (word32)i + 2 >= echConfigsLen ) { + break; + } + + /* skip this config, +4 for version and length */ + i += length + 4; + continue; + } + + /* check if the length will overrun the buffer */ + if ((word32)i + length + 4 > echConfigsLen) { + break; + } + + if (workingConfig == NULL) { + workingConfig = + (WOLFSSL_EchConfig*)XMALLOC(sizeof(WOLFSSL_EchConfig), heap, + DYNAMIC_TYPE_TMP_BUFFER); + configList = workingConfig; + if (workingConfig != NULL) { + workingConfig->next = NULL; + } + } + else { + lastConfig = workingConfig; + workingConfig->next = + (WOLFSSL_EchConfig*)XMALLOC(sizeof(WOLFSSL_EchConfig), + heap, DYNAMIC_TYPE_TMP_BUFFER); + workingConfig = workingConfig->next; + } + + if (workingConfig == NULL) { + ret = MEMORY_E; + break; + } + + XMEMSET(workingConfig, 0, sizeof(WOLFSSL_EchConfig)); + + /* rawLen */ + workingConfig->rawLen = length + 4; + + /* raw body */ + workingConfig->raw = (byte*)XMALLOC(workingConfig->rawLen, + heap, DYNAMIC_TYPE_TMP_BUFFER); + if (workingConfig->raw == NULL) { + ret = MEMORY_E; + break; + } + + XMEMCPY(workingConfig->raw, echConfig, workingConfig->rawLen); + + /* skip over version and length */ + echConfig += 4; + + /* configId, 1 byte */ + workingConfig->configId = *(echConfig); + echConfig++; + /* kemId, 2 bytes */ + ato16(echConfig, &workingConfig->kemId); + echConfig += 2; + /* hpke public_key length, 2 bytes */ + ato16(echConfig, &hpkePubkeyLen); + echConfig += 2; + /* hpke public_key */ + XMEMCPY(workingConfig->receiverPubkey, echConfig, hpkePubkeyLen); + echConfig += hpkePubkeyLen; + /* cipherSuitesLen */ + ato16(echConfig, &cipherSuitesLen); + + workingConfig->cipherSuites = (EchCipherSuite*)XMALLOC(cipherSuitesLen, + heap, DYNAMIC_TYPE_TMP_BUFFER); + if (workingConfig->cipherSuites == NULL) { + ret = MEMORY_E; + break; + } + + echConfig += 2; + workingConfig->numCipherSuites = cipherSuitesLen / 4; + /* cipherSuites */ + for (j = 0; j < workingConfig->numCipherSuites; j++) { + ato16(echConfig + j * 4, &workingConfig->cipherSuites[j].kdfId); + ato16(echConfig + j * 4 + 2, + &workingConfig->cipherSuites[j].aeadId); + } + echConfig += cipherSuitesLen; + /* ignore the maximum name length */ + echConfig++; + /* publicNameLen */ + publicNameLen = *(echConfig); + workingConfig->publicName = (char*)XMALLOC(publicNameLen + 1, + heap, DYNAMIC_TYPE_TMP_BUFFER); + if (workingConfig->publicName == NULL) { + ret = MEMORY_E; + break; + } + echConfig++; + /* publicName */ + XMEMCPY(workingConfig->publicName, echConfig, publicNameLen); + /* null terminated */ + workingConfig->publicName[publicNameLen] = 0; + + /* add length to go to next config, +4 for version and length */ + i += length + 4; + + /* check that we support this config */ + for (j = 0; j < HPKE_SUPPORTED_KEM_LEN; j++) { + if (hpkeSupportedKem[j] == workingConfig->kemId) + break; + } + + /* if we don't support the kem or at least one cipher suite */ + if (j >= HPKE_SUPPORTED_KEM_LEN || + EchConfigGetSupportedCipherSuite(workingConfig) < 0) + { + XFREE(workingConfig->cipherSuites, heap, + DYNAMIC_TYPE_TMP_BUFFER); + XFREE(workingConfig->publicName, heap, + DYNAMIC_TYPE_TMP_BUFFER); + XFREE(workingConfig->raw, heap, DYNAMIC_TYPE_TMP_BUFFER); + workingConfig = lastConfig; + } + } while ((word32)i < echConfigsLen); + + /* if we found valid configs */ + if (ret == 0 && configList != NULL) { + *outputConfigs = configList; + + return ret; + } + + workingConfig = configList; + + while (workingConfig != NULL) { + lastConfig = workingConfig; + workingConfig = workingConfig->next; + + XFREE(lastConfig->cipherSuites, heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(lastConfig->publicName, heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(lastConfig->raw, heap, DYNAMIC_TYPE_TMP_BUFFER); + + XFREE(lastConfig, heap, DYNAMIC_TYPE_TMP_BUFFER); + } + + if (ret == 0) + return WOLFSSL_FATAL_ERROR; + + return ret; +} + +/* get the raw ech configs from our linked list of ech config structs */ +int GetEchConfigsEx(WOLFSSL_EchConfig* configs, byte* output, word32* outputLen) +{ + int ret = 0; + WOLFSSL_EchConfig* workingConfig = NULL; + byte* outputStart = output; + word32 totalLen = 2; + word32 workingOutputLen = 0; + + if (configs == NULL || outputLen == NULL || + (output != NULL && *outputLen < totalLen)) { + return BAD_FUNC_ARG; + } + + + /* skip over total length which we fill in later */ + if (output != NULL) { + workingOutputLen = *outputLen - totalLen; + output += 2; + } + else { + /* caller getting the size only, set current 2 byte length size */ + *outputLen = totalLen; + } + + workingConfig = configs; + + while (workingConfig != NULL) { + /* get this config */ + ret = GetEchConfig(workingConfig, output, &workingOutputLen); + + if (output != NULL) + output += workingOutputLen; + + /* add this config's length to the total length */ + totalLen += workingOutputLen; + + if (totalLen > *outputLen) + workingOutputLen = 0; + else + workingOutputLen = *outputLen - totalLen; + + /* only error we break on, other 2 we need to keep finding length */ + if (ret == WC_NO_ERR_TRACE(BAD_FUNC_ARG)) + return BAD_FUNC_ARG; + + workingConfig = workingConfig->next; + } + + if (output == NULL) { + *outputLen = totalLen; + return WC_NO_ERR_TRACE(LENGTH_ONLY_E); + } + + if (totalLen > *outputLen) { + *outputLen = totalLen; + return INPUT_SIZE_E; + } + + /* total size -2 for size itself */ + c16toa(totalLen - 2, outputStart); + + *outputLen = totalLen; + + return WOLFSSL_SUCCESS; +} + +#endif /* WOLFSSL_TLS13 && HAVE_ECH */ + +#endif /* !WOLFSSL_SSL_ECH_INCLUDED */ + diff --git a/src/ssl_load.c b/src/ssl_load.c index e9e6862955..f63fd18c31 100644 --- a/src/ssl_load.c +++ b/src/ssl_load.c @@ -928,7 +928,8 @@ static int ProcessBufferTryDecodeDilithium(WOLFSSL_CTX* ctx, WOLFSSL* ssl, if (ret == 0) { /* Decode as a Dilithium private key. */ idx = 0; - ret = wc_Dilithium_PrivateKeyDecode(der->buffer, &idx, key, der->length); + ret = wc_Dilithium_PrivateKeyDecode(der->buffer, &idx, key, + der->length); if (ret == 0) { ret = dilithium_get_oid_sum(key, &keyFormatTemp); if (ret == 0) { @@ -1079,11 +1080,9 @@ static int ProcessBufferTryDecode(WOLFSSL_CTX* ctx, WOLFSSL* ssl, } #ifdef WC_RSA_PSS if((ret == 0) && (*keyFormat == RSAPSSk)) { - /* - Require logic to verify that the der is RSAPSSk (when *keyFormat == RSAPSSK), - and to detect that the der is RSAPSSk (when *keyFormat == 0). - */ - + /* Require logic to verify that the der is RSAPSSk + * (when *keyFormat == RSAPSSK), and to detect that the der is RSAPSSk + * (when *keyFormat == 0). */ matchAnyKey = 1; } #endif /* WC_RSA_PSS */ @@ -2138,7 +2137,8 @@ static int ProcessBufferCertHandleDer(WOLFSSL_CTX* ctx, WOLFSSL* ssl, * certificates so we can inject them at verification time */ if (ret == 1 && ctx->doAppleNativeCertValidationFlag == 1) { WOLFSSL_MSG("ANCV Test: Appending CA to cert list"); - ret = wolfSSL_TestAppleNativeCertValidation_AppendCA(ctx, derBuf, (int)derLen); + ret = wolfSSL_TestAppleNativeCertValidation_AppendCA(ctx, derBuf, + (int)derLen); if (ret == WOLFSSL_SUCCESS) { WOLFSSL_MSG("ANCV Test: Clearing CA table"); /* Clear the CA table so we can ensure they won't be used for @@ -2949,8 +2949,8 @@ int wolfSSL_CTX_load_verify_locations_ex(WOLFSSL_CTX* ctx, const char* file, NULL, verify); #else /* Load the DER formatted CA file */ - ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_ASN1, CA_TYPE, NULL, 0, - NULL, verify); + ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_ASN1, CA_TYPE, NULL, + 0, NULL, verify); #endif #ifndef NO_WOLFSSL_DIR if (ret == 1) { @@ -3234,8 +3234,8 @@ int wolfSSL_CTX_use_certificate_chain_file(WOLFSSL_CTX* ctx, const char* file) ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, CERT_TYPE, NULL, 1, NULL, GET_VERIFY_SETTING_CTX(ctx)); #else - ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, NULL, 1, NULL, - GET_VERIFY_SETTING_CTX(ctx)); + ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_ASN1, CERT_TYPE, NULL, 1, + NULL, GET_VERIFY_SETTING_CTX(ctx)); #endif /* Return 1 on success or 0 on failure. */ @@ -4871,7 +4871,8 @@ static int wolfssl_ctx_add_to_chain(WOLFSSL_CTX* ctx, const byte* der, if (res == 1) { /* Add chain to DER buffer. */ - res = wolfssl_add_to_chain(&ctx->certChain, 1, der, (word32)derSz, ctx->heap); + res = wolfssl_add_to_chain(&ctx->certChain, 1, der, (word32)derSz, + ctx->heap); #ifdef WOLFSSL_TLS13 /* Update count of certificates. */ ctx->certChainCnt++; @@ -5417,7 +5418,8 @@ int wolfSSL_CTX_set_default_verify_paths(WOLFSSL_CTX* ctx) } #else /* OpenSSL's implementation of this API does not require loading the - system CA cert directory. Allow skipping this without erroring out. */ + * system CA cert directory. Allow skipping this without erroring out. + */ ret = 1; #endif } @@ -5538,8 +5540,10 @@ int wolfSSL_SetTmpDH(WOLFSSL* ssl, const unsigned char* p, int pSz, if (ret == 1) { /* Allocate buffers for p and g to be assigned into SSL. */ - pAlloc = (byte*)XMALLOC((size_t)pSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); - gAlloc = (byte*)XMALLOC((size_t)gSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY); + pAlloc = (byte*)XMALLOC((size_t)pSz, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + gAlloc = (byte*)XMALLOC((size_t)gSz, ssl->heap, + DYNAMIC_TYPE_PUBLIC_KEY); if ((pAlloc == NULL) || (gAlloc == NULL)) { /* Memory will be freed below in the (ret != 1) block */ ret = MEMORY_E; @@ -5590,7 +5594,8 @@ static int wolfssl_check_dh_key(unsigned char* p, int pSz, unsigned char* g, /* Initialize a DH object. */ if ((ret = wc_InitDhKey(checkKey)) == 0) { /* Check DH parameters. */ - ret = wc_DhSetCheckKey(checkKey, p, (word32)pSz, g, (word32)gSz, NULL, 0, 0, &rng); + ret = wc_DhSetCheckKey(checkKey, p, (word32)pSz, g, (word32)gSz, + NULL, 0, 0, &rng); /* Dispose of DH object. */ wc_FreeDhKey(checkKey); } @@ -5686,8 +5691,10 @@ int wolfSSL_CTX_SetTmpDH(WOLFSSL_CTX* ctx, const unsigned char* p, int pSz, if (ret == 1) { /* Allocate buffers for p and g to be assigned into SSL context. */ - pAlloc = (byte*)XMALLOC((size_t)pSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); - gAlloc = (byte*)XMALLOC((size_t)gSz, ctx->heap, DYNAMIC_TYPE_PUBLIC_KEY); + pAlloc = (byte*)XMALLOC((size_t)pSz, ctx->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + gAlloc = (byte*)XMALLOC((size_t)gSz, ctx->heap, + DYNAMIC_TYPE_PUBLIC_KEY); if ((pAlloc == NULL) || (gAlloc == NULL)) { ret = MEMORY_E; } diff --git a/src/ssl_p7p12.c b/src/ssl_p7p12.c index 7fc44a4b97..0b43d71e6d 100644 --- a/src/ssl_p7p12.c +++ b/src/ssl_p7p12.c @@ -1029,7 +1029,8 @@ int wolfSSL_PEM_write_bio_PKCS7(WOLFSSL_BIO* bio, PKCS7* p7) XMEMSET(pem, 0, pemSz); - if (wc_DerToPemEx(output, outputSz, pem, (word32)pemSz, NULL, CERT_TYPE) < 0) { + if (wc_DerToPemEx(output, outputSz, pem, (word32)pemSz, NULL,CERT_TYPE) + < 0) { goto error; } if ((wolfSSL_BIO_write(bio, pem, pemSz) == pemSz)) { @@ -1368,8 +1369,8 @@ PKCS7* wolfSSL_SMIME_read_PKCS7(WOLFSSL_BIO* in, WOLFSSL_MSG("Error base64 decoding S/MIME message."); goto error; } - pkcs7 = wolfSSL_d2i_PKCS7_only(NULL, (const unsigned char**)&out, (int)outLen, - bcontMem, (word32)bcontMemSz); + pkcs7 = wolfSSL_d2i_PKCS7_only(NULL, (const unsigned char**)&out, + (int)outLen, bcontMem, (word32)bcontMemSz); wc_MIME_free_hdrs(allHdrs); XFREE(outHead, NULL, DYNAMIC_TYPE_PKCS7); @@ -1912,7 +1913,8 @@ int wolfSSL_PKCS12_parse(WC_PKCS12* pkcs12, const char* psw, DYNAMIC_TYPE_X509); InitX509(x509, 1, heap); InitDecodedCert(DeCert, current->buffer, current->bufferSz, heap); - if (ParseCertRelative(DeCert, CERT_TYPE, NO_VERIFY, NULL, NULL) != 0) { + if (ParseCertRelative(DeCert, CERT_TYPE, NO_VERIFY, NULL, NULL) + != 0) { WOLFSSL_MSG("Issue with parsing certificate"); FreeDecodedCert(DeCert); wolfSSL_X509_free(x509); diff --git a/src/ssl_sess.c b/src/ssl_sess.c index ac368c9b66..cff0046289 100644 --- a/src/ssl_sess.c +++ b/src/ssl_sess.c @@ -968,7 +968,8 @@ WOLFSSL_SESSION* wolfSSL_GetSessionClient(WOLFSSL* ssl, const byte* id, int len) } /* start from most recently used */ - count = (int)min((word32)ClientCache[row].totalCount, CLIENT_SESSIONS_PER_ROW); + count = (int)min((word32)ClientCache[row].totalCount, + CLIENT_SESSIONS_PER_ROW); idx = ClientCache[row].nextIdx - 1; if (idx < 0 || idx >= CLIENT_SESSIONS_PER_ROW) { /* if back to front, the previous was end */ @@ -997,7 +998,8 @@ WOLFSSL_SESSION* wolfSSL_GetSessionClient(WOLFSSL* ssl, const byte* id, int len) #else current = &sessRow->Sessions[clSess[idx].serverIdx]; #endif - if (current && XMEMCMP(current->serverID, id, (unsigned long)len) == 0) { + if (current && XMEMCMP(current->serverID, id, + (unsigned long)len) == 0) { WOLFSSL_MSG("Found a serverid match for client"); if (LowResTimer() < (current->bornOn + current->timeout)) { WOLFSSL_MSG("Session valid"); @@ -1265,8 +1267,8 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) #endif if (output->ticketLenAlloc) XFREE(output->ticket, output->heap, DYNAMIC_TYPE_SESSION_TICK); - output->ticket = tmpTicket; /* cppcheck-suppress autoVariables - */ + /* cppcheck-suppress autoVariables */ + output->ticket = tmpTicket; output->ticketLenAlloc = PREALLOC_SESSION_TICKET_LEN; output->ticketLen = 0; tmpBufSet = 1; @@ -1394,7 +1396,8 @@ int wolfSSL_GetSessionFromCache(WOLFSSL* ssl, WOLFSSL_SESSION* output) output->ticketLen = 0; } if (error == WOLFSSL_SUCCESS) { - XMEMCPY(output->ticket, tmpTicket, output->ticketLen); /* cppcheck-suppress uninitvar */ + /* cppcheck-suppress uninitvar */ + XMEMCPY(output->ticket, tmpTicket, output->ticketLen); } } WC_FREE_VAR_EX(tmpTicket, output->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -1839,8 +1842,9 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, if (SESSION_ROW_WR_LOCK(sessRow) != 0) { #ifdef HAVE_SESSION_TICKET XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); - #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && \ + FIPS_VERSION_GE(5,3))) XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); #endif #endif @@ -1879,8 +1883,9 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, if (cacheSession == NULL) { #ifdef HAVE_SESSION_TICKET XFREE(ticBuff, NULL, DYNAMIC_TYPE_SESSION_TICK); - #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ - (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && FIPS_VERSION_GE(5,3))) + #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_TICKET_NONCE_MALLOC) && \ + (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && \ + FIPS_VERSION_GE(5,3))) XFREE(preallocNonce, addSession->heap, DYNAMIC_TYPE_SESSION_TICK); #endif #endif @@ -2028,8 +2033,8 @@ int AddSessionToCache(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* addSession, #ifndef NO_CLIENT_CACHE if (ret == 0 && clientCacheEntry != NULL) { - ClientSession* clientCache = AddSessionToClientCache(side, row, (int)idx, - addSession->serverID, addSession->idLen, id, useTicket); + ClientSession* clientCache = AddSessionToClientCache(side, row, + (int)idx, addSession->serverID, addSession->idLen, id, useTicket); if (clientCache != NULL) *clientCacheEntry = clientCache; } @@ -4088,7 +4093,8 @@ void wolfSSL_FreeSession(WOLFSSL_CTX* ctx, WOLFSSL_SESSION* session) ForceZero(session->sessionID, ID_LEN); if (session->type == WOLFSSL_SESSION_TYPE_HEAP) { - XFREE(session, session->heap, DYNAMIC_TYPE_SESSION); /* // NOLINT(clang-analyzer-unix.Malloc) */ + /* // NOLINTNEXTLINE(clang-analyzer-unix.Malloc) */ + XFREE(session, session->heap, DYNAMIC_TYPE_SESSION); } } diff --git a/tests/api/test_ossl_x509_str.c b/tests/api/test_ossl_x509_str.c index 79f1ce5581..d628e08b37 100644 --- a/tests/api/test_ossl_x509_str.c +++ b/tests/api/test_ossl_x509_str.c @@ -36,9 +36,8 @@ #include #include -#if defined(OPENSSL_ALL) && \ - !defined(NO_RSA) && !defined(NO_FILESYSTEM) - +#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \ + !defined(NO_ASN_TIME) static int last_errcodes[10]; static int last_errdepths[10]; static int err_index = 0; @@ -187,8 +186,7 @@ int test_wolfSSL_X509_STORE_check_time(void) wolfSSL_X509_free(cert); cert = NULL; -#if defined(OPENSSL_ALL) && \ - !defined(NO_RSA) && !defined(NO_FILESYSTEM) +#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) err_index = 0; diff --git a/wolfcrypt/src/evp_pk.c b/wolfcrypt/src/evp_pk.c new file mode 100644 index 0000000000..27801f010c --- /dev/null +++ b/wolfcrypt/src/evp_pk.c @@ -0,0 +1,1909 @@ +/* evp_pk.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 + +#if !defined(WOLFSSL_EVP_PK_INCLUDED) + #ifndef WOLFSSL_IGNORE_FILE_WARN + #warning evp_pk.c does not need to be compiled separately from ssl.c + #endif +#elif defined(WOLFCRYPT_ONLY) +#else + +/******************************************************************************* + * START OF d2i APIs + ******************************************************************************/ + +#ifndef NO_CERTS + +#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) +/** + * Make an EVP PKEY and put data and type in. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @param [in] type The type of public/private key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2i_make_pkey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + word32 memSz, int priv, int type) +{ + WOLFSSL_EVP_PKEY* pkey; + int ret = 1; + + /* Get or create the EVP PKEY object. */ + if (*out != NULL) { + pkey = *out; + } + else { + pkey = wolfSSL_EVP_PKEY_new(); + if (pkey == NULL) { + WOLFSSL_MSG("wolfSSL_EVP_PKEY_new error"); + return 0; + } + } + + /* Set the size and allocate memory for key data to be copied into. */ + pkey->pkey_sz = (int)memSz; + pkey->pkey.ptr = (char*)XMALLOC((size_t)memSz, NULL, + priv ? DYNAMIC_TYPE_PRIVATE_KEY : DYNAMIC_TYPE_PUBLIC_KEY); + if (pkey->pkey.ptr == NULL) { + ret = 0; + } + if (ret == 1) { + /* Copy in key data, set key type passed in and return object. */ + XMEMCPY(pkey->pkey.ptr, mem, memSz); + pkey->type = type; + *out = pkey; + } + if ((ret == 0) && (*out == NULL)) { + /* Dispose of object allocated in this function. */ + wolfSSL_EVP_PKEY_free(pkey); + } + + return ret; +} + +#if !defined(NO_RSA) +/** + * Try to make an RSA EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryRsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_RSA* rsaObj = NULL; + word32 keyIdx = 0; + int isRsaKey; + int ret = 1; + WC_DECLARE_VAR(rsa, RsaKey, 1, NULL); + + WC_ALLOC_VAR_EX(rsa, RsaKey, 1, NULL, DYNAMIC_TYPE_RSA, return 0); + + XMEMSET(rsa, 0, sizeof(RsaKey)); + + if (wc_InitRsaKey(rsa, NULL) != 0) { + WC_FREE_VAR_EX(rsa, NULL, DYNAMIC_TYPE_RSA); + return 0; + } + /* Try decoding data as an RSA private/public key. */ + if (priv) { + isRsaKey = + (wc_RsaPrivateKeyDecode(mem, &keyIdx, rsa, (word32)memSz) == 0); + } + else { + isRsaKey = + (wc_RsaPublicKeyDecode(mem, &keyIdx, rsa, (word32)memSz) == 0); + } + wc_FreeRsaKey(rsa); + WC_FREE_VAR_EX(rsa, NULL, DYNAMIC_TYPE_RSA); + + if (!isRsaKey) { + return WOLFSSL_FATAL_ERROR; + } + + /* Create RSA key object from data. */ + rsaObj = wolfssl_rsa_d2i(NULL, mem, keyIdx, + priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC); + if (rsaObj == NULL) { + ret = 0; + } + if (ret == 1) { + /* Create an EVP PKEY object. */ + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_RSA); + } + if (ret == 1) { + /* Put RSA key object into EVP PKEY object. */ + (*out)->ownRsa = 1; + (*out)->rsa = rsaObj; + } + if (ret == 0) { + wolfSSL_RSA_free(rsaObj); + } + + return ret; +} +#endif /* !NO_RSA */ + +#if defined(HAVE_ECC) && defined(OPENSSL_EXTRA) +/** + * Try to make an ECC EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryEccKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_EC_KEY* ec = NULL; + word32 keyIdx = 0; + int isEccKey; + int ret = 1; + WC_DECLARE_VAR(ecc, ecc_key, 1, NULL); + + WC_ALLOC_VAR_EX(ecc, ecc_key, 1, NULL, DYNAMIC_TYPE_ECC, return 0); + + XMEMSET(ecc, 0, sizeof(ecc_key)); + + if (wc_ecc_init(ecc) != 0) { + WC_FREE_VAR_EX(ecc, NULL, DYNAMIC_TYPE_ECC); + return 0; + } + + /* Try decoding data as an ECC private/public key. */ + if (priv) { + isEccKey = + (wc_EccPrivateKeyDecode(mem, &keyIdx, ecc, (word32)memSz) == 0); + } + else { + isEccKey = + (wc_EccPublicKeyDecode(mem, &keyIdx, ecc, (word32)memSz) == 0); + } + wc_ecc_free(ecc); + WC_FREE_VAR_EX(ecc, NULL, DYNAMIC_TYPE_ECC); + + if (!isEccKey) { + return WOLFSSL_FATAL_ERROR; + } + + /* Create EC key object from data. */ + ec = wolfSSL_EC_KEY_new(); + if (ec == NULL) { + ret = 0; + } + if ((ret == 1) && (wolfSSL_EC_KEY_LoadDer_ex(ec, mem, keyIdx, + priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC) != 1)) { + ret = 0; + } + if (ret == 1) { + /* Create an EVP PKEY object. */ + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_EC); + } + if (ret == 1) { + /* Put RSA key object into EVP PKEY object. */ + (*out)->ownEcc = 1; + (*out)->ecc = ec; + } + if (ret == 0) { + wolfSSL_EC_KEY_free(ec); + } + + return ret; +} +#endif /* HAVE_ECC && OPENSSL_EXTRA */ + +#if !defined(NO_DSA) +/** + * Try to make a DSA EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryDsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_DSA* dsaObj; + word32 keyIdx = 0; + int isDsaKey; + int ret = 1; + WC_DECLARE_VAR(dsa, DsaKey, 1, NULL); + + WC_ALLOC_VAR_EX(dsa, DsaKey, 1, NULL, DYNAMIC_TYPE_DSA, return 0); + + XMEMSET(dsa, 0, sizeof(DsaKey)); + + if (wc_InitDsaKey(dsa) != 0) { + WC_FREE_VAR_EX(dsa, NULL, DYNAMIC_TYPE_DSA); + return 0; + } + + /* Try decoding data as a DSA private/public key. */ + if (priv) { + isDsaKey = + (wc_DsaPrivateKeyDecode(mem, &keyIdx, dsa, (word32)memSz) == 0); + } + else { + isDsaKey = + (wc_DsaPublicKeyDecode(mem, &keyIdx, dsa, (word32)memSz) == 0); + } + wc_FreeDsaKey(dsa); + WC_FREE_VAR_EX(dsa, NULL, DYNAMIC_TYPE_DSA); + + /* test if DSA key */ + if (!isDsaKey) { + return WOLFSSL_FATAL_ERROR; + } + + /* Create DSA key object from data. */ + dsaObj = wolfSSL_DSA_new(); + if (dsaObj == NULL) { + ret = 0; + } + if ((ret == 1) && (wolfSSL_DSA_LoadDer_ex(dsaObj, mem, keyIdx, + priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC) != 1)) { + ret = 0; + } + if (ret == 1) { + /* Create an EVP PKEY object. */ + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DSA); + } + if (ret == 1) { + /* Put RSA key object into EVP PKEY object. */ + (*out)->ownDsa = 1; + (*out)->dsa = dsaObj; + } + if (ret == 0) { + wolfSSL_DSA_free(dsaObj); + } + + return ret; +} +#endif /* NO_DSA */ + +#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION > 2)) +/** + * Try to make a DH EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_DH* dhObj; + int isDhKey; + word32 keyIdx = 0; + int ret = 1; + WC_DECLARE_VAR(dh, DhKey, 1, NULL); + + WC_ALLOC_VAR_EX(dh, DhKey, 1, NULL, DYNAMIC_TYPE_DH, return 0); + + XMEMSET(dh, 0, sizeof(DhKey)); + + if (wc_InitDhKey(dh) != 0) { + WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH); + return 0; + } + + /* Try decoding data as a DH public key. */ + isDhKey = (wc_DhKeyDecode(mem, &keyIdx, dh, (word32)memSz) == 0); + wc_FreeDhKey(dh); + WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH); + + /* test if DH key */ + if (!isDhKey) { + return WOLFSSL_FATAL_ERROR; + } + + /* Create DH key object from data. */ + dhObj = wolfSSL_DH_new(); + if (dhObj == NULL) { + ret = 0; + } + if ((ret == 1) && (wolfSSL_DH_LoadDer(dhObj, mem, keyIdx) != 1)) { + ret = 0; + } + if (ret == 1) { + /* Create an EVP PKEY object. */ + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DH); + } + if (ret == 1) { + /* Put RSA key object into EVP PKEY object. */ + (*out)->ownDh = 1; + (*out)->dh = dhObj; + } + if (ret == 0) { + wolfSSL_DH_free(dhObj); + } + + return ret; +} +#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ +#endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */ + +#if !defined(NO_DH) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_DH_EXTRA) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION > 2)) +/** + * Try to make a DH EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryAltDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + WOLFSSL_DH* dhObj; + word32 keyIdx = 0; + DhKey* key = NULL; + int elements; + int ret = 1; + + /* Create DH key object from data. */ + dhObj = wolfSSL_DH_new(); + if (dhObj == NULL) { + return 0; + } + + key = (DhKey*)dhObj->internal; + /* Try decoding data as a DH public key. */ + if (wc_DhKeyDecode(mem, &keyIdx, key, (word32)memSz) != 0) { + ret = 0; + } + if (ret == 1) { + /* DH key has data and is external to DH object. */ + elements = ELEMENT_P | ELEMENT_G | ELEMENT_Q | ELEMENT_PUB; + if (priv) { + elements |= ELEMENT_PRV; + } + if (SetDhExternal_ex(dhObj, elements) != WOLFSSL_SUCCESS ) { + ret = 0; + } + } + if (ret == 1) { + /* Create an EVP PKEY object. */ + ret = d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DH); + } + if (ret == 1) { + /* Put RSA key object into EVP PKEY object. */ + (*out)->ownDh = 1; + (*out)->dh = dhObj; + } + if (ret == 0) { + wolfSSL_DH_free(dhObj); + } + + return ret; +} +#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ +#endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */ + +#ifdef HAVE_FALCON +/** + * Attempt to import a private Falcon key at a specified level. + * + * @param [in] falcon Falcon key object. + * @param [in] level Level of Falcon key. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2i_falcon_priv_key_level(falcon_key* falcon, byte level, + const unsigned char* mem, long memSz) +{ + return (wc_falcon_set_level(falcon, level) == 0) && + (wc_falcon_import_private_only(mem, (word32)memSz, falcon) == 0); +} + +/** + * Attempt to import a public Falcon key at a specified level. + * + * @param [in] falcon Falcon key object. + * @param [in] level Level of Falcon key. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2i_falcon_pub_key_level(falcon_key* falcon, byte level, + const unsigned char* mem, long memSz) +{ + return (wc_falcon_set_level(falcon, level) == 0) && + (wc_falcon_import_public(mem, (word32)memSz, falcon) == 0); +} + +/** + * Try to make a Falcon EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryFalconKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + int isFalcon = 0; + WC_DECLARE_VAR(falcon, falcon_key, 1, NULL); + + WC_ALLOC_VAR_EX(falcon, falcon_key, 1, NULL, DYNAMIC_TYPE_FALCON, + return 0); + + if (wc_falcon_init(falcon) != 0) { + WC_FREE_VAR_EX(falcon, NULL, DYNAMIC_TYPE_FALCON); + return 0; + } + + /* Try decoding data as a Falcon private/public key. */ + if (priv) { + /* Try level 1 */ + isFalcon = d2i_falcon_priv_key_level(falcon, 1, mem, memSz); + if (!isFalcon) { + /* Try level 5 */ + isFalcon = d2i_falcon_priv_key_level(falcon, 5, mem, memSz); + } + } + else { + /* Try level 1 */ + isFalcon = d2i_falcon_pub_key_level(falcon, 1, mem, memSz); + if (!isFalcon) { + /* Try level 5 */ + isFalcon = d2i_falcon_pub_key_level(falcon, 5, mem, memSz); + } + } + /* Dispose of any Falcon key created. */ + wc_falcon_free(falcon); + WC_FREE_VAR_EX(falcon, NULL, DYNAMIC_TYPE_FALCON); + + if (!isFalcon) { + return WOLFSSL_FATAL_ERROR; + } + + /* Create an EVP PKEY object. */ + return d2i_make_pkey(out, NULL, 0, priv, WC_EVP_PKEY_FALCON); +} +#endif /* HAVE_FALCON */ + +#ifdef HAVE_DILITHIUM +/** + * Attempt to import a private Dilithium key at a specified level. + * + * @param [in] dilithium Dilithium key object. + * @param [in] level Level of Dilithium key. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2i_dilithium_priv_key_level(dilithium_key* dilithium, byte level, + const unsigned char* mem, long memSz) +{ + return (wc_dilithium_set_level(dilithium, level) == 0) && + (wc_dilithium_import_private(mem, (word32)memSz, dilithium) == 0); +} + +/** + * Attempt to import a public Dilithium key at a specified level. + * + * @param [in] dilithium Dilithium key object. + * @param [in] level Level of Dilithium key. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2i_dilithium_pub_key_level(dilithium_key* dilithium, byte level, + const unsigned char* mem, long memSz) +{ + return (wc_dilithium_set_level(dilithium, level) == 0) && + (wc_dilithium_import_public(mem, (word32)memSz, dilithium) == 0); +} + +/** + * Try to make a Dilithium EVP PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static int d2iTryDilithiumKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, + long memSz, int priv) +{ + int isDilithium = 0; + WC_DECLARE_VAR(dilithium, dilithium_key, 1, NULL); + + WC_ALLOC_VAR_EX(dilithium, dilithium_key, 1, NULL, DYNAMIC_TYPE_DILITHIUM, + return 0); + + if (wc_dilithium_init(dilithium) != 0) { + WC_FREE_VAR_EX(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM); + return 0; + } + + /* Try decoding data as a Dilithium private/public key. */ + if (priv) { + isDilithium = d2i_dilithium_priv_key_level(dilithium, WC_ML_DSA_44, + mem, memSz); + if (!isDilithium) { + isDilithium = d2i_dilithium_priv_key_level(dilithium, WC_ML_DSA_65, + mem, memSz); + } + if (!isDilithium) { + isDilithium = d2i_dilithium_priv_key_level(dilithium, WC_ML_DSA_87, + mem, memSz); + } + } + else { + isDilithium = d2i_dilithium_pub_key_level(dilithium, WC_ML_DSA_44, + mem, memSz); + if (!isDilithium) { + isDilithium = d2i_dilithium_pub_key_level(dilithium, WC_ML_DSA_65, + mem, memSz); + } + if (!isDilithium) { + isDilithium = d2i_dilithium_pub_key_level(dilithium, WC_ML_DSA_87, + mem, memSz); + } + } + /* Dispose of any Dilithium key created. */ + wc_dilithium_free(dilithium); + WC_FREE_VAR_EX(dilithium, NULL, DYNAMIC_TYPE_DILITHIUM); + + if (!isDilithium) { + return WOLFSSL_FATAL_ERROR; + } + + /* Create an EVP PKEY object. */ + return d2i_make_pkey(out, NULL, 0, priv, WC_EVP_PKEY_DILITHIUM); +} +#endif /* HAVE_DILITHIUM */ + +/** + * Try to make a WOLFSSL_EVP_PKEY from data. + * + * @param [in, out] out On in, an EVP PKEY or NULL. + * On out, an EVP PKEY or NULL. + * @param [in] mem Memory containing key data. + * @param [in] memSz Size of key data in bytes. + * @param [in] priv 1 means private key, 0 means public key. + * @return 1 on success. + * @return 0 otherwise. + */ +static WOLFSSL_EVP_PKEY* d2i_evp_pkey_try(WOLFSSL_EVP_PKEY** out, + const unsigned char** in, long inSz, int priv) +{ + WOLFSSL_EVP_PKEY* pkey = NULL; + + WOLFSSL_ENTER("d2i_evp_pkey_try"); + + if (in == NULL || *in == NULL || inSz < 0) { + WOLFSSL_MSG("Bad argument"); + return NULL; + } + + if ((out != NULL) && (*out != NULL)) { + pkey = *out; + } + +#if !defined(NO_RSA) + if (d2iTryRsaKey(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* NO_RSA */ +#if defined(HAVE_ECC) && defined(OPENSSL_EXTRA) + if (d2iTryEccKey(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* HAVE_ECC && OPENSSL_EXTRA */ +#if !defined(NO_DSA) + if (d2iTryDsaKey(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* NO_DSA */ +#if !defined(NO_DH) && (defined(WOLFSSL_QT) || defined(OPENSSL_ALL)) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION > 2)) + if (d2iTryDhKey(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ +#endif /* !NO_DH && (WOLFSSL_QT || OPENSSL_ALL) */ + +#if !defined(NO_DH) && defined(OPENSSL_EXTRA) && defined(WOLFSSL_DH_EXTRA) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION > 2)) + if (d2iTryAltDhKey(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ +#endif /* !NO_DH && OPENSSL_EXTRA && WOLFSSL_DH_EXTRA */ + +#ifdef HAVE_FALCON + if (d2iTryFalconKey(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* HAVE_FALCON */ +#ifdef HAVE_DILITHIUM + if (d2iTryDilithiumKey(&pkey, *in, inSz, priv) >= 0) { + ; + } + else +#endif /* HAVE_DILITHIUM */ + { + WOLFSSL_MSG("d2i_evp_pkey_try couldn't determine key type"); + } + + if ((pkey != NULL) && (out != NULL)) { + *out = pkey; + } + return pkey; +} +#endif /* OPENSSL_EXTRA || WPA_SMALL */ + +#ifdef OPENSSL_EXTRA +/* Converts a DER encoded public key to a WOLFSSL_EVP_PKEY structure. + * + * @param [in, out] out Pointer to new WOLFSSL_EVP_PKEY structure. + * Can be NULL. + * @param [in, out] in DER buffer to convert. + * @param [in] inSz Size of in buffer. + * @return Pointer to a new WOLFSSL_EVP_PKEY structure on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY(WOLFSSL_EVP_PKEY** out, + const unsigned char** in, long inSz) +{ + WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY"); + return d2i_evp_pkey_try(out, in, inSz, 0); +} + +#ifndef NO_BIO +/* Converts a DER encoded public key in a BIO to a WOLFSSL_EVP_PKEY structure. + * + * @param [in] bio BIO to read DER from. + * @param [out] out New WOLFSSL_EVP_PKEY pointer when not NULL. + * @return Pointer to a new WOLFSSL_EVP_PKEY structure on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PUBKEY_bio(WOLFSSL_BIO* bio, + WOLFSSL_EVP_PKEY** out) +{ + unsigned char* mem; + long memSz; + WOLFSSL_EVP_PKEY* pkey = NULL; + + WOLFSSL_ENTER("wolfSSL_d2i_PUBKEY_bio"); + + /* Validate parameters. */ + if (bio == NULL) { + return NULL; + } + + /* Get length of data in BIO. */ + memSz = wolfSSL_BIO_get_len(bio); + if (memSz <= 0) { + return NULL; + } + /* Allocate memory to read all of BIO data into. */ + mem = (unsigned char*)XMALLOC((size_t)memSz, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (mem == NULL) { + return NULL; + } + /* Read all data into allocated buffer. */ + if (wolfSSL_BIO_read(bio, mem, (int)memSz) == memSz) { + /* Create a WOLFSSL_EVP_PKEY from data. */ + pkey = wolfSSL_d2i_PUBKEY(NULL, (const unsigned char**)&mem, memSz); + if (out != NULL && pkey != NULL) { + /* Return new WOLFSSL_EVP_PKEY through parameter. */ + *out = pkey; + } + } + + /* Dispose of memory holding BIO data. */ + XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return pkey; +} +#endif /* !NO_BIO */ +#endif /* OPENSSL_EXTRA */ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \ + defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_QT) || defined(WOLFSSL_WPAS_SMALL) +/* Converts a DER encoded private key to a WOLFSSL_EVP_PKEY structure. + * + * @param [in, out] out Pointer to new WOLFSSL_EVP_PKEY structure. + * Can be NULL. + * @param [in, out] in DER buffer to convert. + * @param [in] inSz Size of in buffer. + * @return Pointer to a new WOLFSSL_EVP_PKEY structure on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_EVP(WOLFSSL_EVP_PKEY** out, + unsigned char** in, long inSz) +{ + WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_EVP"); + return d2i_evp_pkey_try(out, (const unsigned char**)in, inSz, 1); +} +#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_QT || + * WOLFSSL_WPAS_SMALL*/ + +#if defined(OPENSSL_ALL) || defined(WOLFSSL_ASIO) || \ + defined(WOLFSSL_HAPROXY) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_QT) + +#ifndef NO_BIO +/* Converts a DER encoded private key in a BIO to a WOLFSSL_EVP_PKEY structure. + * + * @param [in] bio BIO to read DER from. + * @param [out] out New WOLFSSL_EVP_PKEY pointer when not NULL. + * @return Pointer to a new WOLFSSL_EVP_PKEY structure on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_bio(WOLFSSL_BIO* bio, + WOLFSSL_EVP_PKEY** out) +{ + unsigned char* mem = NULL; + int memSz = 0; + WOLFSSL_EVP_PKEY* key = NULL; + + WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey_bio"); + + /* Validate parameters. */ + if (bio == NULL) { + return NULL; + } + + /* Get length of data in BIO. */ + memSz = wolfSSL_BIO_get_len(bio); + if (memSz <= 0) { + WOLFSSL_MSG("wolfSSL_BIO_get_len() failure"); + return NULL; + } + /* Allocate memory to read all of BIO data into. */ + mem = (unsigned char*)XMALLOC((size_t)memSz, bio->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (mem == NULL) { + WOLFSSL_MSG("Malloc failure"); + return NULL; + } + + /* Read all of data. */ + if (wolfSSL_BIO_read(bio, (unsigned char*)mem, memSz) == memSz) { + /* Determines key type and returns the new private EVP_PKEY object */ + if ((key = wolfSSL_d2i_PrivateKey_EVP(NULL, &mem, (long)memSz)) == + NULL) { + WOLFSSL_MSG("wolfSSL_d2i_PrivateKey_EVP() failure"); + XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + + /* Write extra data back into bio object if necessary. */ + if (memSz > key->pkey_sz) { + wolfSSL_BIO_write(bio, mem + key->pkey_sz, memSz - key->pkey_sz); + if (wolfSSL_BIO_get_len(bio) <= 0) { + WOLFSSL_MSG("Failed to write memory to bio"); + XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + } + + /* Return key through parameter if required. */ + if (out != NULL) { + *out = key; + } + } + + /* Dispose of memory holding BIO data. */ + XFREE(mem, bio->heap, DYNAMIC_TYPE_TMP_BUFFER); + return key; +} +#endif /* !NO_BIO */ + +#endif /* OPENSSL_ALL || WOLFSSL_ASIO || WOLFSSL_HAPROXY || WOLFSSL_NGINX || + * WOLFSSL_QT */ + +#ifdef OPENSSL_EXTRA +/* Reads in a DER format key. If PKCS8 headers are found they are stripped off. + * + * @param [in] type Type of key. + * @param [in, out] out Newly created WOLFSSL_EVP_PKEY structure. + * @param [in, out] in Pointer to input key DER. + * Pointer is advanced the same number of bytes read on + * success. + * @param [in] inSz Size of in buffer. + * @return A non null pointer on success. + * @return NULL on failure. + */ +static WOLFSSL_EVP_PKEY* d2i_evp_pkey(int type, WOLFSSL_EVP_PKEY** out, + const unsigned char **in, long inSz, int priv) +{ + int ret = 0; + word32 idx = 0, algId; + word16 pkcs8HeaderSz = 0; + WOLFSSL_EVP_PKEY* local; + const unsigned char* p; + int opt; + + (void)opt; + + /* Validate parameters. */ + if (in == NULL || inSz < 0) { + WOLFSSL_MSG("Bad argument"); + return NULL; + } + + if (priv == 1) { + /* Check if input buffer has PKCS8 header. In the case that it does not + * have a PKCS8 header then do not error out. */ + if ((ret = ToTraditionalInline_ex((const byte*)(*in), &idx, + (word32)inSz, &algId)) > 0) { + WOLFSSL_MSG("Found PKCS8 header"); + pkcs8HeaderSz = (word16)idx; + + /* Check header algorithm id matches algorithm type passed in. */ + if ((type == WC_EVP_PKEY_RSA && algId != RSAk + #ifdef WC_RSA_PSS + && algId != RSAPSSk + #endif + ) || + (type == WC_EVP_PKEY_EC && algId != ECDSAk) || + (type == WC_EVP_PKEY_DSA && algId != DSAk) || + (type == WC_EVP_PKEY_DH && algId != DHk)) { + WOLFSSL_MSG("PKCS8 does not match EVP key type"); + return NULL; + } + + (void)idx; /* not used */ + } + /* Ensure no error occurred try to remove any PKCS#8 header. */ + else if (ret != WC_NO_ERR_TRACE(ASN_PARSE_E)) { + WOLFSSL_MSG("Unexpected error with trying to remove PKCS8 header"); + return NULL; + } + } + + /* Dispose of any WOLFSSL_EVP_PKEY passed in. */ + if (out != NULL && *out != NULL) { + wolfSSL_EVP_PKEY_free(*out); + *out = NULL; + } + /* Create a new WOLFSSL_EVP_PKEY and populate. */ + local = wolfSSL_EVP_PKEY_new(); + if (local == NULL) { + return NULL; + } + local->type = type; + local->pkey_sz = (int)inSz; + local->pkcs8HeaderSz = pkcs8HeaderSz; + local->pkey.ptr = (char*)XMALLOC((size_t)inSz, NULL, + DYNAMIC_TYPE_PUBLIC_KEY); + if (local->pkey.ptr == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + XMEMCPY(local->pkey.ptr, *in, (size_t)inSz); + p = (const unsigned char*)local->pkey.ptr; + + /* Create an algorithm specific object into WOLFSSL_EVP_PKEY. */ + switch (type) { +#ifndef NO_RSA + case WC_EVP_PKEY_RSA: + /* Create a WOLFSSL_RSA object. */ + local->ownRsa = 1; + opt = priv ? WOLFSSL_RSA_LOAD_PRIVATE : WOLFSSL_RSA_LOAD_PUBLIC; + local->rsa = wolfssl_rsa_d2i(NULL, p, local->pkey_sz, opt); + if (local->rsa == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + break; +#endif /* NO_RSA */ +#ifdef HAVE_ECC + case WC_EVP_PKEY_EC: + /* Create a WOLFSSL_EC object. */ + local->ownEcc = 1; + local->ecc = wolfSSL_EC_KEY_new(); + if (local->ecc == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + opt = priv ? WOLFSSL_EC_KEY_LOAD_PRIVATE : + WOLFSSL_EC_KEY_LOAD_PUBLIC; + if (wolfSSL_EC_KEY_LoadDer_ex(local->ecc, p, local->pkey_sz, opt) != + WOLFSSL_SUCCESS) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + break; +#endif /* HAVE_ECC */ +#if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) || defined(WOLFSSL_OPENSSH) +#ifndef NO_DSA + case WC_EVP_PKEY_DSA: + /* Create a WOLFSSL_DSA object. */ + local->ownDsa = 1; + local->dsa = wolfSSL_DSA_new(); + if (local->dsa == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + opt = priv ? WOLFSSL_DSA_LOAD_PRIVATE : WOLFSSL_DSA_LOAD_PUBLIC; + if (wolfSSL_DSA_LoadDer_ex(local->dsa, p, local->pkey_sz, opt) != + WOLFSSL_SUCCESS) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + break; +#endif /* NO_DSA */ +#ifndef NO_DH +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + case WC_EVP_PKEY_DH: + /* Create a WOLFSSL_DH object. */ + local->ownDh = 1; + local->dh = wolfSSL_DH_new(); + if (local->dh == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + if (wolfSSL_DH_LoadDer(local->dh, p, local->pkey_sz) != + WOLFSSL_SUCCESS) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + break; +#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ +#endif /* HAVE_DH */ +#endif /* WOLFSSL_QT || OPENSSL_ALL || WOLFSSL_OPENSSH */ + default: + WOLFSSL_MSG("Unsupported key type"); + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + + /* Advance pointer and return through parameter when required on success. */ + if (local != NULL) { + if (local->pkey_sz <= (int)inSz) { + *in += local->pkey_sz; + } + if (out != NULL) { + *out = local; + } + } + + /* Return newly allocated WOLFSSL_EVP_PKEY structure. */ + return local; +} + +/* Reads in a DER format key. + * + * @param [in] type Type of key. + * @param [in, out] out Newly created WOLFSSL_EVP_PKEY structure. + * @param [in, out] in Pointer to input key DER. + * Pointer is advanced the same number of bytes read on + * success. + * @param [in] inSz Size of in buffer. + * @return A non null pointer on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PublicKey(int type, WOLFSSL_EVP_PKEY** out, + const unsigned char **in, long inSz) +{ + WOLFSSL_ENTER("wolfSSL_d2i_PublicKey"); + + return d2i_evp_pkey(type, out, in, inSz, 0); +} + +/* Reads in a DER format key. If PKCS8 headers are found they are stripped off. + * + * @param [in] type Type of key. + * @param [in, out] out Newly created WOLFSSL_EVP_PKEY structure. + * @param [in, out] in Pointer to input key DER. + * Pointer is advanced the same number of bytes read on + * success. + * @param [in] inSz Size of in buffer. + * @return A non null pointer on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey(int type, WOLFSSL_EVP_PKEY** out, + const unsigned char **in, long inSz) +{ + WOLFSSL_ENTER("wolfSSL_d2i_PrivateKey"); + + return d2i_evp_pkey(type, out, in, inSz, 1); +} +#endif /* OPENSSL_EXTRA */ + +#ifdef OPENSSL_ALL +/* Detect RSA or EC key and decode private key DER. + * + * @param [in, out] pkey Newly created WOLFSSL_EVP_PKEY structure. + * @param [in, out] pp Pointer to private key DER data. + * @param [in] length Length in bytes of DER data. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_AutoPrivateKey(WOLFSSL_EVP_PKEY** pkey, + const unsigned char** pp, long length) +{ + int ret; + WOLFSSL_EVP_PKEY* key = NULL; + const byte* der = *pp; + word32 idx = 0; + int len = 0; + int cnt = 0; + word32 algId; + word32 keyLen = (word32)length; + + /* Take off PKCS#8 wrapper if found. */ + if ((len = ToTraditionalInline_ex(der, &idx, keyLen, &algId)) >= 0) { + der += idx; + keyLen = (word32)len; + } + + idx = 0; + len = 0; + /* Use the number of elements in the outer sequence to determine key type. + */ + ret = GetSequence(der, &idx, &len, keyLen); + if (ret >= 0) { + word32 end = idx + (word32)len; + while (ret >= 0 && idx < end) { + /* Skip type */ + idx++; + /* Get length and skip over - keeping count */ + len = 0; + ret = GetLength(der, &idx, &len, keyLen); + if (ret >= 0) { + if (idx + (word32)len > end) { + ret = ASN_PARSE_E; + } + else { + idx += (word32)len; + cnt++; + } + } + } + } + + if (ret >= 0) { + int type; + /* ECC includes version, private[, curve][, public key] */ + if (cnt >= 2 && cnt <= 4) { + type = WC_EVP_PKEY_EC; + } + else { + type = WC_EVP_PKEY_RSA; + } + + /* Decode the detected type of private key. */ + key = wolfSSL_d2i_PrivateKey(type, pkey, &der, keyLen); + /* Update the pointer to after the DER data. */ + *pp = der; + } + + return key; +} + +#if !defined(NO_BIO) && !defined(NO_PWDBASED) && defined(HAVE_PKCS8) +/* Read all of the BIO data into a newly allocated buffer. + * + * @param [in] bio BIO to read from. + * @param [out] data Allocated buffer holding all BIO data. + * @return Number of bytes allocated and read. + * @return MEMORY_E on dynamic memory allocation failure. + * @return Other negative on error. + */ +static int bio_get_data(WOLFSSL_BIO* bio, byte** data) +{ + int ret = 0; + byte* mem = NULL; + + /* Get length of data in BIO. */ + ret = wolfSSL_BIO_get_len(bio); + if (ret > 0) { + /* Allocate memory big enough to hold data in BIO. */ + mem = (byte*)XMALLOC((size_t)ret, bio->heap, DYNAMIC_TYPE_OPENSSL); + if (mem == NULL) { + WOLFSSL_MSG("Memory error"); + ret = MEMORY_E; + } + if (ret >= 0) { + /* Read data from BIO. */ + if ((ret = wolfSSL_BIO_read(bio, mem, ret)) <= 0) { + XFREE(mem, bio->heap, DYNAMIC_TYPE_OPENSSL); + ret = MEMORY_E; + mem = NULL; + } + } + } + + /* Return allocated buffer with data from BIO. */ + *data = mem; + return ret; +} + +/* Convert the algorithm id to a key type. + * + * @param [in] algId Algorithm Id. + * @return Key type on success. + * @return WC_EVP_PKEY_NONE when algorithm id not supported. + */ +static int wolfssl_i_alg_id_to_key_type(word32 algId) +{ + int type; + + /* Convert algorithm id into EVP PKEY id. */ + switch (algId) { +#ifndef NO_RSA + case RSAk: + #ifdef WC_RSA_PSS + case RSAPSSk: + #endif + type = WC_EVP_PKEY_RSA; + break; +#endif + #ifdef HAVE_ECC + case ECDSAk: + type = WC_EVP_PKEY_EC; + break; + #endif + #ifndef NO_DSA + case DSAk: + type = WC_EVP_PKEY_DSA; + break; + #endif + #ifndef NO_DH + case DHk: + type = WC_EVP_PKEY_DH; + break; + #endif + default: + WOLFSSL_MSG("PKEY algorithm, from PKCS#8 header, not supported"); + type = WC_EVP_PKEY_NONE; + break; + } + + return type; +} + +/* Creates an WOLFSSL_EVP_PKEY from PKCS#8 encrypted private DER in a BIO. + * + * Uses the PEM default password callback when cb is NULL. + * + * @param [in] bio BIO to read DER from. + * @param [in, out] pkey Newly created WOLFSSL_EVP_PKEY structure. + * @param [in] cb Password callback. May be NULL. + * @param [in] ctx Password callback context. May be NULL. + * @return A non null pointer on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PKCS8PrivateKey_bio(WOLFSSL_BIO* bio, + WOLFSSL_EVP_PKEY** pkey, wc_pem_password_cb* cb, void* ctx) +{ + int ret; + const byte* p; + byte* der = NULL; + int len; + word32 algId; + WOLFSSL_EVP_PKEY* key; + int type; + char password[NAME_SZ]; + int passwordSz; + + /* Get the data from the BIO into a newly allocated buffer. */ + if ((len = bio_get_data(bio, &der)) < 0) + return NULL; + + /* Use the PEM default callback if none supplied. */ + if (cb == NULL) { + cb = wolfSSL_PEM_def_callback; + } + /* Get the password. */ + passwordSz = cb(password, sizeof(password), PEM_PASS_READ, ctx); + if (passwordSz < 0) { + XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); + return NULL; + } +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Add("wolfSSL_d2i_PKCS8PrivateKey_bio password", password, + passwordSz); +#endif + + /* Decrypt the PKCS#8 encrypted private key and get algorithm. */ + ret = ToTraditionalEnc(der, (word32)len, password, passwordSz, &algId); + ForceZero(password, (word32)passwordSz); +#ifdef WOLFSSL_CHECK_MEM_ZERO + wc_MemZero_Check(password, passwordSz); +#endif + if (ret < 0) { + XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + + /* Get the key type from the algorithm id of the PKCS#8 header. */ + if ((type = wolfssl_i_alg_id_to_key_type(algId)) == WC_EVP_PKEY_NONE) { + XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); + return NULL; + } + + /* Decode private key with the known type. */ + p = der; + key = d2i_evp_pkey(type, pkey, &p, len, 1); + + /* Dispose of memory holding BIO data. */ + XFREE(der, bio->heap, DYNAMIC_TYPE_OPENSSL); + return key; +} +#endif /* !NO_BIO && !NO_PWDBASED && HAVE_PKCS8 */ +#endif /* OPENSSL_ALL */ + +#ifdef OPENSSL_EXTRA +/* Reads in a PKCS#8 DER format key. + * + * @param [in, out] pkey Newly created WOLFSSL_PKCS8_PRIV_KEY_INFO structure. + * @param [in, out] keyBuf Pointer to input key DER. + * Pointer is advanced the same number of bytes read on + * success. + * @param [in] keyLen Number of bytes in keyBuf. + * @return A non null pointer on success. + * @return NULL on failure. + */ +WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY( + WOLFSSL_PKCS8_PRIV_KEY_INFO** pkey, const unsigned char** keyBuf, + long keyLen) +{ + WOLFSSL_PKCS8_PRIV_KEY_INFO* pkcs8 = NULL; +#ifdef WOLFSSL_PEM_TO_DER + int ret; + DerBuffer* pkcs8Der = NULL; + DerBuffer rawDer; + EncryptedInfo info; + int advanceLen = 0; + + /* Clear the encryption information and DER buffer. */ + XMEMSET(&info, 0, sizeof(info)); + XMEMSET(&rawDer, 0, sizeof(rawDer)); + + /* Validate parameters. */ + if ((keyBuf == NULL) || (*keyBuf == NULL) || (keyLen <= 0)) { + WOLFSSL_MSG("Bad key PEM/DER args"); + return NULL; + } + + /* Try to decode the PEM into DER. */ + ret = PemToDer(*keyBuf, keyLen, PRIVATEKEY_TYPE, &pkcs8Der, NULL, &info, + NULL); + if (ret >= 0) { + /* Cache the amount of data in PEM formatted private key. */ + advanceLen = (int)info.consumed; + } + else { + /* Not PEM - create a DerBuffer with the PKCS#8 DER data. */ + WOLFSSL_MSG("Not PEM format"); + ret = AllocDer(&pkcs8Der, (word32)keyLen, PRIVATEKEY_TYPE, NULL); + if (ret == 0) { + XMEMCPY(pkcs8Der->buffer, *keyBuf, keyLen); + } + } + + if (ret == 0) { + /* Verify this is PKCS8 Key */ + word32 inOutIdx = 0; + word32 algId; + + ret = ToTraditionalInline_ex(pkcs8Der->buffer, &inOutIdx, + pkcs8Der->length, &algId); + if (ret >= 0) { + if (advanceLen == 0) { + /* Set only if not PEM */ + advanceLen = (int)inOutIdx + ret; + } + if (algId == DHk) { + /* Special case for DH as we expect the DER buffer to be always + * be in PKCS8 format */ + rawDer.buffer = pkcs8Der->buffer; + rawDer.length = inOutIdx + (word32)ret; + } + else { + rawDer.buffer = pkcs8Der->buffer + inOutIdx; + rawDer.length = (word32)ret; + } + ret = 0; /* good DER */ + } + } + + if (ret == 0) { + /* Create a WOLFSSL_EVP_PKEY for a WOLFSSL_PKCS8_PRIV_KEY_INFO. */ + pkcs8 = wolfSSL_EVP_PKEY_new(); + if (pkcs8 == NULL) { + ret = MEMORY_E; + } + } + if (ret == 0) { + /* Allocate memory to hold DER. */ + pkcs8->pkey.ptr = (char*)XMALLOC(rawDer.length, NULL, + DYNAMIC_TYPE_PUBLIC_KEY); + if (pkcs8->pkey.ptr == NULL) { + ret = MEMORY_E; + } + } + if (ret == 0) { + /* Copy in DER data and size. */ + XMEMCPY(pkcs8->pkey.ptr, rawDer.buffer, rawDer.length); + pkcs8->pkey_sz = (int)rawDer.length; + } + + /* Dispose of PKCS#8 DER data - raw DER reference data in pkcs8Der. */ + FreeDer(&pkcs8Der); + if (ret != 0) { + /* Dispose of WOLFSSL_PKCS8_PRIV_KEY_INFO object on error. */ + wolfSSL_EVP_PKEY_free(pkcs8); + pkcs8 = NULL; + } + else { + /* Advance the buffer past the key on success. */ + *keyBuf += advanceLen; + } + if (pkey != NULL) { + /* Return the WOLFSSL_PKCS8_PRIV_KEY_INFO object through parameter. */ + *pkey = pkcs8; + } +#else + (void)pkey; + (void)keyBuf; + (void)keyLen; +#endif /* WOLFSSL_PEM_TO_DER */ + + /* Return new WOLFSSL_PKCS8_PRIV_KEY_INFO object. */ + return pkcs8; +} + +#ifndef NO_BIO +/* Converts a DER format key read from BIO to a PKCS#8 structure. + * + * @param [in] bio Input BIO to read DER from. + * @param [out] pkey If not NULL then this pointer will be overwritten with a + * new PKCS8 structure. + * @return A WOLFSSL_PKCS8_PRIV_KEY_INFO pointer on success + * @return NULL on failure. + */ +WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY_bio(WOLFSSL_BIO* bio, + WOLFSSL_PKCS8_PRIV_KEY_INFO** pkey) +{ + WOLFSSL_PKCS8_PRIV_KEY_INFO* pkcs8 = NULL; +#ifdef WOLFSSL_PEM_TO_DER + unsigned char* mem = NULL; + int memSz; + + WOLFSSL_ENTER("wolfSSL_d2i_PKCS8_PKEY_bio"); + + /* Validate parameters. */ + if (bio == NULL) { + return NULL; + } + + /* Get the memory buffer from the BIO. */ + if ((memSz = wolfSSL_BIO_get_mem_data(bio, &mem)) < 0) { + return NULL; + } + + /* Decode the PKCS#8 key into a WOLFSSL_PKCS8_PRIV_KEY_INFO object. */ + pkcs8 = wolfSSL_d2i_PKCS8_PKEY(pkey, (const unsigned char**)&mem, memSz); +#else + (void)bio; + (void)pkey; +#endif /* WOLFSSL_PEM_TO_DER */ + + /* Return new WOLFSSL_PKCS8_PRIV_KEY_INFO object. */ + return pkcs8; +} +#endif /* !NO_BIO */ + +#ifdef WOLF_PRIVATE_KEY_ID +/* Create an EVP structure for use with crypto callbacks. + * + * @param [in] type Type of private key. + * @param [out] out WOLFSSL_EVP_PKEY object created. + * @param [in] heap Heap hint for dynamic memory allocation. + * @param [in] devId Device id. + * @return A new WOLFSSL_EVP_PKEY object on success. + * @return NULL on failure. + */ +WOLFSSL_EVP_PKEY* wolfSSL_d2i_PrivateKey_id(int type, WOLFSSL_EVP_PKEY** out, + void* heap, int devId) +{ + WOLFSSL_EVP_PKEY* local; + + /* Dispose of any object passed in through out. */ + if (out != NULL && *out != NULL) { + wolfSSL_EVP_PKEY_free(*out); + *out = NULL; + } + + /* Create a local WOLFSSL_EVP_PKEY to be decoded into. */ + local = wolfSSL_EVP_PKEY_new_ex(heap); + if (local == NULL) { + return NULL; + } + local->type = type; + local->pkey_sz = 0; + local->pkcs8HeaderSz = 0; + + switch (type) { +#ifndef NO_RSA + case WC_EVP_PKEY_RSA: + { + /* Create a WOLFSSL_RSA object into WOLFSSL_EVP_PKEY. */ + local->rsa = wolfSSL_RSA_new_ex(heap, devId); + if (local->rsa == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + local->ownRsa = 1; + /* Algorithm specific object set into WOLFSL_EVP_PKEY. */ + local->rsa->inSet = 1; + #ifdef WOLF_CRYPTO_CB + ((RsaKey*)local->rsa->internal)->devId = devId; + #endif + break; + } +#endif /* !NO_RSA */ +#ifdef HAVE_ECC + case WC_EVP_PKEY_EC: + { + ecc_key* key; + + /* Create a WOLFSSL_EC object into WOLFSSL_EVP_PKEY. */ + local->ecc = wolfSSL_EC_KEY_new_ex(heap, devId); + if (local->ecc == NULL) { + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + local->ownEcc = 1; + /* Algorithm specific object set into WOLFSL_EVP_PKEY. */ + local->ecc->inSet = 1; + + /* Get wolfSSL EC key and set fields. */ + key = (ecc_key*)local->ecc->internal; + #ifdef WOLF_CRYPTO_CB + key->devId = devId; + #endif + key->type = ECC_PRIVATEKEY; + /* key is required to have a key size / curve set, although + * actual one used is determined by devId callback function. */ + wc_ecc_set_curve(key, ECDHE_SIZE, ECC_CURVE_DEF); + break; + } +#endif /* HAVE_ECC */ + default: + WOLFSSL_MSG("Unsupported private key id type"); + wolfSSL_EVP_PKEY_free(local); + return NULL; + } + + /* Return new WOLFSSL_EVP_PKEY through parameter if required. */ + if (local != NULL && out != NULL) { + *out = local; + } + /* Return new WOLFSSL_EVP_PKEY. */ + return local; +} +#endif /* WOLF_PRIVATE_KEY_ID */ +#endif /* OPENSSL_EXTRA */ + +/******************************************************************************* + * END OF d2i APIs + ******************************************************************************/ + +/******************************************************************************* + * START OF i2d APIs + ******************************************************************************/ + +#ifdef OPENSSL_ALL +/* Encode PKCS#8 key as DER data. + * + * @param [in] key PKCS#8 private key to encode. + * @param [out] pp Pointer to buffer of encoded data. + * @return Length of DER encoded data on success. + * @return Less than zero on failure. + */ +int wolfSSL_i2d_PKCS8_PKEY(WOLFSSL_PKCS8_PRIV_KEY_INFO* key, unsigned char** pp) +{ + word32 keySz = 0; + unsigned char* out; + int len; + + WOLFSSL_ENTER("wolfSSL_i2d_PKCS8_PKEY"); + + /* Validate parameters. */ + if (key == NULL) { + return WOLFSSL_FATAL_ERROR; + } + + /* Get the length of DER encoding. */ + if (pkcs8_encode(key, NULL, &keySz) != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) { + return WOLFSSL_FATAL_ERROR; + } + len = (int)keySz; + + /* Return the length when output parameter is NULL. */ + if ((pp == NULL) || (len == 0)) { + return len; + } + + /* Allocate memory for DER encoding if NULL passed in for output buffer. */ + if (*pp == NULL) { + out = (unsigned char*)XMALLOC((size_t)len, NULL, DYNAMIC_TYPE_ASN1); + if (out == NULL) { + return WOLFSSL_FATAL_ERROR; + } + } + else { + /* Use buffer passed in - assume it is big enough. */ + out = *pp; + } + + /* Encode the PKCS#8 key into the output buffer. */ + if (pkcs8_encode(key, out, &keySz) != len) { + if (*pp == NULL) { + XFREE(out, NULL, DYNAMIC_TYPE_ASN1); + } + return WOLFSSL_FATAL_ERROR; + } + + /* Return new output buffer or move pointer passed encoded data. */ + if (*pp == NULL) { + *pp = out; + } + else { + *pp += len; + } + + return len; +} +#endif + +#ifdef OPENSSL_EXTRA + +#if !defined(NO_ASN) && !defined(NO_PWDBASED) +/* Get raw pointer to DER buffer from WOLFSSL_EVP_PKEY. + * + * Assumes der is large enough if passed in. + * + * @param [in] key WOLFSSL_EVP_PKEY to get DER buffer for. + * @param [out] der Buffer holding DER encoding. May be NULL. + * @return Size of DER encoding on success. + * @return Less than 0 on failure. + */ +static int wolfssl_i_evp_pkey_get_der(const WOLFSSL_EVP_PKEY* key, + unsigned char** der) +{ + int sz; + word16 pkcs8HeaderSz; + + /* Validate parameters. */ + if ((key == NULL) || (key->pkey_sz == 0)) { + return WOLFSSL_FATAL_ERROR; + } + + /* If pkcs8HeaderSz is invalid, return all of the DER encoding. */ + pkcs8HeaderSz = 0; + if (key->pkey_sz > key->pkcs8HeaderSz) { + pkcs8HeaderSz = key->pkcs8HeaderSz; + } + /* Calculate the size of the DER encoding to return. */ + sz = key->pkey_sz - pkcs8HeaderSz; + /* Returning encoding when DER is not NULL. */ + if (der != NULL) { + unsigned char* pt = (unsigned char*)key->pkey.ptr; + int bufferPassedIn = ((*der) != NULL); + + if (!bufferPassedIn) { + /* Allocate buffer to hold DER encoding. */ + *der = (unsigned char*)XMALLOC((size_t)sz, NULL, + DYNAMIC_TYPE_OPENSSL); + if (*der == NULL) { + return WOLFSSL_FATAL_ERROR; + } + } + /* Copy in non-PKCS#8 DER encoding. */ + XMEMCPY(*der, pt + pkcs8HeaderSz, (size_t)sz); + /* Step past encoded key when buffer provided. */ + if (bufferPassedIn) { + *der += sz; + } + } + + /* Return size of DER encoded data. */ + return sz; +} + +/* Encode key as unencrypted DER data. + * + * @param [in] key PKCS#8 private key to encode. + * @param [out] der Pointer to buffer of encoded data. + * @return Length of DER encoded data on success. + * @return Less than zero on failure. + */ +int wolfSSL_i2d_PrivateKey(const WOLFSSL_EVP_PKEY* key, unsigned char** der) +{ + return wolfssl_i_evp_pkey_get_der(key, der); +} + +#ifndef NO_BIO +/* Encode key as unencrypted DER data and write to BIO. + * + * @param [in] bio BIO to write data to. + * @param [in] key PKCS#8 private key to encode. + * @return Length of DER encoded data on success. + * @return Less than zero on failure. + */ +int wolfSSL_i2d_PrivateKey_bio(WOLFSSL_BIO* bio, WOLFSSL_EVP_PKEY* key) +{ + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + int derSz = 0; + byte* der = NULL; + + if (bio == NULL || key == NULL) { + return WOLFSSL_FAILURE; + } + + derSz = wolfSSL_i2d_PrivateKey(key, &der); + if (derSz <= 0) { + WOLFSSL_MSG("wolfSSL_i2d_PrivateKey (for getting size) failed"); + return WOLFSSL_FAILURE; + } + + if (wolfSSL_BIO_write(bio, der, derSz) != derSz) { + goto cleanup; + } + + ret = WOLFSSL_SUCCESS; + +cleanup: + XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL); + return ret; +} +#endif + +#ifdef HAVE_ECC +/* Encode EC key as public key DER. + * + * @param [in] key WOLFSSL_EVP_KEY object to encode. + * @param [in] ec WOLFSSL_EC_KEY object to encode. + * @param [out] der Buffer with DER encoding of EC public key. + * @return Public key DER encoding size on success. + * @return WOLFSSL_FATAL_ERROR when dynamic memory allocation fails. + * @return WOLFSSL_FATAL_ERROR when encoding fails. + */ +static int wolfssl_i_i2d_ecpublickey(const WOLFSSL_EVP_PKEY* key, + const WOLFSSL_EC_KEY *ec, unsigned char **der) +{ + word32 pub_derSz = 0; + int ret; + unsigned char *local_der = NULL; + word32 local_derSz = 0; + unsigned char *pub_der = NULL; + ecc_key *eccKey = NULL; + word32 inOutIdx = 0; + + /* We need to get the DER, then convert it to a public key. But what we get + * might be a buffered private key so we need to decode it and then encode + * the public part. */ + ret = wolfssl_i_evp_pkey_get_der(key, &local_der); + if (ret <= 0) { + /* In this case, there was no buffered DER at all. This could be the + * case where the key that was passed in was generated. So now we + * have to create the local DER. */ + local_derSz = (word32)wolfSSL_i2d_ECPrivateKey(ec, &local_der); + if (local_derSz == 0) { + ret = WOLFSSL_FATAL_ERROR; + } + } else { + local_derSz = (word32)ret; + ret = 0; + } + + if (ret == 0) { + eccKey = (ecc_key *)XMALLOC(sizeof(*eccKey), NULL, DYNAMIC_TYPE_ECC); + if (eccKey == NULL) { + WOLFSSL_MSG("Failed to allocate key buffer."); + ret = WOLFSSL_FATAL_ERROR; + } + } + + /* Initialize a wolfCrypt ECC key. */ + if (ret == 0) { + ret = wc_ecc_init(eccKey); + } + if (ret == 0) { + /* Decode the DER data with wolfCrypt ECC key. */ + ret = wc_EccPublicKeyDecode(local_der, &inOutIdx, eccKey, local_derSz); + if (ret < 0) { + /* We now try again as x.963 [point type][x][opt y]. */ + ret = wc_ecc_import_x963(local_der, local_derSz, eccKey); + } + } + + if (ret == 0) { + /* Get the size of the encoding of the public key DER. */ + pub_derSz = (word32)wc_EccPublicKeyDerSize(eccKey, 1); + if ((int)pub_derSz <= 0) { + ret = WOLFSSL_FAILURE; + } + } + + if (ret == 0) { + /* Allocate memory for public key DER encoding. */ + pub_der = (unsigned char*)XMALLOC(pub_derSz, NULL, + DYNAMIC_TYPE_PUBLIC_KEY); + if (pub_der == NULL) { + WOLFSSL_MSG("Failed to allocate output buffer."); + ret = WOLFSSL_FATAL_ERROR; + } + } + + if (ret == 0) { + /* Encode public key as DER. */ + pub_derSz = (word32)wc_EccPublicKeyToDer(eccKey, pub_der, pub_derSz, 1); + if ((int)pub_derSz <= 0) { + ret = WOLFSSL_FATAL_ERROR; + } + } + + /* This block is for actually returning the DER of the public key */ + if ((ret == 0) && (der != NULL)) { + int bufferPassedIn = ((*der) != NULL); + if (!bufferPassedIn) { + *der = (unsigned char*)XMALLOC(pub_derSz, NULL, + DYNAMIC_TYPE_PUBLIC_KEY); + if (*der == NULL) { + WOLFSSL_MSG("Failed to allocate output buffer."); + ret = WOLFSSL_FATAL_ERROR; + } + } + if (ret == 0) { + XMEMCPY(*der, pub_der, pub_derSz); + if (bufferPassedIn) { + *der += pub_derSz; + } + } + } + + /* Dispose of allocated objects. */ + XFREE(pub_der, NULL, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(local_der, NULL, DYNAMIC_TYPE_OPENSSL); + wc_ecc_free(eccKey); + XFREE(eccKey, NULL, DYNAMIC_TYPE_ECC); + + /* Return error or the size of the DER encoded public key. */ + if (ret == 0) { + ret = (int)pub_derSz; + } + return ret; +} +#endif + +/* Encode the WOLFSSL_EVP_PKEY object as public key DER. + * + * @param [in] key WOLFSLS_EVP_PKEY object to encode. + * @param [out] der Buffer with DER encoding of public key. + * @return Public key DER encoding size on success. + * @return WOLFSSL_FATAL_ERROR when key is NULL. + * @return WOLFSSL_FATAL_ERROR when key type not supported. + * @return WOLFSSL_FATAL_ERROR when dynamic memory allocation fails. + */ +int wolfSSL_i2d_PublicKey(const WOLFSSL_EVP_PKEY *key, unsigned char **der) +{ + int ret; + + /* Validate parameters. */ + if (key == NULL) { + return WOLFSSL_FATAL_ERROR; + } + + /* Encode based on key type. */ + switch (key->type) { + #ifndef NO_RSA + case WC_EVP_PKEY_RSA: + return wolfSSL_i2d_RSAPublicKey(key->rsa, der); + #endif + #ifdef HAVE_ECC + case WC_EVP_PKEY_EC: + return wolfssl_i_i2d_ecpublickey(key, key->ecc, der); + #endif + default: + ret = WOLFSSL_FATAL_ERROR; + break; + } + + return ret; +} + +/* Encode the WOLFSSL_EVP_PKEY object as public key DER. + * + * @param [in] key WOLFSLS_EVP_PKEY object to encode. + * @param [out] der Buffer with DER encoding of public key. + * @return Public key DER encoding size on success. + * @return WOLFSSL_FATAL_ERROR when key is NULL. + * @return WOLFSSL_FATAL_ERROR when key type not supported. + * @return WOLFSSL_FATAL_ERROR when dynamic memory allocation fails. + */ +int wolfSSL_i2d_PUBKEY(const WOLFSSL_EVP_PKEY *key, unsigned char **der) +{ + return wolfSSL_i2d_PublicKey(key, der); +} +#endif /* !NO_ASN && !NO_PWDBASED */ + +#endif /* OPENSSL_EXTRA */ + +#endif /* !NO_CERTS */ + +/******************************************************************************* + * END OF i2d APIs + ******************************************************************************/ + +#endif /* !WOLFSSL_EVP_PK_INCLUDED */ + diff --git a/wolfcrypt/src/include.am b/wolfcrypt/src/include.am index a14ae1884c..bb8eea3f42 100644 --- a/wolfcrypt/src/include.am +++ b/wolfcrypt/src/include.am @@ -12,6 +12,7 @@ MAINTAINERCLEANFILES+= $(ASYNC_FILES) EXTRA_DIST += wolfcrypt/src/misc.c EXTRA_DIST += wolfcrypt/src/evp.c +EXTRA_DIST += wolfcrypt/src/evp_pk.c EXTRA_DIST += wolfcrypt/src/asm.c EXTRA_DIST += wolfcrypt/src/aes_asm.asm EXTRA_DIST += wolfcrypt/src/aes_gcm_asm.asm diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index a499a95278..49301a4d3a 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -4990,6 +4990,10 @@ extern void uITRON4_free(void *p) ; #error "If TLS is enabled please make sure either client or server is enabled." #endif +#if defined(WC_RNG_BANK_SUPPORT) && defined(NO_ASN_TIME) + #undef WC_RNG_BANK_SUPPORT +#endif + #ifdef __cplusplus } /* extern "C" */ #endif