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,3909 +926,9 @@ static int wolfssl_der_length(const unsigned char* seq, int len) #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 - ******************************************************************************/ +#define WOLFSSL_PK_RSA_INCLUDED +#include "src/pk_rsa.c" /******************************************************************************* @@ -5393,7 +1478,7 @@ int wolfSSL_i2d_DSA_SIG(const WOLFSSL_DSA_SIG *sig, byte **out) } /** - * Same as wolfSSL_DSA_SIG_new but also initializes the internal bignums as well. + * 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_DSA_SIG* wolfSSL_DSA_SIG_new_bn(void) @@ -6226,7 +2311,8 @@ WOLFSSL_DSA *wolfSSL_PEM_read_bio_DSA_PUBKEY(WOLFSSL_BIO* bio,WOLFSSL_DSA** dsa, #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) +int wolfSSL_DSA_LoadDer(WOLFSSL_DSA* dsa, const unsigned char* derBuf, + int derSz) { word32 idx = 0; int ret; @@ -6330,7 +2416,7 @@ WOLFSSL_DSA *wolfSSL_PEM_read_bio_DSAparams(WOLFSSL_BIO *bp, WOLFSSL_DSA **x, * 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"); + WOLFSSL_MSG("Not supporting callback or password for encrypted PEM"); } if (PemToDer(buf, (long)bufSz, DSA_PARAM_TYPE, &pDer, NULL, NULL, @@ -8950,5511 +5036,9 @@ int wolfSSL_DH_compute_key_padded(unsigned char* key, ******************************************************************************/ -/******************************************************************************* - * START OF EC API - ******************************************************************************/ +#define WOLFSSL_PK_EC_INCLUDED +#include "src/pk_ec.c" -#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 - ******************************************************************************/ /******************************************************************************* * 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,710 +413,8 @@ 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; - - 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 */ +#define WOLFSSL_SSL_ECH_INCLUDED +#include "src/ssl_ech.c" #ifdef OPENSSL_EXTRA static int wolfSSL_parse_cipher_list(WOLFSSL_CTX* ctx, WOLFSSL* ssl, @@ -1858,48 +1165,6 @@ int wolfSSL_dtls(WOLFSSL* ssl) 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( @@ -3666,60 +2931,6 @@ int wolfSSL_CTX_UseTruncatedHMAC(WOLFSSL_CTX* ctx) #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) @@ -5202,16 +4413,6 @@ int wolfSSL_GetSequenceNumber(WOLFSSL* ssl, word64 *seq) #endif /* ATOMIC_USER */ -#ifndef NO_CERTS -WOLFSSL_CERT_MANAGER* wolfSSL_CTX_GetCertManager(WOLFSSL_CTX* ctx) -{ - 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) @@ -5538,826 +4739,6 @@ int wolfSSL_SetVersion(WOLFSSL* ssl, int version) } #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) -{ - 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 */ - - #if defined(OPENSSL_EXTRA) && !defined(WOLFSSL_NO_OPENSSL_RAND_CB) static int wolfSSL_RAND_InitMutex(void); #endif @@ -6862,2580 +5243,8 @@ void wolfSSL_set_security_level(WOLFSSL * ssl, int level) #define WOLFSSL_SSL_LOAD_INCLUDED #include -#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); -} - -#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 */ - -#endif /* HAVE_OCSP */ - -#ifdef HAVE_CRL - -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 */ - - -/* 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"); - - if (ctx == NULL || depth < 0 || depth > MAX_CHAIN_DEPTH) { - WOLFSSL_MSG("Bad depth argument, too large or less than 0"); - return; - } - - ctx->verifyDepth = (byte)depth; -} - - -/* get cert chaining depth using ssl struct */ -long wolfSSL_get_verify_depth(WOLFSSL* ssl) -{ - if(ssl == NULL) { - return BAD_FUNC_ARG; - } -#ifndef OPENSSL_EXTRA - return MAX_CHAIN_DEPTH; -#else - return ssl->options.verifyDepth; -#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; -#else - return ctx->verifyDepth; -#endif -} - -#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) -{ - int ret = 0; - int type = 0; - void *pkey = NULL; - - if (privKey == NULL) { - return MISSING_KEY; - } - -#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; - } -#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) -{ - WC_DECLARE_VAR(der, DecodedCert, 1, 0); - word32 size; - byte* buff; - int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - - WOLFSSL_ENTER("check_cert_key"); - - if (cert == NULL || key == NULL) { - return WOLFSSL_FAILURE; - } - - WC_ALLOC_VAR_EX(der, DecodedCert, 1, heap, DYNAMIC_TYPE_DCERT, - return MEMORY_E); - - 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; - } - - 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; - } - - 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); - - (void)devId; - (void)isKeyLabel; - (void)isKeyId; - (void)altKey; - (void)altDevId; - (void)isAltKeyLabel; - (void)isAltKeyId; - - return ret; -} - -/* 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; - } - -#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); - } - - return res; -} -#endif /* !NO_CHECK_PRIVATE_KEY */ - -#ifdef OPENSSL_ALL -/** - * Return the private key of the WOLFSSL_CTX struct - * @return WOLFSSL_EVP_PKEY* 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. - */ -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; -} -#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) -{ - 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 (*out != NULL) { - pkey = *out; - } - else { - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) { - WOLFSSL_MSG("RSA wolfSSL_EVP_PKEY_new error"); - return 0; - } - } - - 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; - - 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; - } - - if ((ret == 0) && (*out == NULL)) { - wolfSSL_EVP_PKEY_free(pkey); - } - return ret; -} -#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) -{ - 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 - - XMEMSET(ecc, 0, sizeof(ecc_key)); - - 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; - } - - if (*out != NULL) { - pkey = *out; - } - else { - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) { - WOLFSSL_MSG("ECC wolfSSL_EVP_PKEY_new error"); - return 0; - } - } - - 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; - } - - if ((ret == 0) && (*out == NULL)) { - wolfSSL_EVP_PKEY_free(pkey); - } - return ret; -} -#endif /* HAVE_ECC && OPENSSL_EXTRA */ - -#if !defined(NO_DSA) -static int d2iTryDsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, - long memSz, int priv) -{ - 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 - - XMEMSET(dsa, 0, sizeof(DsaKey)); - - 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); - - /* test if DSA key */ - if (!isDsaKey) { - return WOLFSSL_FATAL_ERROR; - } - - if (*out != NULL) { - pkey = *out; - } - else { - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) { - WOLFSSL_MSG("DSA wolfSSL_EVP_PKEY_new error"); - return 0; - } - } - - 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; - - 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; - } - - if ((ret == 0) && (*out == NULL)) { - wolfSSL_EVP_PKEY_free(pkey); - } - 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)) -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)); - - if (wc_InitDhKey(dh) != 0) { - WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH); - return 0; - } - - 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; - } - - if (*out != NULL) { - pkey = *out; - } - else { - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) { - WOLFSSL_MSG("DH wolfSSL_EVP_PKEY_new error"); - return 0; - } - } - - 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; - - 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; - } - - if ((ret == 0) && (*out == NULL)) { - wolfSSL_EVP_PKEY_free(pkey); - } - 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)) -static int d2iTryAltDhKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, - long memSz, int priv) -{ - 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)); - - /* test if DH-public key */ - if (wc_InitDhKey(dh) != 0) { - WC_FREE_VAR_EX(dh, NULL, DYNAMIC_TYPE_DH); - return 0; - } - - 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; - } - - if (*out != NULL) { - pkey = *out; - } - else { - pkey = wolfSSL_EVP_PKEY_new(); - if (pkey == NULL) { - return 0; - } - } - - 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; - } - } - - 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; - } - - if ((ret == 0) && (*out == NULL)) { - wolfSSL_EVP_PKEY_free(pkey); - } - return ret; -} -#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) -{ - 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 (wc_falcon_init(falcon) != 0) { - WC_FREE_VAR_EX(falcon, NULL, DYNAMIC_TYPE_FALCON); - return 0; - } - - /* 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)); - - 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); - - if (!isFalcon) { - return WOLFSSL_FATAL_ERROR; - } - - 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; - - *out = pkey; - return 1; - -} -#endif /* HAVE_FALCON */ - -#ifdef HAVE_DILITHIUM -static int d2iTryDilithiumKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem, - long memSz, int priv) -{ - 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; - } -#endif - - 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; - - *out = pkey; - return 1; -} -#endif /* HAVE_DILITHIUM */ - -static WOLFSSL_EVP_PKEY* d2iGenericKey(WOLFSSL_EVP_PKEY** out, - const unsigned char** in, long inSz, int priv) -{ - WOLFSSL_EVP_PKEY* pkey = NULL; - - WOLFSSL_ENTER("d2iGenericKey"); - - 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("wolfSSL_d2i_PUBKEY couldn't determine key type"); - } - - if ((pkey != NULL) && (out != NULL)) { - *out = pkey; - } - return pkey; -} -#endif /* OPENSSL_EXTRA || WPA_SMALL */ - -#ifdef OPENSSL_EXTRA - -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; - - XMEMSET(&info, 0, sizeof(info)); - XMEMSET(&rawDer, 0, sizeof(rawDer)); - - if (keyBuf == NULL || *keyBuf == NULL || keyLen <= 0) { - WOLFSSL_MSG("Bad key PEM/DER args"); - return NULL; - } - - 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; - } - - 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) { - 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; - } - -#else - (void)bio; - (void)pkey; -#endif /* WOLFSSL_PEM_TO_DER */ - - return pkcs8; -} - -#ifdef OPENSSL_ALL -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"); - - if (key == NULL) - return WOLFSSL_FATAL_ERROR; - - if (pkcs8_encode(key, NULL, &keySz) != WC_NO_ERR_TRACE(LENGTH_ONLY_E)) - return WOLFSSL_FATAL_ERROR; - len = (int)keySz; - - if ((pp == NULL) || (len == 0)) - 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; - } - - if (pkcs8_encode(key, out, &keySz) != len) { - if (*pp == NULL) - XFREE(out, NULL, DYNAMIC_TYPE_ASN1); - return WOLFSSL_FATAL_ERROR; - } - - if (*pp == NULL) - *pp = out; - else - *pp += len; - - return len; -} -#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) -{ - 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"); - - if (bio == NULL) { - return NULL; - } - - if ((memSz = wolfSSL_BIO_get_mem_data(bio, &mem)) < 0) { - return NULL; - } - - pkcs8 = wolfSSL_d2i_PKCS8_PKEY(pkey, (const unsigned char**)&mem, memSz); -#else - (void)bio; - (void)pkey; -#endif /* WOLFSSL_PEM_TO_DER */ - - return pkcs8; -} - - -/* 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) -{ - 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; - } - - mem = (unsigned char*)XMALLOC((size_t)memSz, bio->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (mem == NULL) { - return NULL; - } - - 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; - } - } - - 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); -} - -#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) -{ - int sz; - word16 pkcs8HeaderSz; - - if (!key || !key->pkey_sz) - return WOLFSSL_FATAL_ERROR; - - /* 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; - } - 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); - } - } - return sz; -} - -int wolfSSL_i2d_PUBKEY(const WOLFSSL_EVP_PKEY *key, unsigned char **der) -{ - return wolfSSL_i2d_PublicKey(key, der); -} - -#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 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; - } - - (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; - } - } - } - - if (out != NULL && *out != NULL) { - wolfSSL_EVP_PKEY_free(*out); - *out = NULL; - } - 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); - local = NULL; - return NULL; - } - else { - XMEMCPY(local->pkey.ptr, *in, (size_t)inSz); - } - - 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; - } - 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; - } - 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; - } - 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; - } - 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 with success */ - if (local != NULL) { - if (local->pkey_sz <= (int)inSz) { - *in += local->pkey_sz; - } - - if (out != NULL) { - *out = local; - } - } - - return local; -} - -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_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 - * - * On success a non null pointer is returned and the pointer in is advanced the - * same number of bytes read. - */ -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_PublicKey(type, out, in, inSz, 1); -} - -#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_EVP_PKEY* local; - - if (out != NULL && *out != NULL) { - wolfSSL_EVP_PKEY_free(*out); - *out = NULL; - } - - 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: - { - 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; - } -#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 /* HAVE_ECC */ - default: - WOLFSSL_MSG("Unsupported private key id type"); - wolfSSL_EVP_PKEY_free(local); - return NULL; - } - - if (local != NULL && out != NULL) { - *out = local; - } - - 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); - } -#ifdef WOLFSSL_BLIND_PRIVATE_KEY - wolfssl_priv_der_unblind_free(privateKey); -#endif -#endif - - return res; -} -#endif /* !NO_CHECK_PRIVATE_KEY */ - -#endif /* !NO_CERTS */ - -#endif /* OPENSSL_EXTRA */ - -#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; - } - } - } - 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; - } - - 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; - } - - if (!isArrayUnique(buf, (size_t)bufLen)) - return BAD_FUNC_ARG; - - 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]; - } - *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 (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; - } - 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 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; - } - 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) -{ - WOLFSSL_ENTER("wolfSSL_CTX_SetTmpEC_DHE_Sz"); - - if (ctx == NULL) - return BAD_FUNC_ARG; - - /* 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; - - if (ctx->privateKeySz == 0) { - WOLFSSL_MSG("Must set private key/cert first"); - return BAD_FUNC_ARG; - } - - sz = (word16)ctx->privateKeySz; - } - - /* 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; - - ctx->eccTempKeySz = sz; - - 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) -{ - WOLFSSL_ENTER("wolfSSL_SetTmpEC_DHE_Sz"); - - if (ssl == NULL) - return BAD_FUNC_ARG; - - /* 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; - - ssl->eccTempKeySz = sz; - - return WOLFSSL_SUCCESS; -} - -#endif /* HAVE_ECC */ - - -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 - } - } - - return opts; -} - -WOLFSSL_ABI -void wolfSSL_CTX_set_verify(WOLFSSL_CTX* ctx, int mode, VerifyCallback verify_callback) -{ - SetVerifyOptions opts; - - WOLFSSL_ENTER("wolfSSL_CTX_set_verify"); - if (ctx == NULL) - return; - - opts = ModeToVerifyOptions(mode); - - 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 - - ctx->verifyCallback = verify_callback; -} - -#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; - - ctx->verifyCertCb = cb; - ctx->verifyCertCbArg = arg; -} -#endif - - -void wolfSSL_set_verify(WOLFSSL* ssl, int mode, VerifyCallback verify_callback) -{ - 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; -} - -void wolfSSL_set_verify_result(WOLFSSL *ssl, long v) -{ - WOLFSSL_ENTER("wolfSSL_set_verify_result"); - - if (ssl == NULL) - return; - -#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 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); - - } - else { - WOLFSSL_ERROR(ret); /* log the error in the error queue */ - } - } - 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 */ - -/* store user ctx for verify callback */ -void wolfSSL_SetCertCbCtx(WOLFSSL* ssl, void* ctx) -{ - WOLFSSL_ENTER("wolfSSL_SetCertCbCtx"); - if (ssl) - ssl->verifyCbCtx = ctx; -} - - -/* store user ctx for verify callback */ -void wolfSSL_CTX_SetCertCbCtx(WOLFSSL_CTX* ctx, void* userCtx) -{ - WOLFSSL_ENTER("wolfSSL_CTX_SetCertCbCtx"); - if (ctx) - ctx->verifyCbCtx = userCtx; -} - - -/* store context CA Cache addition callback */ -void wolfSSL_CTX_SetCACb(WOLFSSL_CTX* ctx, CallbackCACache cb) -{ - if (ctx && ctx->cm) - ctx->cm->caCacheCallback = cb; -} - - -#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) -{ - WOLFSSL_ENTER("wolfSSL_CTX_save_cert_cache"); - - if (ctx == NULL || fname == NULL) - return BAD_FUNC_ARG; - - return CM_SaveCertCache(ctx->cm, fname); -} - - -/* Persist cert cache from file */ -int wolfSSL_CTX_restore_cert_cache(WOLFSSL_CTX* ctx, const char* fname) -{ - WOLFSSL_ENTER("wolfSSL_CTX_restore_cert_cache"); - - if (ctx == NULL || fname == NULL) - return BAD_FUNC_ARG; - - return CM_RestoreCertCache(ctx->cm, fname); -} - -#endif /* NO_FILESYSTEM */ - -/* Persist cert cache to memory */ -int wolfSSL_CTX_memsave_cert_cache(WOLFSSL_CTX* ctx, void* mem, - int sz, int* used) -{ - WOLFSSL_ENTER("wolfSSL_CTX_memsave_cert_cache"); - - if (ctx == NULL || mem == NULL || used == NULL || sz <= 0) - return BAD_FUNC_ARG; - - return CM_MemSaveCertCache(ctx->cm, mem, sz, used); -} - - -/* Restore cert cache from memory */ -int wolfSSL_CTX_memrestore_cert_cache(WOLFSSL_CTX* ctx, const void* mem, int sz) -{ - 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); -} - - -/* 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); -} - -#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 @@ -12622,249 +8267,6 @@ int wolfSSL_set_compression(WOLFSSL* ssl) } #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; - } - - list = wolfSSL_sk_X509_NAME_new(NULL); - if (list == NULL) { - WOLFSSL_MSG("wolfSSL_sk_X509_NAME_new error"); - goto cleanup; - } - - /* 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; - } - - 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; - } - return list; - #else - (void)fname; - return NULL; - #endif - } - #endif - #endif /* !NO_BIO */ -#endif /* OPENSSL_EXTRA || WOLFSSL_EXTRA */ - #ifdef OPENSSL_EXTRA #if defined(WOLFCRYPT_HAVE_SRP) && !defined(NO_SHA256) \ @@ -13215,130 +8617,6 @@ cleanup: } #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) @@ -17335,38 +12346,6 @@ long wolfSSL_set_tlsext_debug_arg(WOLFSSL* ssl, void *arg) } #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."); - 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 */ - #ifndef NO_WOLFSSL_STUB long wolfSSL_get_tlsext_status_exts(WOLFSSL *s, void *arg) { @@ -18773,374 +13752,6 @@ void wolfSSL_SetFuzzerCb(WOLFSSL* ssl, CallbackFuzzer cbf, void* fCtx) #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; -} -void* wolfSSL_GetRsaEncCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->RsaEncCtx; - - return NULL; -} - -void wolfSSL_CTX_SetRsaDecCb(WOLFSSL_CTX* ctx, CallbackRsaDec cb) -{ - if (ctx) - ctx->RsaDecCb = cb; -} -void wolfSSL_SetRsaDecCtx(WOLFSSL* ssl, void *ctx) -{ - if (ssl) - ssl->RsaDecCtx = ctx; -} -void* wolfSSL_GetRsaDecCtx(WOLFSSL* ssl) -{ - if (ssl) - return ssl->RsaDecCtx; - - return NULL; -} -#endif /* NO_RSA */ - /* 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 e963a5d9e1..240d72e268 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. */ @@ -4893,7 +4893,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++; @@ -5439,7 +5440,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 } @@ -5560,8 +5562,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; @@ -5612,7 +5616,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); } @@ -5708,8 +5713,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