diff --git a/.gitignore b/.gitignore index f8ff8a508..999db3fe8 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,8 @@ cyassl.sublime* fips.c fips_test.c fips +src/async.c +wolfssl/async.h ctaocrypt/benchmark/benchmark ctaocrypt/test/testctaocrypt wolfcrypt/benchmark/benchmark diff --git a/autogen.sh b/autogen.sh index 196764e1f..971878e33 100755 --- a/autogen.sh +++ b/autogen.sh @@ -18,6 +18,10 @@ if test -d .git; then # touch fips files for non fips distribution touch ./ctaocrypt/src/fips.c touch ./ctaocrypt/src/fips_test.c + + # touch async crypt files + touch ./src/async.c + touch ./wolfssl/async.h else WARNINGS="all" fi diff --git a/configure.ac b/configure.ac index c7e14cc9d..6e4669717 100644 --- a/configure.ac +++ b/configure.ac @@ -2505,6 +2505,27 @@ fi AM_CONDITIONAL([BUILD_MCAPI], [test "x$ENABLED_MCAPI" = "xyes"]) +# Asynchronous Crypto +AC_ARG_ENABLE([asynccrypt], + [ --enable-asynccrypt Enable Asynchronous Crypto (default: disabled)], + [ ENABLED_ASYNCCRYPT=$enableval ], + [ ENABLED_ASYNCCRYPT=no ] + ) + +if test "$ENABLED_ASYNCCRYPT" = "yes" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ASYNC_CRYPT" + + # if Cavium not enabled the use async simulator for testing + if test "x$ENABLED_CAVIUM" = "xno" + then + AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ASYNC_CRYPT_TEST" + fi +fi + +AM_CONDITIONAL([BUILD_ASYNCCRYPT], [test "x$ENABLED_ASYNCCRYPT" = "xyes"]) + + # check if PSK was enabled for conditionally running psk.test script AM_CONDITIONAL([BUILD_PSK], [test "x$ENABLED_PSK" = "xyes"]) @@ -2836,5 +2857,6 @@ echo " * LIBZ: $ENABLED_LIBZ" echo " * Examples: $ENABLED_EXAMPLES" echo " * User Crypto: $ENABLED_USER_CRYPTO" echo " * Fast RSA: $ENABLED_FAST_RSA" +echo " * Async Crypto: $ENABLED_ASYNCCRYPT" echo "" echo "---" diff --git a/examples/client/client.c b/examples/client/client.c index 08fdf9ad2..d800cb26e 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -68,7 +68,7 @@ #endif -static void NonBlockingSSL_Connect(WOLFSSL* ssl) +static void NonBlockingSSL_Connect(WOLFSSL_CTX* ctx, WOLFSSL* ssl) { #ifndef WOLFSSL_CALLBACKS int ret = wolfSSL_connect(ssl); @@ -79,14 +79,23 @@ static void NonBlockingSSL_Connect(WOLFSSL* ssl) SOCKET_T sockfd = (SOCKET_T)wolfSSL_get_fd(ssl); int select_ret; + (void)ctx; + while (ret != SSL_SUCCESS && (error == SSL_ERROR_WANT_READ || - error == SSL_ERROR_WANT_WRITE)) { + error == SSL_ERROR_WANT_WRITE || + error == WC_PENDING_E)) { int currTimeout = 1; if (error == SSL_ERROR_WANT_READ) printf("... client would read block\n"); - else + else if (error == SSL_ERROR_WANT_WRITE) printf("... client would write block\n"); +#ifdef WOLFSSL_ASYNC_CRYPT + else if (error == WC_PENDING_E) { + ret = AsyncCryptPoll(ctx, ssl); + if (ret < 0) { break; } else if (ret == 0) { continue; } + } +#endif #ifdef WOLFSSL_DTLS currTimeout = wolfSSL_dtls_get_current_timeout(ssl); @@ -95,11 +104,11 @@ static void NonBlockingSSL_Connect(WOLFSSL* ssl) if ((select_ret == TEST_RECV_READY) || (select_ret == TEST_ERROR_READY)) { - #ifndef WOLFSSL_CALLBACKS - ret = wolfSSL_connect(ssl); - #else - ret = wolfSSL_connect_ex(ssl,handShakeCB,timeoutCB,timeout); - #endif + #ifndef WOLFSSL_CALLBACKS + ret = wolfSSL_connect(ssl); + #else + ret = wolfSSL_connect_ex(ssl,handShakeCB,timeoutCB,timeout); + #endif error = wolfSSL_get_error(ssl, 0); } else if (select_ret == TEST_TIMEOUT && !wolfSSL_dtls(ssl)) { @@ -107,7 +116,7 @@ static void NonBlockingSSL_Connect(WOLFSSL* ssl) } #ifdef WOLFSSL_DTLS else if (select_ret == TEST_TIMEOUT && wolfSSL_dtls(ssl) && - wolfSSL_dtls_got_timeout(ssl) >= 0) { + wolfSSL_dtls_got_timeout(ssl) >= 0) { error = SSL_ERROR_WANT_READ; } #endif @@ -436,6 +445,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) int disableCRL = 0; int externalTest = 0; int ret; + int err = 0; int scr = 0; /* allow secure renegotiation */ int forceScr = 0; /* force client initiaed scr */ int trackMemory = 0; @@ -1170,27 +1180,40 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) if (nonBlocking) { wolfSSL_set_using_nonblock(ssl, 1); tcp_set_nonblocking(&sockfd); - NonBlockingSSL_Connect(ssl); + NonBlockingSSL_Connect(ctx, ssl); } - else if (wolfSSL_connect(ssl) != SSL_SUCCESS) { - /* see note at top of README */ - int err = wolfSSL_get_error(ssl, 0); - char buffer[WOLFSSL_MAX_ERROR_SZ]; - printf("err = %d, %s\n", err, - wolfSSL_ERR_error_string(err, buffer)); - err_sys("SSL_connect failed"); - /* if you're getting an error here */ + else { + do { +#ifdef WOLFSSL_ASYNC_CRYPT + if (err == WC_PENDING_E) { + ret = AsyncCryptPoll(ctx, ssl); + if (ret < 0) { break; } else if (ret == 0) { continue; } + } +#endif + err = 0; /* Reset error */ + ret = wolfSSL_connect(ssl); + if (ret != SSL_SUCCESS) { + err = wolfSSL_get_error(ssl, 0); + } + } while (ret != SSL_SUCCESS && err == WC_PENDING_E); + + if (ret != SSL_SUCCESS) { + char buffer[WOLFSSL_MAX_ERROR_SZ]; + printf("err = %d, %s\n", err, wolfSSL_ERR_error_string(err, buffer)); + err_sys("wolfSSL_connect failed"); + /* see note at top of README */ + /* if you're getting an error here */ + } } #else timeout.tv_sec = 2; timeout.tv_usec = 0; - NonBlockingSSL_Connect(ssl); /* will keep retrying on timeout */ + NonBlockingSSL_Connect(ctx, ssl); /* will keep retrying on timeout */ #endif showPeer(ssl); #ifdef HAVE_ALPN if (alpnList != NULL) { - int err; char *protocol_name = NULL; word16 protocol_nameSz = 0; @@ -1315,14 +1338,14 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) if (nonBlocking) { wolfSSL_set_using_nonblock(sslResume, 1); tcp_set_nonblocking(&sockfd); - NonBlockingSSL_Connect(sslResume); + NonBlockingSSL_Connect(ctx, sslResume); } else if (wolfSSL_connect(sslResume) != SSL_SUCCESS) err_sys("SSL resume failed"); #else timeout.tv_sec = 2; timeout.tv_usec = 0; - NonBlockingSSL_Connect(ssl); /* will keep retrying on timeout */ + NonBlockingSSL_Connect(ctx, ssl); /* will keep retrying on timeout */ #endif showPeer(sslResume); @@ -1333,7 +1356,6 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #ifdef HAVE_ALPN if (alpnList != NULL) { - int err; char *protocol_name = NULL; word16 protocol_nameSz = 0; diff --git a/examples/echoclient/echoclient.c b/examples/echoclient/echoclient.c index 04bbf0374..4957b7a34 100644 --- a/examples/echoclient/echoclient.c +++ b/examples/echoclient/echoclient.c @@ -68,6 +68,7 @@ void echoclient_test(void* args) SSL_CTX* ctx = 0; SSL* ssl = 0; + int ret = 0, err = 0; int doDTLS = 0; int doPSK = 0; int sendSz; @@ -173,7 +174,25 @@ void echoclient_test(void* args) Sleep(100); #endif - if (SSL_connect(ssl) != SSL_SUCCESS) err_sys("SSL_connect failed"); + do { +#ifdef WOLFSSL_ASYNC_CRYPT + if (err == WC_PENDING_E) { + ret = AsyncCryptPoll(ctx, ssl); + if (ret < 0) { break; } else if (ret == 0) { continue; } + } +#endif + err = 0; /* Reset error */ + ret = SSL_connect(ssl); + if (ret != SSL_SUCCESS) { + err = SSL_get_error(ssl, 0); + } + } while (ret != SSL_SUCCESS && err == WC_PENDING_E); + + if (ret != SSL_SUCCESS) { + char buffer[CYASSL_MAX_ERROR_SZ]; + printf("err = %d, %s\n", err, ERR_error_string(err, buffer)); + err_sys("SSL_connect failed"); + } while (fgets(msg, sizeof(msg), fin) != 0) { diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index 76bf3e57a..4318a5816 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -77,6 +77,7 @@ THREAD_RETURN CYASSL_THREAD echoserver_test(void* args) CYASSL_METHOD* method = 0; CYASSL_CTX* ctx = 0; + int ret = 0; int doDTLS = 0; int doPSK = 0; int outCreated = 0; @@ -228,6 +229,7 @@ THREAD_RETURN CYASSL_THREAD echoserver_test(void* args) int clientfd; int firstRead = 1; int gotFirstG = 0; + int err = 0; SOCKADDR_IN_T client; socklen_t client_len = sizeof(client); #ifndef CYASSL_DTLS @@ -260,7 +262,25 @@ THREAD_RETURN CYASSL_THREAD echoserver_test(void* args) #elif !defined(NO_DH) SetDH(ssl); /* will repick suites with DHE, higher than PSK */ #endif - if (CyaSSL_accept(ssl) != SSL_SUCCESS) { + + do { +#ifdef WOLFSSL_ASYNC_CRYPT + if (err == WC_PENDING_E) { + ret = AsyncCryptPoll(ctx, ssl); + if (ret < 0) { break; } else if (ret == 0) { continue; } + } +#endif + err = 0; /* Reset error */ + ret = CyaSSL_accept(ssl); + if (ret != SSL_SUCCESS) { + err = CyaSSL_get_error(ssl, 0); + } + } while (ret != SSL_SUCCESS && err == WC_PENDING_E); + + if (ret != SSL_SUCCESS) { + err = CyaSSL_get_error(ssl, 0); + char buffer[CYASSL_MAX_ERROR_SZ]; + printf("error = %d, %s\n", err, CyaSSL_ERR_error_string(err, buffer)); printf("SSL_accept failed\n"); CyaSSL_free(ssl); CloseSocket(clientfd); diff --git a/examples/server/server.c b/examples/server/server.c index d4937d280..0774a3142 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -71,7 +71,7 @@ -static void NonBlockingSSL_Accept(SSL* ssl) +static int NonBlockingSSL_Accept(SSL* ssl) { #ifndef CYASSL_CALLBACKS int ret = SSL_accept(ssl); @@ -120,8 +120,8 @@ static void NonBlockingSSL_Accept(SSL* ssl) error = SSL_FATAL_ERROR; } } - if (ret != SSL_SUCCESS) - err_sys("SSL_accept failed"); + + return ret; } /* Echo number of bytes specified by -e arg */ @@ -279,6 +279,7 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) int doListen = 1; int crlFlags = 0; int ret; + int err = 0; char* serverReadyFile = NULL; char* alpnList = NULL; unsigned char alpn_opt = 0; @@ -836,21 +837,44 @@ THREAD_RETURN CYASSL_THREAD server_test(void* args) if (nonBlocking) { CyaSSL_set_using_nonblock(ssl, 1); tcp_set_nonblocking(&clientfd); - NonBlockingSSL_Accept(ssl); - } else if (SSL_accept(ssl) != SSL_SUCCESS) { - int err = SSL_get_error(ssl, 0); + } +#endif + + do { +#ifdef WOLFSSL_ASYNC_CRYPT + if (err == WC_PENDING_E) { + ret = AsyncCryptPoll(ctx, ssl); + if (ret < 0) { break; } else if (ret == 0) { continue; } + } +#endif + + err = 0; /* Reset error */ +#ifndef CYASSL_CALLBACKS + if (nonBlocking) { + ret = NonBlockingSSL_Accept(ssl); + } + else { + ret = SSL_accept(ssl); + } +#else + ret = NonBlockingSSL_Accept(ssl); +#endif + if (ret != SSL_SUCCESS) { + err = SSL_get_error(ssl, 0); + } + } while (ret != SSL_SUCCESS && err == WC_PENDING_E); + + if (ret != SSL_SUCCESS) { + err = SSL_get_error(ssl, 0); char buffer[CYASSL_MAX_ERROR_SZ]; printf("error = %d, %s\n", err, ERR_error_string(err, buffer)); err_sys("SSL_accept failed"); } -#else - NonBlockingSSL_Accept(ssl); -#endif + showPeer(ssl); #ifdef HAVE_ALPN if (alpnList != NULL) { - int err; char *protocol_name = NULL, *list = NULL; word16 protocol_nameSz = 0, listSz = 0; diff --git a/src/include.am b/src/include.am index c65e8d263..5402934a9 100644 --- a/src/include.am +++ b/src/include.am @@ -250,4 +250,8 @@ if BUILD_SNIFFER src_libwolfssl_la_SOURCES += src/sniffer.c endif +if BUILD_ASYNCCRYPT +src_libwolfssl_la_SOURCES += src/async.c +endif + endif # !BUILD_CRYPTONLY diff --git a/src/internal.c b/src/internal.c old mode 100644 new mode 100755 index c1fa85438..60cc76706 --- a/src/internal.c +++ b/src/internal.c @@ -69,6 +69,8 @@ #define FALSE 0 #endif +#define ERROR_OUT(err, eLabel) { ret = (err); goto eLabel; } + #ifdef _MSC_VER /* disable for while(0) cases at the .c level for now */ #pragma warning(disable:4127) @@ -465,6 +467,61 @@ static INLINE void ato32(const byte* c, word32* u32) #endif /* HAVE_LIBZ */ +#ifdef HAVE_WOLF_EVENT +int wolfSSL_EventInit(WOLFSSL* ssl, WOLF_EVENT_TYPE type) +{ + if (!ssl) { + return BAD_FUNC_ARG; + } + + if (ssl->event.pending) { + WOLFSSL_MSG("ssl.event already pending!"); + return BAD_COND_E; + } + + XMEMSET(&ssl->event, 0, sizeof(WOLF_EVENT)); + ssl->event.ssl = ssl; + ssl->event.type = type; + + return 0; +} + +int wolfSSL_CTX_EventPush(WOLFSSL_CTX* ctx, WOLF_EVENT* event) +{ + int ret; + + if (ctx == NULL || event == NULL) { + return BAD_FUNC_ARG; + } + +#ifndef SINGLE_THREADED + if (LockMutex(&ctx->event_queue.lock) != 0) { + return BAD_MUTEX_E; + } +#endif + + /* Setup event */ + event->next = NULL; + event->pending = 1; + + if (ctx->event_queue.tail == NULL) { + ctx->event_queue.head = event; + } + else { + ctx->event_queue.tail->next = event; + } + ctx->event_queue.tail = event; /* add to the end either way */ + ret = 0; + +#ifndef SINGLE_THREADED + UnLockMutex(&ctx->event_queue.lock); +#endif + + return ret; +} +#endif /* HAVE_WOLF_EVENT */ + + void InitSSL_Method(WOLFSSL_METHOD* method, ProtocolVersion pv) { method->version = pv; @@ -542,6 +599,16 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method) ctx->ticketHint = SESSION_TICKET_HINT_DEFAULT; #endif +#ifdef HAVE_WOLF_EVENT + XMEMSET(&ctx->event_queue, 0, sizeof(WOLF_EVENT_QUEUE)); + #ifndef SINGLE_THREADED + if (InitMutex(&ctx->event_queue.lock) < 0) { + WOLFSSL_MSG("Mutex error on CTX event queue init"); + return BAD_MUTEX_E; + } + #endif +#endif /* HAVE_WOLF_EVENT */ + return 0; } @@ -553,6 +620,12 @@ void SSL_CtxResourceFree(WOLFSSL_CTX* ctx) (void)i; +#ifdef HAVE_WOLF_EVENT + #ifndef SINGLE_THREADED + FreeMutex(&ctx->event_queue.lock); + #endif +#endif /* HAVE_WOLF_EVENT */ + XFREE(ctx->method, ctx->heap, DYNAMIC_TYPE_METHOD); if (ctx->suites) XFREE(ctx->suites, ctx->heap, DYNAMIC_TYPE_SUITES); @@ -1697,9 +1770,78 @@ void FreeX509(WOLFSSL_X509* x509) #ifndef NO_RSA +int RsaSign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, + word32* outSz, RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx) +{ + int ret; + + (void)ssl; + (void)keyBuf; + (void)keySz; + (void)ctx; + +#if defined(WOLFSSL_ASYNC_CRYPT_TEST) + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->asyncCryptTest.type == ASYNC_TEST_NONE) + { + ssl->asyncCryptTest.type = ASYNC_TEST_RSA_SIGN; + ssl->asyncCryptTest.rsaSign.in = in; + ssl->asyncCryptTest.rsaSign.inSz = inSz; + ssl->asyncCryptTest.rsaSign.out = out; + ssl->asyncCryptTest.rsaSign.outSz = outSz; + ssl->asyncCryptTest.rsaSign.keyBuf = keyBuf; + ssl->asyncCryptTest.rsaSign.keySz = keySz; + ssl->asyncCryptTest.rsaSign.key = key; + #if defined(HAVE_PK_CALLBACKS) + ssl->asyncCryptTest.ctx = ctx; + #endif + return WC_PENDING_E; + } +#endif /* WOLFSSL_ASYNC_CRYPT_TEST */ + +#if defined(HAVE_PK_CALLBACKS) + if (ssl->ctx->RsaSignCb) { + ret = ssl->ctx->RsaSignCb(ssl, in, inSz, out, outSz, keyBuf, keySz, + ctx); + } + else +#endif /*HAVE_PK_CALLBACKS */ + { + ret = wc_RsaSSL_Sign(in, inSz, out, *outSz, key, ssl->rng); + } + if (ret > 0) { + *outSz = ret; + ret = 0; + } + + return ret; +} + +int RsaVerify(WOLFSSL* ssl, byte* in, word32 inSz, + byte** out, RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx) +{ + int ret; + + (void)ssl; + (void)keyBuf; + (void)keySz; + (void)ctx; + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaVerifyCb) { + ret = ssl->ctx->RsaVerifyCb(ssl, in, inSz, out, keyBuf, keySz, ctx); + } + else +#endif /*HAVE_PK_CALLBACKS */ + { + ret = wc_RsaSSL_VerifyInline(in, inSz, out, key); + } + return ret; +} + /* Verify RSA signature, 0 on success */ -int VerifyRsaSign(const byte* sig, word32 sigSz, - const byte* plain, word32 plainSz, RsaKey* key) +int VerifyRsaSign(WOLFSSL* ssl, const byte* sig, word32 sigSz, + const byte* plain, word32 plainSz, RsaKey* key) { #ifdef WOLFSSL_SMALL_STACK byte* verifySig = NULL; @@ -1709,6 +1851,8 @@ int VerifyRsaSign(const byte* sig, word32 sigSz, byte* out = NULL; /* inline result */ int ret; + (void)ssl; + WOLFSSL_ENTER("VerifyRsaSign"); if (sig == NULL || plain == NULL || key == NULL) { @@ -1745,8 +1889,261 @@ int VerifyRsaSign(const byte* sig, word32 sigSz, return ret; } +int RsaDec(WOLFSSL* ssl, byte* in, word32 inSz, byte** out, word32* outSz, + RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx) +{ + int ret; + + (void)ssl; + (void)keyBuf; + (void)keySz; + (void)ctx; + +#if defined(WOLFSSL_ASYNC_CRYPT_TEST) + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->asyncCryptTest.type == ASYNC_TEST_NONE) + { + ssl->asyncCryptTest.type = ASYNC_TEST_RSA_DEC; + ssl->asyncCryptTest.rsaDec.in = in; + ssl->asyncCryptTest.rsaDec.inSz = inSz; + ssl->asyncCryptTest.rsaDec.out = out; + ssl->asyncCryptTest.rsaDec.outSz = outSz; + ssl->asyncCryptTest.rsaDec.keyBuf = keyBuf; + ssl->asyncCryptTest.rsaDec.keySz = keySz; + ssl->asyncCryptTest.rsaDec.key = key; + #if defined(HAVE_PK_CALLBACKS) + ssl->asyncCryptTest.ctx = ctx; + #endif + return WC_PENDING_E; + } +#endif /* WOLFSSL_ASYNC_CRYPT_TEST */ + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->RsaDecCb) { + ret = ssl->ctx->RsaDecCb(ssl, in, inSz, out, keyBuf, keySz, + ctx); + } + else +#endif /* HAVE_PK_CALLBACKS */ + { + ret = wc_RsaPrivateDecryptInline(in, inSz, out, key); + } + + if (ret > 0) { + *outSz = ret; + ret = 0; + } + return ret; +} + #endif /* NO_RSA */ +#ifdef HAVE_ECC + +int EccSign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, + word32* outSz, ecc_key* key, byte* keyBuf, word32 keySz, void* ctx) +{ + int ret; + + (void)ssl; + (void)keyBuf; + (void)keySz; + (void)ctx; + +#if defined(WOLFSSL_ASYNC_CRYPT_TEST) + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->asyncCryptTest.type == ASYNC_TEST_NONE) + { + ssl->asyncCryptTest.type = ASYNC_TEST_ECC_SIGN; + ssl->asyncCryptTest.eccSign.in = in; + ssl->asyncCryptTest.eccSign.inSz = inSz; + ssl->asyncCryptTest.eccSign.out = out; + ssl->asyncCryptTest.eccSign.outSz = outSz; + ssl->asyncCryptTest.eccSign.keyBuf = keyBuf; + ssl->asyncCryptTest.eccSign.keySz = keySz; + ssl->asyncCryptTest.eccSign.key = key; + #if defined(HAVE_PK_CALLBACKS) + ssl->asyncCryptTest.ctx = ctx; + #endif + return WC_PENDING_E; + } +#endif /* WOLFSSL_ASYNC_CRYPT_TEST */ + +#if defined(HAVE_PK_CALLBACKS) + if (ssl->ctx->EccSignCb) { + ret = ssl->ctx->EccSignCb(ssl, in, inSz, out, outSz, keyBuf, + keySz, ctx); + } + else +#endif /* HAVE_PK_CALLBACKS */ + { + ret = wc_ecc_sign_hash(in, inSz, out, outSz, ssl->rng, key); + } + return ret; +} + +int EccVerify(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, + word32 outSz, ecc_key* key, byte* keyBuf, word32 keySz, + void* ctx) +{ + int ret, verify; + + (void)ssl; + (void)keyBuf; + (void)keySz; + (void)ctx; + +#ifdef HAVE_PK_CALLBACKS + if (ssl->ctx->EccVerifyCb) { + ret = ssl->ctx->EccVerifyCb(ssl, in, inSz, out, outSz, keyBuf, keySz, + &verify, ctx); + } + else +#endif + { + ret = wc_ecc_verify_hash(in, inSz, out, outSz, &verify, key); + } + + ret = (ret != 0 || verify == 0) ? VERIFY_SIGN_ERROR : 0; + + return ret; +} + +int EccSharedSecret(WOLFSSL* ssl, ecc_key* priv_key, ecc_key* pub_key, + byte* out, word32* outSz) +{ + int ret; + + (void)ssl; + +#if defined(WOLFSSL_ASYNC_CRYPT_TEST) + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->asyncCryptTest.type == ASYNC_TEST_NONE) + { + ssl->asyncCryptTest.type = ASYNC_TEST_ECC_SHARED_SEC; + ssl->asyncCryptTest.eccSharedSec.private_key = priv_key; + ssl->asyncCryptTest.eccSharedSec.public_key = pub_key; + ssl->asyncCryptTest.eccSharedSec.out = out; + ssl->asyncCryptTest.eccSharedSec.outLen = outSz; + return WC_PENDING_E; + } +#endif /* WOLFSSL_ASYNC_CRYPT_TEST */ + + ret = wc_ecc_shared_secret(priv_key, pub_key, out, outSz); + + return ret; +} + +int EccMakeTempKey(WOLFSSL* ssl) +{ + int ret = 0; + if (ssl->eccTempKeyPresent == 0) { + #if defined(WOLFSSL_ASYNC_CRYPT_TEST) + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->asyncCryptTest.type == ASYNC_TEST_NONE) + { + ssl->asyncCryptTest.type = ASYNC_TEST_ECC_TMPKEY_GEN; + return WC_PENDING_E; + } + #endif /* WOLFSSL_ASYNC_CRYPT_TEST */ + + ret = wc_ecc_make_key(ssl->rng, ssl->eccTempKeySz, + ssl->eccTempKey); + if (ret == MP_OKAY) { + ssl->eccTempKeyPresent = 1; + ret = 0; + } + } + return ret; +} + +#endif /* HAVE_ECC */ + +#if !defined(NO_DH) + +int DhGenKeyPair(WOLFSSL* ssl, + byte* p, word32 pSz, + byte* g, word32 gSz, + byte* priv, word32* privSz, + byte* pub, word32* pubSz) +{ + int ret; + DhKey dhKey; + +#if defined(WOLFSSL_ASYNC_CRYPT_TEST) + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->asyncCryptTest.type == ASYNC_TEST_NONE) + { + ssl->asyncCryptTest.type = ASYNC_TEST_DH_GEN; + ssl->asyncCryptTest.dhGen.p = p; + ssl->asyncCryptTest.dhGen.pSz = pSz; + ssl->asyncCryptTest.dhGen.g = g; + ssl->asyncCryptTest.dhGen.gSz = gSz; + ssl->asyncCryptTest.dhGen.priv = priv; + ssl->asyncCryptTest.dhGen.privSz = privSz; + ssl->asyncCryptTest.dhGen.pub = pub; + ssl->asyncCryptTest.dhGen.pubSz = pubSz; + return WC_PENDING_E; + } +#endif /* WOLFSSL_ASYNC_CRYPT_TEST */ + + wc_InitDhKey(&dhKey); + ret = wc_DhSetKey(&dhKey, p, pSz, g, gSz); + if (ret == 0) { + ret = wc_DhGenerateKeyPair(&dhKey, ssl->rng, priv, privSz, pub, pubSz); + } + wc_FreeDhKey(&dhKey); + return ret; +} + +int DhAgree(WOLFSSL* ssl, + byte* p, word32 pSz, + byte* g, word32 gSz, + byte* priv, word32* privSz, + byte* pub, word32* pubSz, + const byte* otherPub, word32 otherPubSz, + byte* agree, word32* agreeSz) +{ + int ret; + DhKey dhKey; + +#if defined(WOLFSSL_ASYNC_CRYPT_TEST) + if (ssl->options.side == WOLFSSL_SERVER_END && + ssl->asyncCryptTest.type == ASYNC_TEST_NONE) + { + ssl->asyncCryptTest.type = ASYNC_TEST_DH_AGREE; + ssl->asyncCryptTest.dhAgree.p = p; + ssl->asyncCryptTest.dhAgree.pSz = pSz; + ssl->asyncCryptTest.dhAgree.g = g; + ssl->asyncCryptTest.dhAgree.gSz = gSz; + ssl->asyncCryptTest.dhAgree.priv = priv; + ssl->asyncCryptTest.dhAgree.privSz = privSz; + ssl->asyncCryptTest.dhAgree.pub = pub; + ssl->asyncCryptTest.dhAgree.pubSz = pubSz; + ssl->asyncCryptTest.dhAgree.otherPub = otherPub; + ssl->asyncCryptTest.dhAgree.otherPubSz = otherPubSz; + ssl->asyncCryptTest.dhAgree.agree = agree; + ssl->asyncCryptTest.dhAgree.agreeSz = agreeSz; + return WC_PENDING_E; + } +#endif /* WOLFSSL_ASYNC_CRYPT_TEST */ + + wc_InitDhKey(&dhKey); + ret = wc_DhSetKey(&dhKey, p, pSz, g, gSz); + if (ret == 0 && pub) { + /* for DH, encSecret is Yc, agree is pre-master */ + ret = wc_DhGenerateKeyPair(&dhKey, ssl->rng, priv, privSz, pub, pubSz); + } + if (ret == 0) { + ret = wc_DhAgree(&dhKey, agree, agreeSz, priv, *privSz, otherPub, otherPubSz); + } + wc_FreeDhKey(&dhKey); + + return ret; +} + +#endif /* !NO_DH */ + #endif /* NO_CERTS */ @@ -2092,6 +2489,43 @@ void FreeArrays(WOLFSSL* ssl, int keep) ssl->arrays = NULL; } +static void FreeKeyExchange(WOLFSSL* ssl) +{ + /* Cleanup signature buffer */ + if (ssl->buffers.sig.buffer) { + XFREE(ssl->buffers.sig.buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); + ssl->buffers.sig.buffer = NULL; + ssl->buffers.sig.length = 0; + } + + /* Free sigKey */ + if (ssl->sigKey) { + switch (ssl->sigType) + { + #ifndef NO_RSA + case DYNAMIC_TYPE_RSA: + { + wc_FreeRsaKey((RsaKey*)ssl->sigKey); + XFREE(ssl->sigKey, NULL, DYNAMIC_TYPE_RSA); + break; + } + #endif /* ! NO_RSA */ + #ifdef HAVE_ECC + case DYNAMIC_TYPE_ECC: + { + wc_ecc_free((ecc_key*)ssl->sigKey); + XFREE(ssl->sigKey, NULL, DYNAMIC_TYPE_ECC); + break; + } + #endif /* HAVE_ECC */ + default: + break; + } + /* Reset type and pointer */ + ssl->sigType = 0; + ssl->sigKey = NULL; + } +} /* In case holding SSL object in array and don't want to free actual ssl */ void SSL_ResourceFree(WOLFSSL* ssl) @@ -2104,6 +2538,7 @@ void SSL_ResourceFree(WOLFSSL* ssl) FreeCiphers(ssl); FreeArrays(ssl, 0); + FreeKeyExchange(ssl); wc_FreeRng(ssl->rng); XFREE(ssl->rng, ssl->heap, DYNAMIC_TYPE_RNG); XFREE(ssl->suites, ssl->heap, DYNAMIC_TYPE_SUITES); @@ -2379,6 +2814,9 @@ int DtlsPoolInit(WOLFSSL* ssl) int DtlsPoolSave(WOLFSSL* ssl, const byte *src, int sz) { DtlsPool *pool = ssl->dtls_pool; + if (src == NULL) { + return BAD_FUNC_ARG; + } if (pool != NULL && pool->used < DTLS_POOL_SZ) { buffer *pBuf = &pool->buf[pool->used]; pBuf->buffer = (byte*)XMALLOC(sz, ssl->heap, DYNAMIC_TYPE_DTLS_POOL); @@ -5788,7 +6226,8 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, /* hello_request not hashed */ /* Also, skip hashing the client_hello message here for DTLS. It will be * hashed later if the DTLS cookie is correct. */ - if (type != hello_request && !(ssl->options.dtls && type == client_hello)) { + if (type != hello_request && !(ssl->options.dtls && type == client_hello) && + ssl->error != WC_PENDING_E) { ret = HashInput(ssl, input + *inOutIdx, size); if (ret != 0) return ret; } @@ -7395,7 +7834,8 @@ int ProcessReply(WOLFSSL* ssl) atomicUser = 1; #endif - if (ssl->error != 0 && ssl->error != WANT_READ && ssl->error != WANT_WRITE){ + if (ssl->error != 0 && ssl->error != WANT_READ && + ssl->error != WANT_WRITE && ssl->error != WC_PENDING_E) { WOLFSSL_MSG("ProcessReply retry in error state, not allowed"); return ssl->error; } @@ -7768,7 +8208,7 @@ int ProcessReply(WOLFSSL* ssl) ssl->options.processReply = doProcessInit; /* input exhausted? */ - if (ssl->buffers.inputBuffer.idx == ssl->buffers.inputBuffer.length) + if (ssl->buffers.inputBuffer.idx >= ssl->buffers.inputBuffer.length) return 0; /* more messages per record */ @@ -9056,7 +9496,7 @@ int SendData(WOLFSSL* ssl, const void* data, int sz) ret, dtlsExtra = 0; - if (ssl->error == WANT_WRITE) + if (ssl->error == WANT_WRITE || ssl->error == WC_PENDING_E) ssl->error = 0; if (ssl->options.handShakeState != HANDSHAKE_DONE) { @@ -9171,7 +9611,7 @@ int ReceiveData(WOLFSSL* ssl, byte* output, int sz, int peek) WOLFSSL_ENTER("ReceiveData()"); - if (ssl->error == WANT_READ) + if (ssl->error == WANT_READ || ssl->error == WC_PENDING_E) ssl->error = 0; if (ssl->error != 0 && ssl->error != WANT_WRITE) { @@ -9661,6 +10101,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case OCSP_INVALID_STATUS: return "Invalid OCSP Status Error"; + case ASYNC_NOT_PENDING: + return "Async operation not pending"; + default : return "unknown error number"; } @@ -11455,7 +11898,6 @@ static void PickHashSigAlgo(WOLFSSL* ssl, word16 length = 0; word32 begin = *inOutIdx; int ret = 0; - #define ERROR_OUT(err, eLabel) do { ret = err; goto eLabel; } while(0) (void)length; /* shut up compiler warnings */ (void)begin; @@ -12140,32 +12582,25 @@ static void PickHashSigAlgo(WOLFSSL* ssl, case rsa_sa_algo: { byte* out = NULL; - byte doUserRsa = 0; word32 verifiedSz = 0; - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->RsaVerifyCb) - doUserRsa = 1; - #endif /*HAVE_PK_CALLBACKS */ - if (ssl->peerRsaKey == NULL || !ssl->peerRsaKeyPresent) { ERROR_OUT(NO_PEER_KEY, done); } - if (doUserRsa) { + verifiedSz = RsaVerify(ssl, + (byte *)input + *inOutIdx, + length, + &out, + ssl->peerRsaKey, #ifdef HAVE_PK_CALLBACKS - verifiedSz = ssl->ctx->RsaVerifyCb(ssl, - (byte *)input + *inOutIdx, - length, &out, - ssl->buffers.peerRsaKey.buffer, - ssl->buffers.peerRsaKey.length, - ssl->RsaVerifyCtx); - #endif /*HAVE_PK_CALLBACKS */ - } - else { - verifiedSz = wc_RsaSSL_VerifyInline((byte *)input + *inOutIdx, - length, &out, ssl->peerRsaKey); - } + ssl->buffers.peerRsaKey.buffer, + ssl->buffers.peerRsaKey.length, + ssl->RsaVerifyCtx + #else + NULL, 0, NULL + #endif + ); if (IsAtLeastTLSv1_2(ssl)) { word32 encSigSz; @@ -12248,7 +12683,6 @@ static void PickHashSigAlgo(WOLFSSL* ssl, /* ecdsa */ case ecc_dsa_sa_algo: { - int verify = 0; #ifndef NO_OLD_TLS byte* digest = &hash[MD5_DIGEST_SIZE]; word32 digestSz = SHA_DIGEST_SIZE; @@ -12256,13 +12690,6 @@ static void PickHashSigAlgo(WOLFSSL* ssl, byte* digest = hash256; word32 digestSz = SHA256_DIGEST_SIZE; #endif - byte doUserEcc = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->EccVerifyCb) { - doUserEcc = 1; - } - #endif if (!ssl->peerEccDsaKeyPresent) ERROR_OUT(NO_PEER_KEY, done); @@ -12293,22 +12720,19 @@ static void PickHashSigAlgo(WOLFSSL* ssl, #endif } } - if (doUserEcc) { + + ret = EccVerify(ssl, + input + *inOutIdx, length, + digest, digestSz, + ssl->peerEccDsaKey, #ifdef HAVE_PK_CALLBACKS - ret = ssl->ctx->EccVerifyCb(ssl, input + *inOutIdx, length, - digest, digestSz, - ssl->buffers.peerEccDsaKey.buffer, - ssl->buffers.peerEccDsaKey.length, - &verify, ssl->EccVerifyCtx); + ssl->buffers.peerEccDsaKey.buffer, + ssl->buffers.peerEccDsaKey.length, + ssl->EccVerifyCtx + #else + NULL, 0, NULL #endif - } - else { - ret = wc_ecc_verify_hash(input + *inOutIdx, length, - digest, digestSz, &verify, ssl->peerEccDsaKey); - } - if (ret != 0 || verify == 0) { - ERROR_OUT(VERIFY_SIGN_ERROR, done); - } + ); break; } #endif /* HAVE_ECC */ @@ -12379,8 +12803,6 @@ static void PickHashSigAlgo(WOLFSSL* ssl, #else /* !NO_DH or HAVE_ECC */ return NOT_COMPILED_IN; /* not supported by build */ #endif /* !NO_DH or HAVE_ECC */ - - #undef ERROR_OUT } @@ -12848,10 +13270,9 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) byte priv[ENCRYPT_LEN]; #endif word32 privSz = 0; - DhKey key; - if (serverP.buffer == 0 || serverG.buffer == 0 || - serverPub.buffer == 0) { + if (serverP.buffer == NULL || serverG.buffer == NULL || + serverPub.buffer == NULL) { #ifdef WOLFSSL_SMALL_STACK XFREE(encSecret, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif @@ -12867,21 +13288,17 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) } #endif - wc_InitDhKey(&key); - ret = wc_DhSetKey(&key, serverP.buffer, serverP.length, - serverG.buffer, serverG.length); - if (ret == 0) - /* for DH, encSecret is Yc, agree is pre-master */ - ret = wc_DhGenerateKeyPair(&key, ssl->rng, priv, &privSz, - encSecret, &encSz); - if (ret == 0) - ret = wc_DhAgree(&key, ssl->arrays->preMasterSecret, - &ssl->arrays->preMasterSz, priv, privSz, - serverPub.buffer, serverPub.length); + ret = DhAgree(ssl, + serverP.buffer, serverP.length, + serverG.buffer, serverG.length, + priv, &privSz, + encSecret, &encSz, + serverPub.buffer, serverPub.length, + ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz); + #ifdef WOLFSSL_SMALL_STACK XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif - wc_FreeDhKey(&key); } break; #endif /* NO_DH */ @@ -12945,7 +13362,6 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) word32 privSz = 0; word32 pubSz = 0; word32 esSz = 0; - DhKey key; if (serverP.buffer == 0 || serverG.buffer == 0 || serverPub.buffer == 0) { @@ -12992,19 +13408,15 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) XMEMCPY(es, ssl->arrays->client_identity, esSz); es += esSz; encSz = esSz + OPAQUE16_LEN; + + ret = DhAgree(ssl, + serverP.buffer, serverP.length, + serverG.buffer, serverG.length, + priv, &privSz, + es + OPAQUE16_LEN, &pubSz, + serverPub.buffer, serverPub.length, + pms + OPAQUE16_LEN, &ssl->arrays->preMasterSz); - wc_InitDhKey(&key); - ret = wc_DhSetKey(&key, serverP.buffer, serverP.length, - serverG.buffer, serverG.length); - if (ret == 0) - /* for DH, encSecret is Yc, agree is pre-master */ - ret = wc_DhGenerateKeyPair(&key, ssl->rng, priv, &privSz, - es + OPAQUE16_LEN, &pubSz); - if (ret == 0) - ret = wc_DhAgree(&key, pms + OPAQUE16_LEN, - &ssl->arrays->preMasterSz, priv, privSz, - serverPub.buffer, serverPub.length); - wc_FreeDhKey(&key); #ifdef WOLFSSL_SMALL_STACK XFREE(priv, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif @@ -13114,12 +13526,13 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) ret = ECC_EXPORT_ERROR; } else { - /* Create shared ECC key leaveing room at the begining + /* Create shared ECC key leaving room at the begining of buffer for size of shared key. Note sizeof preMasterSecret is ENCRYPT_LEN currently 512 */ size = sizeof(ssl->arrays->preMasterSecret) - OPAQUE16_LEN; - ret = wc_ecc_shared_secret(&myKey, peerKey, + + ret = EccSharedSecret(ssl, &myKey, peerKey, ssl->arrays->preMasterSecret + OPAQUE16_LEN, &size); if (ret != 0) { #ifdef WOLFSSL_SMALL_STACK @@ -13259,8 +13672,8 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) ret = ECC_EXPORT_ERROR; else { size = sizeof(ssl->arrays->preMasterSecret); - ret = wc_ecc_shared_secret(&myKey, peerKey, - ssl->arrays->preMasterSecret, &size); + ret = EccSharedSecret(ssl, &myKey, peerKey, + ssl->arrays->preMasterSecret, &size); if (ret != 0) ret = ECC_SHARED_ERROR; } @@ -13557,7 +13970,6 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) word32 localSz = MAX_ENCODED_SIG_SZ; word32 digestSz; byte* digest; - byte doUserEcc = 0; #ifndef NO_OLD_TLS /* old tls default */ digestSz = SHA_DIGEST_SIZE; @@ -13568,13 +13980,6 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) digest = ssl->hsHashes->certHashes.sha256; #endif - #ifdef HAVE_PK_CALLBACKS - #ifdef HAVE_ECC - if (ssl->ctx->EccSignCb) - doUserEcc = 1; - #endif /* HAVE_ECC */ - #endif /*HAVE_PK_CALLBACKS */ - if (IsAtLeastTLSv1_2(ssl)) { if (ssl->suites->hashAlgo == sha_mac) { #ifndef NO_SHA @@ -13602,36 +14007,28 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) } } - if (doUserEcc) { - #ifdef HAVE_PK_CALLBACKS - #ifdef HAVE_ECC - ret = ssl->ctx->EccSignCb(ssl, digest, digestSz, - encodedSig, &localSz, - ssl->buffers.key->buffer, - ssl->buffers.key->length, - ssl->EccSignCtx); - #endif /* HAVE_ECC */ - #endif /*HAVE_PK_CALLBACKS */ - } - else { - ret = wc_ecc_sign_hash(digest, digestSz, encodedSig, - &localSz, ssl->rng, &eccKey); - } + ret = EccSign(ssl, + digest, digestSz, + encodedSig, &localSz, + &eccKey, + #if defined(HAVE_PK_CALLBACKS) + ssl->buffers.key->buffer, + ssl->buffers.key->length, + ssl->EccSignCtx + #else + NULL, 0, NULL + #endif + ); if (ret == 0) { length = localSz; c16toa((word16)length, verify + extraSz); /* prepend hdr */ XMEMCPY(verify + extraSz + VERIFY_HEADER,encodedSig,length); } -#endif +#endif /* HAVE_ECC */ } #ifndef NO_RSA else { - byte doUserRsa = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->RsaSignCb) - doUserRsa = 1; - #endif /*HAVE_PK_CALLBACKS */ + word32 ioLen = ENCRYPT_LEN; if (IsAtLeastTLSv1_2(ssl)) { /* @@ -13695,28 +14092,28 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) } c16toa((word16)length, verify + extraSz); /* prepend hdr */ - if (doUserRsa) { - #ifdef HAVE_PK_CALLBACKS - #ifndef NO_RSA - word32 ioLen = ENCRYPT_LEN; - ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz, - verify + extraSz + VERIFY_HEADER, - &ioLen, - ssl->buffers.key->buffer, - ssl->buffers.key->length, - ssl->RsaSignCtx); - #endif /* NO_RSA */ - #endif /*HAVE_PK_CALLBACKS */ - } - else { - ret = wc_RsaSSL_Sign(signBuffer, signSz, verify + extraSz + - VERIFY_HEADER, ENCRYPT_LEN, &key, ssl->rng); - } - if (ret > 0) { + ret = RsaSign(ssl, + signBuffer, signSz, + verify + extraSz + VERIFY_HEADER, + &ioLen, + &key, + ssl->buffers.key->buffer, + ssl->buffers.key->length, + #ifdef HAVE_PK_CALLBACKS + ssl->RsaSignCtx + #else + NULL + #endif + ); + if (ret == 0) { /* check for signature faults */ - ret = VerifyRsaSign(verify + extraSz + VERIFY_HEADER, ret, - signBuffer, signSz, &key); + ret = VerifyRsaSign(ssl, + verify + extraSz + VERIFY_HEADER, + ioLen, + signBuffer, + signSz, + &key); } } #endif @@ -13726,45 +14123,45 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) if (ret == 0) { AddHeaders(output, length + extraSz + VERIFY_HEADER, - certificate_verify, ssl); + certificate_verify, ssl); - sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + length + + sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + length + extraSz + VERIFY_HEADER; - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - } - #endif + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif - if (IsEncryptionOn(ssl, 1)) { - byte* input; - int inputSz = sendSz - RECORD_HEADER_SZ; - /* build msg adds rec hdr */ - input = (byte*)XMALLOC(inputSz, ssl->heap, - DYNAMIC_TYPE_TMP_BUFFER); - if (input == NULL) - ret = MEMORY_E; - else { - XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz); - sendSz = BuildMessage(ssl, output, - MAX_CERT_VERIFY_SZ +MAX_MSG_EXTRA, - input, inputSz, handshake, 1); - XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (IsEncryptionOn(ssl, 1)) { + byte* input; + int inputSz = sendSz - RECORD_HEADER_SZ; + /* build msg adds rec hdr */ + input = (byte*)XMALLOC(inputSz, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (input == NULL) + ret = MEMORY_E; + else { + XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz); + sendSz = BuildMessage(ssl, output, + MAX_CERT_VERIFY_SZ +MAX_MSG_EXTRA, + input, inputSz, handshake, 1); + XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); - if (sendSz < 0) - ret = sendSz; - } - } else { - ret = HashOutput(ssl, output, sendSz, 0); - } + if (sendSz < 0) + ret = sendSz; + } + } else { + ret = HashOutput(ssl, output, sendSz, 0); + } - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) - return ret; - } - #endif + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) + return ret; + } + #endif } } #ifndef NO_RSA @@ -13788,9 +14185,9 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer) return 0; else return SendBuffered(ssl); - } + } else - return ret; + return ret; } #endif /* NO_CERTS */ @@ -14031,1714 +14428,1087 @@ int DoSessionTicket(WOLFSSL* ssl, int SendServerKeyExchange(WOLFSSL* ssl) { - int ret = 0; - #ifdef HAVE_QSH - word32 qshSz = 0; + int ret; + int sendSz = 0; + byte *output = NULL; + word32 idx = 0, sigSz = 0, length = 0; + #if defined(HAVE_ECC) || (!defined(NO_DH) && !defined(NO_RSA)) + byte *sigDataBuf = NULL; + word32 sigDataSz = 0; #endif + #if defined(HAVE_ECC) + byte *exportBuf = NULL; + word32 exportSz = 0; + #endif + (void)ssl; - #define ERROR_OUT(err, eLabel) do { ret = err; goto eLabel; } while(0) + (void)sigSz; - #ifdef HAVE_QSH - if (ssl->peerQSHKeyPresent && ssl->options.haveQSH) { - qshSz = QSH_KeyGetSize(ssl); + #ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_async_pop(ssl, WOLF_EVENT_TYPE_ASYNC_ACCEPT); + if (ret != ASYNC_NOT_PENDING) { + /* Check for error */ + if (ret < 0) { + goto exit_sske; + } + else { + /* Restore variables needed for async */ + output = ssl->async.output; + sendSz = ssl->async.sendSz; + idx = ssl->async.idx; + sigSz = ssl->async.sigSz; + length = ssl->async.length; + + /* Advance key share state */ + ssl->options.keyShareState++; + } + } + else + #endif + { + /* Reset state */ + ret = 0; + ssl->options.keyShareState = KEYSHARE_BEGIN; + } + + switch(ssl->options.keyShareState) + { + case KEYSHARE_BEGIN: + { + /* Do some checks / debug msgs */ + switch(ssl->specs.kea) + { + #if defined(HAVE_ECC) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + /* pub key size */ + WOLFSSL_MSG("Using ephemeral ECDH"); + break; + } + #endif /* HAVE_ECC && !NO_PSK */ + #ifdef HAVE_ECC + case ecc_diffie_hellman_kea: + { + if (ssl->specs.static_ecdh) { + WOLFSSL_MSG("Using Static ECDH, not sending ServerKeyExchange"); + ERROR_OUT(0, exit_sske); + } + + if (!ssl->buffers.key->buffer) { + ERROR_OUT(NO_PRIVATE_KEY, exit_sske); + } + + WOLFSSL_MSG("Using ephemeral ECDH"); + break; + } + #endif /* HAVE_ECC */ + } + + /* Preparing keys */ + switch(ssl->specs.kea) + { + #ifndef NO_PSK + case psk_kea: + { + /* Nothing to do in this sub-state */ + break; + } + #endif /* !NO_PSK */ + #if !defined(NO_DH) && (!defined(NO_PSK) || !defined(NO_RSA)) + #if !defined(NO_PSK) + case dhe_psk_kea: + #endif + #if !defined(NO_RSA) + case diffie_hellman_kea: + #endif + { + /* Allocate DH key buffers and generate key */ + if (ssl->buffers.serverDH_P.buffer == NULL || + ssl->buffers.serverDH_G.buffer == NULL) { + ERROR_OUT(NO_DH_PARAMS, exit_sske); + } + + if (ssl->buffers.serverDH_Pub.buffer == NULL) { + /* Free'd in SSL_ResourceFree and FreeHandshakeResources */ + ssl->buffers.serverDH_Pub.buffer = (byte*)XMALLOC( + ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap, + DYNAMIC_TYPE_DH); + if (ssl->buffers.serverDH_Pub.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + } + + if (ssl->buffers.serverDH_Priv.buffer == NULL) { + /* Free'd in SSL_ResourceFree and FreeHandshakeResources */ + ssl->buffers.serverDH_Priv.buffer = (byte*)XMALLOC( + ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap, + DYNAMIC_TYPE_DH); + if (ssl->buffers.serverDH_Priv.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + } + + ret = DhGenKeyPair(ssl, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length, + ssl->buffers.serverDH_Priv.buffer, + &ssl->buffers.serverDH_Priv.length, + ssl->buffers.serverDH_Pub.buffer, + &ssl->buffers.serverDH_Pub.length); + break; + } + #endif /* !defined(NO_DH) && (!defined(NO_PSK) || !defined(NO_RSA)) */ + #if defined(HAVE_ECC) && !defined(NO_PSK) + case ecdhe_psk_kea: + /* Fall through to create temp ECC key */ + #endif /* HAVE_ECC && !NO_PSK */ + #ifdef HAVE_ECC + case ecc_diffie_hellman_kea: + { + /* need ephemeral key now, create it if missing */ + if (ssl->eccTempKey == NULL) { + /* alloc/init on demand */ + ssl->eccTempKey = (ecc_key*)XMALLOC(sizeof(ecc_key), + ssl->ctx->heap, DYNAMIC_TYPE_ECC); + if (ssl->eccTempKey == NULL) { + WOLFSSL_MSG("EccTempKey Memory error"); + ERROR_OUT(MEMORY_E, exit_sske); + } + wc_ecc_init(ssl->eccTempKey); + } + ret = EccMakeTempKey(ssl); + break; + } + #endif /* HAVE_ECC */ + default: + /* Skip ServerKeyExchange */ + goto exit_sske; + } /* switch(ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_sske; + } + + /* Advance state and proceed */ + ssl->options.keyShareState = KEYSHARE_BUILD; + } /* case KEYSHARE_BEGIN */ + + case KEYSHARE_BUILD: + { + word32 preSigSz, preSigIdx; + + #ifdef HAVE_QSH + word32 qshSz = 0; + if (ssl->peerQSHKeyPresent && ssl->options.haveQSH) { + qshSz = QSH_KeyGetSize(ssl); + } + #endif + + switch(ssl->specs.kea) + { + #ifndef NO_PSK + case psk_kea: + { + idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + + if (ssl->arrays->server_hint[0] == 0) { + ERROR_OUT(0, exit_sske); /* don't send */ + } + + /* include size part */ + length = (word32)XSTRLEN(ssl->arrays->server_hint); + if (length > MAX_PSK_ID_LEN) { + ERROR_OUT(SERVER_HINT_ERROR, exit_sske); + } + + length += HINT_LEN_SZ; + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef HAVE_QSH + length += qshSz; + sendSz += qshSz; + #endif + + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { + goto exit_sske; + } + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, length, server_key_exchange, ssl); + + /* key data */ + #ifdef HAVE_QSH + c16toa((word16)(length - qshSz - HINT_LEN_SZ), output + idx); + #else + c16toa((word16)(length - HINT_LEN_SZ), output + idx); + #endif + + idx += HINT_LEN_SZ; + XMEMCPY(output + idx, ssl->arrays->server_hint, length - HINT_LEN_SZ); + break; + } + #endif /* !NO_PSK */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + word32 hintLen; + + idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + length = LENGTH_SZ * 3 + /* p, g, pub */ + ssl->buffers.serverDH_P.length + + ssl->buffers.serverDH_G.length + + ssl->buffers.serverDH_Pub.length; + + /* include size part */ + hintLen = (word32)XSTRLEN(ssl->arrays->server_hint); + if (hintLen > MAX_PSK_ID_LEN) { + ERROR_OUT(SERVER_HINT_ERROR, exit_sske); + } + length += hintLen + HINT_LEN_SZ; + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef HAVE_QSH + length += qshSz; + sendSz += qshSz; + #endif + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { + goto exit_sske; + } + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, length, server_key_exchange, ssl); + + /* key data */ + c16toa((word16)hintLen, output + idx); + idx += HINT_LEN_SZ; + XMEMCPY(output + idx, ssl->arrays->server_hint, hintLen); + idx += hintLen; + + /* add p, g, pub */ + c16toa((word16)ssl->buffers.serverDH_P.length, output + idx); + idx += LENGTH_SZ; + XMEMCPY(output + idx, ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length); + idx += ssl->buffers.serverDH_P.length; + + /* g */ + c16toa((word16)ssl->buffers.serverDH_G.length, output + idx); + idx += LENGTH_SZ; + XMEMCPY(output + idx, ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length); + idx += ssl->buffers.serverDH_G.length; + + /* pub */ + c16toa((word16)ssl->buffers.serverDH_Pub.length, output + idx); + idx += LENGTH_SZ; + XMEMCPY(output + idx, ssl->buffers.serverDH_Pub.buffer, + ssl->buffers.serverDH_Pub.length); + idx += ssl->buffers.serverDH_Pub.length; + break; + } + #endif /* !defined(NO_DH) && !defined(NO_PSK) */ + #if defined(HAVE_ECC) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + word32 hintLen; + + /* curve type, named curve, length(1) */ + idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + length = ENUM_LEN + CURVE_LEN + ENUM_LEN; + + exportSz = MAX_EXPORT_ECC_SZ; + exportBuf = (byte*)XMALLOC(exportSz, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (exportBuf == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + if (wc_ecc_export_x963(ssl->eccTempKey, exportBuf, &exportSz) != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_sske); + } + length += exportSz; + + /* include size part */ + hintLen = (word32)XSTRLEN(ssl->arrays->server_hint); + if (hintLen > MAX_PSK_ID_LEN) { + ERROR_OUT(SERVER_HINT_ERROR, exit_sske); + } + length += hintLen + HINT_LEN_SZ; + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef HAVE_QSH + length += qshSz; + sendSz += qshSz; + #endif + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + } + #endif + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { + goto exit_sske; + } + + /* get output buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* key data */ + c16toa((word16)hintLen, output + idx); + idx += HINT_LEN_SZ; + XMEMCPY(output + idx, ssl->arrays->server_hint, hintLen); + idx += hintLen; + + /* ECC key exchange data */ + output[idx++] = named_curve; + output[idx++] = 0x00; /* leading zero */ + output[idx++] = SetCurveId(wc_ecc_size(ssl->eccTempKey)); + output[idx++] = (byte)exportSz; + XMEMCPY(output + idx, exportBuf, exportSz); + break; + } + #endif /* HAVE_ECC && !NO_PSK */ + #ifdef HAVE_ECC + case ecc_diffie_hellman_kea: + { + int typeH = 0; + enum wc_HashType hashType = WC_HASH_TYPE_NONE; + + /* curve type, named curve, length(1) */ + idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + length = ENUM_LEN + CURVE_LEN + ENUM_LEN; + + /* Export temp ECC key and add to length */ + exportSz = MAX_EXPORT_ECC_SZ; + exportBuf = (byte*)XMALLOC(exportSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (exportBuf == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + if (wc_ecc_export_x963(ssl->eccTempKey, exportBuf, &exportSz) != 0) { + ERROR_OUT(ECC_EXPORT_ERROR, exit_sske); + } + length += exportSz; + + preSigSz = length; + preSigIdx = idx; + + switch(ssl->specs.sig_algo) + { + #ifndef NO_RSA + case rsa_sa_algo: + { + word32 i = 0; + ssl->sigKey = XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA); + if (ssl->sigKey == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + ssl->sigType = DYNAMIC_TYPE_RSA; + + ret = wc_InitRsaKey((RsaKey*)ssl->sigKey, ssl->heap); + if (ret != 0) { + goto exit_sske; + } + + ret = wc_RsaPrivateKeyDecode(ssl->buffers.key->buffer, &i, + (RsaKey*)ssl->sigKey, ssl->buffers.key->length); + if (ret != 0) { + goto exit_sske; + } + sigSz = wc_RsaEncryptSize((RsaKey*)ssl->sigKey); + break; + } + #endif /* !NO_RSA */ + case ecc_dsa_sa_algo: + { + word32 i = 0; + ssl->sigKey = XMALLOC(sizeof(ecc_key), NULL, DYNAMIC_TYPE_ECC); + if (ssl->sigKey == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + ssl->sigType = DYNAMIC_TYPE_ECC; + + wc_ecc_init((ecc_key*)ssl->sigKey); + + ret = wc_EccPrivateKeyDecode(ssl->buffers.key->buffer, &i, + (ecc_key*)ssl->sigKey, ssl->buffers.key->length); + if (ret != 0) { + goto exit_sske; + } + sigSz = wc_ecc_sig_size((ecc_key*)ssl->sigKey); /* worst case estimate */ + break; + } + default: + ERROR_OUT(ALGO_ID_E, exit_sske); /* unsupported type */ + } /* switch(ssl->specs.sig_algo) */ + + /* sig length */ + length += LENGTH_SZ; + length += sigSz; + + if (IsAtLeastTLSv1_2(ssl)) { + length += HASH_SIG_SIZE; + } + + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef HAVE_QSH + length += qshSz; + sendSz += qshSz; + #endif + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + preSigIdx = idx; + } + #endif + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { + goto exit_sske; + } + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + /* record and message headers will be added below, when we're sure + of the sig length */ + + /* key exchange data */ + output[idx++] = named_curve; + output[idx++] = 0x00; /* leading zero */ + output[idx++] = SetCurveId(wc_ecc_size(ssl->eccTempKey)); + output[idx++] = (byte)exportSz; + XMEMCPY(output + idx, exportBuf, exportSz); + idx += exportSz; + + /* Determine hash type */ + if (IsAtLeastTLSv1_2(ssl)) { + output[idx++] = ssl->suites->hashAlgo; + output[idx++] = ssl->suites->sigAlgo; + + switch (ssl->suites->hashAlgo) { + case sha512_mac: + #ifdef WOLFSSL_SHA512 + hashType = WC_HASH_TYPE_SHA512; + typeH = SHA512h; + #endif + break; + + case sha384_mac: + #ifdef WOLFSSL_SHA384 + hashType = WC_HASH_TYPE_SHA384; + typeH = SHA384h; + #endif + break; + + case sha256_mac: + #ifndef NO_SHA256 + hashType = WC_HASH_TYPE_SHA256; + typeH = SHA256h; + #endif + break; + + case sha_mac: + #ifndef NO_OLD_TLS + hashType = WC_HASH_TYPE_SHA; + typeH = SHAh; + #endif + break; + + default: + WOLFSSL_MSG("Bad hash sig algo"); + break; + } + + if (hashType == WC_HASH_TYPE_NONE) { + ERROR_OUT(ALGO_ID_E, exit_sske); + } + + } else { + /* only using sha and md5 for rsa */ + #ifndef NO_OLD_TLS + hashType = WC_HASH_TYPE_SHA; + if (ssl->suites->sigAlgo == rsa_sa_algo) { + hashType = WC_HASH_TYPE_MD5_SHA; + } + #else + ERROR_OUT(ALGO_ID_E, exit_sske); + #endif + } + + /* Signtaure length will be written later, when we're sure what it is */ + + #ifdef HAVE_FUZZER + if (ssl->fuzzerCb) { + ssl->fuzzerCb(ssl, output + preSigIdx, preSigSz, + FUZZ_SIGNATURE, ssl->fuzzerCtx); + } + #endif + + /* Assemble buffer to hash for signature */ + sigDataSz = RAN_LEN + RAN_LEN + preSigSz; + sigDataBuf = (byte*)XMALLOC(sigDataSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (sigDataBuf == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + XMEMCPY(sigDataBuf, ssl->arrays->clientRandom, RAN_LEN); + XMEMCPY(sigDataBuf+RAN_LEN, ssl->arrays->serverRandom, RAN_LEN); + XMEMCPY(sigDataBuf+RAN_LEN+RAN_LEN, output + preSigIdx, preSigSz); + + ssl->buffers.sig.length = wc_HashGetDigestSize(hashType); + ssl->buffers.sig.buffer = (byte*)XMALLOC(ssl->buffers.sig.length, + NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (ssl->buffers.sig.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + + /* Perform hash */ + ret = wc_Hash(hashType, sigDataBuf, sigDataSz, + ssl->buffers.sig.buffer, ssl->buffers.sig.length); + if (ret != 0) { + goto exit_sske; + } + + ssl->sigLen = sigSz; + + /* Sign hash to create signature */ + switch(ssl->specs.sig_algo) + { + #ifndef NO_RSA + case rsa_sa_algo: + { + /* For TLS 1.2 re-encode signature */ + if (IsAtLeastTLSv1_2(ssl)) { + byte* encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (encodedSig == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + + ssl->buffers.sig.length = wc_EncodeSignature(encodedSig, + ssl->buffers.sig.buffer, ssl->buffers.sig.length, typeH); + + /* Replace sig buffer with new one */ + XFREE(ssl->buffers.sig.buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); + ssl->buffers.sig.buffer = encodedSig; + } + + /* write sig size here */ + c16toa((word16)ssl->sigLen, output + idx); + idx += LENGTH_SZ; + + ret = RsaSign(ssl, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + output + idx, + &ssl->sigLen, + (RsaKey*)ssl->sigKey, + ssl->buffers.key->buffer, + ssl->buffers.key->length, + #ifdef HAVE_PK_CALLBACKS + ssl->RsaSignCtx + #else + NULL + #endif + ); + break; + } + #endif /* !NO_RSA */ + case ecc_dsa_sa_algo: + { + ret = EccSign(ssl, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + output + LENGTH_SZ + idx, + &ssl->sigLen, + (ecc_key*)ssl->sigKey, + #if defined(HAVE_PK_CALLBACKS) + ssl->buffers.key->buffer, + ssl->buffers.key->length, + ssl->EccSignCtx + #else + NULL, 0, NULL + #endif + ); + break; + } + } /* switch(ssl->specs.sig_algo) */ + break; + } + #endif /* HAVE_ECC */ + #if !defined(NO_DH) && !defined(NO_RSA) + case diffie_hellman_kea: + { + int typeH = 0; + enum wc_HashType hashType = WC_HASH_TYPE_NONE; + + idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + length = LENGTH_SZ * 3; /* p, g, pub */ + length += ssl->buffers.serverDH_P.length + + ssl->buffers.serverDH_G.length + + ssl->buffers.serverDH_Pub.length; + + preSigIdx = idx; + preSigSz = length; + + if (!ssl->options.usingAnon_cipher) { + word32 i = 0; + + ssl->sigKey = XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA); + if (ssl->sigKey == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + ssl->sigType = DYNAMIC_TYPE_RSA; + + ret = wc_InitRsaKey((RsaKey*)ssl->sigKey, ssl->heap); + if (ret != 0) { + goto exit_sske; + } + + /* sig length */ + length += LENGTH_SZ; + + if (!ssl->buffers.key->buffer) { + ERROR_OUT(NO_PRIVATE_KEY, exit_sske); + } + + ret = wc_RsaPrivateKeyDecode(ssl->buffers.key->buffer, &i, + (RsaKey*)ssl->sigKey, ssl->buffers.key->length); + if (ret != 0) { + goto exit_sske; + } + sigSz = wc_RsaEncryptSize((RsaKey*)ssl->sigKey); + length += sigSz; + + if (IsAtLeastTLSv1_2(ssl)) { + length += HASH_SIG_SIZE; + } + } + + sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; + + #ifdef HAVE_QSH + length += qshSz; + sendSz += qshSz; + #endif + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; + preSigIdx = idx; + } + #endif + + /* check for available size */ + if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { + goto exit_sske; + } + + /* get ouput buffer */ + output = ssl->buffers.outputBuffer.buffer + + ssl->buffers.outputBuffer.length; + + AddHeaders(output, length, server_key_exchange, ssl); + + /* add p, g, pub */ + c16toa((word16)ssl->buffers.serverDH_P.length, output + idx); + idx += LENGTH_SZ; + XMEMCPY(output + idx, ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length); + idx += ssl->buffers.serverDH_P.length; + + /* g */ + c16toa((word16)ssl->buffers.serverDH_G.length, output + idx); + idx += LENGTH_SZ; + XMEMCPY(output + idx, ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length); + idx += ssl->buffers.serverDH_G.length; + + /* pub */ + c16toa((word16)ssl->buffers.serverDH_Pub.length, output + idx); + idx += LENGTH_SZ; + XMEMCPY(output + idx, ssl->buffers.serverDH_Pub.buffer, + ssl->buffers.serverDH_Pub.length); + idx += ssl->buffers.serverDH_Pub.length; + + #ifdef HAVE_FUZZER + if (ssl->fuzzerCb) { + ssl->fuzzerCb(ssl, output + preSigIdx, preSigSz, + FUZZ_SIGNATURE, ssl->fuzzerCtx); + } + #endif + + /* Determine hash type */ + if (IsAtLeastTLSv1_2(ssl)) { + output[idx++] = ssl->suites->hashAlgo; + output[idx++] = ssl->suites->sigAlgo; + + switch (ssl->suites->hashAlgo) { + case sha512_mac: + #ifdef WOLFSSL_SHA512 + hashType = WC_HASH_TYPE_SHA512; + typeH = SHA512h; + #endif + break; + + case sha384_mac: + #ifdef WOLFSSL_SHA384 + hashType = WC_HASH_TYPE_SHA384; + typeH = SHA384h; + #endif + break; + + case sha256_mac: + #ifndef NO_SHA256 + hashType = WC_HASH_TYPE_SHA256; + typeH = SHA256h; + #endif + break; + + case sha_mac: + #ifndef NO_OLD_TLS + hashType = WC_HASH_TYPE_SHA; + typeH = SHAh; + #endif + break; + + default: + WOLFSSL_MSG("Bad hash sig algo"); + break; + } + + if (hashType == WC_HASH_TYPE_NONE) { + ERROR_OUT(ALGO_ID_E, exit_sske); + } + } else { + /* only using sha and md5 for rsa */ + #ifndef NO_OLD_TLS + hashType = WC_HASH_TYPE_SHA; + if (ssl->suites->sigAlgo == rsa_sa_algo) { + hashType = WC_HASH_TYPE_MD5_SHA; + } + #else + ERROR_OUT(ALGO_ID_E, exit_sske); + #endif + } + + /* signature size */ + c16toa((word16)sigSz, output + idx); + idx += LENGTH_SZ; + + /* Assemble buffer to hash for signature */ + sigDataSz = RAN_LEN + RAN_LEN + preSigSz; + sigDataBuf = (byte*)XMALLOC(sigDataSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (sigDataBuf == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + XMEMCPY(sigDataBuf, ssl->arrays->clientRandom, RAN_LEN); + XMEMCPY(sigDataBuf+RAN_LEN, ssl->arrays->serverRandom, RAN_LEN); + XMEMCPY(sigDataBuf+RAN_LEN+RAN_LEN, output + preSigIdx, preSigSz); + + ssl->buffers.sig.length = wc_HashGetDigestSize(hashType); + ssl->buffers.sig.buffer = (byte*)XMALLOC(ssl->buffers.sig.length, + NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (ssl->buffers.sig.buffer == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + + /* Perform hash */ + ret = wc_Hash(hashType, sigDataBuf, sigDataSz, + ssl->buffers.sig.buffer, ssl->buffers.sig.length); + if (ret != 0) { + goto exit_sske; + } + + ssl->sigLen = sigSz; + + /* Sign hash to create signature */ + switch (ssl->suites->sigAlgo) + { + #ifndef NO_RSA + case rsa_sa_algo: + { + /* For TLS 1.2 re-encode signature */ + if (IsAtLeastTLSv1_2(ssl)) { + byte* encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (encodedSig == NULL) { + ERROR_OUT(MEMORY_E, exit_sske); + } + + ssl->buffers.sig.length = wc_EncodeSignature(encodedSig, + ssl->buffers.sig.buffer, ssl->buffers.sig.length, typeH); + + /* Replace sig buffer with new one */ + XFREE(ssl->buffers.sig.buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); + ssl->buffers.sig.buffer = encodedSig; + } + + ret = RsaSign(ssl, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + output + idx, + &ssl->sigLen, + (RsaKey*)ssl->sigKey, + ssl->buffers.key->buffer, + ssl->buffers.key->length, + #ifdef HAVE_PK_CALLBACKS + ssl->RsaSignCtx + #else + NULL + #endif + ); + break; + } + #endif /* NO_RSA */ + } /* switch (ssl->suites->sigAlgo) */ + + break; + } + #endif /* !defined(NO_DH) && !defined(NO_RSA) */ + } /* switch(ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_sske; + } + + /* Advance state and proceed */ + ssl->options.keyShareState = KEYSHARE_VERIFY; + } /* case KEYSHARE_BUILD */ + + case KEYSHARE_VERIFY: + { + switch(ssl->specs.kea) + { + #ifndef NO_PSK + case psk_kea: + { + /* Nothing to do in this sub-state */ + break; + } + #endif /* !NO_PSK */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + /* Nothing to do in this sub-state */ + break; + } + #endif /* !defined(NO_DH) && !defined(NO_PSK) */ + #if defined(HAVE_ECC) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + /* Nothing to do in this sub-state */ + break; + } + #endif /* HAVE_ECC && !NO_PSK */ + #ifdef HAVE_ECC + case ecc_diffie_hellman_kea: + { + switch(ssl->specs.sig_algo) + { + #ifndef NO_RSA + case rsa_sa_algo: + { + /* check for signature faults */ + ret = VerifyRsaSign(ssl, + output + idx, + ssl->sigLen, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + (RsaKey*)ssl->sigKey); + break; + } + #endif + case ecc_dsa_sa_algo: + { + /* Now that we know the real sig size, write it. */ + c16toa((word16)ssl->sigLen, output + idx); + + /* And adjust length and sendSz from estimates */ + length += ssl->sigLen - sigSz; + sendSz += ssl->sigLen - sigSz; + break; + } + default: + ERROR_OUT(ALGO_ID_E, exit_sske); /* unsupported type */ + } /* switch(ssl->specs.sig_algo) */ + break; + } + #endif /* HAVE_ECC */ + #if !defined(NO_DH) && !defined(NO_RSA) + case diffie_hellman_kea: + { + switch (ssl->suites->sigAlgo) + { + #ifndef NO_RSA + case rsa_sa_algo: + { + /* check for signature faults */ + ret = VerifyRsaSign(ssl, + output + idx, + ssl->sigLen, + ssl->buffers.sig.buffer, + ssl->buffers.sig.length, + (RsaKey*)ssl->sigKey); + break; + } + #endif + } /* switch (ssl->suites->sigAlgo) */ + break; + } + #endif /* !defined(NO_DH) && !defined(NO_RSA) */ + } /* switch(ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_sske; + } + + /* Advance state and proceed */ + ssl->options.keyShareState = KEYSHARE_FINALIZE; + } /* case KEYSHARE_VERIFY */ + + case KEYSHARE_FINALIZE: + { + #ifdef HAVE_QSH + if (ssl->peerQSHKeyPresent) { + if (qshSz > 0) { + idx = sendSz - qshSz; + if (QSH_KeyExchangeWrite(ssl, 1) != 0) { + ERROR_OUT(MEMORY_E, exit_sske); + } + + /* extension type */ + c16toa(TLSX_QUANTUM_SAFE_HYBRID, output + idx); + idx += OPAQUE16_LEN; + + /* write to output and check amount written */ + if (TLSX_QSHPK_Write(ssl->QSH_secret->list, output + idx) + > qshSz - OPAQUE16_LEN) { + ERROR_OUT(MEMORY_E, exit_sske); + } + } + } + #endif + + #if defined(HAVE_ECC) + if (ssl->specs.kea == ecdhe_psk_kea || ssl->specs.kea == ecc_diffie_hellman_kea) { + AddHeaders(output, length, server_key_exchange, ssl); + } + #endif /* HAVE_ECC */ + + #ifdef WOLFSSL_DTLS + if (ssl->options.dtls) { + if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) { + goto exit_sske; + } + } + #endif + + ret = HashOutput(ssl, output, sendSz, 0); + if (ret != 0) { + goto exit_sske; + } + + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) { + AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); + } + if (ssl->toInfoOn) { + AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, output, + sendSz, ssl->heap); + } + #endif + + /* Check for error */ + if (ret != 0) { + goto exit_sske; + } + + /* Advance state and proceed */ + ssl->options.keyShareState = KEYSHARE_END; + } /* case KEYSHARE_FINALIZE */ + + case KEYSHARE_END: + { + ssl->buffers.outputBuffer.length += sendSz; + if (!ssl->options.groupMessages) { + ret = SendBuffered(ssl); + } + + ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; + break; + } + default: + ret = INPUT_CASE_ERROR; + } /* switch(ssl->options.keyShareState) */ + + exit_sske: + + /* Handle cleanup for stack variables here */ + #if defined(HAVE_ECC) + if (exportBuf) { + XFREE(exportBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + exportBuf = NULL; + } + #endif + #if defined(HAVE_ECC) || (!defined(NO_DH) && !defined(NO_RSA)) + if (sigDataBuf) { + XFREE(sigDataBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + sigDataBuf = NULL; } #endif +#ifdef WOLFSSL_ASYNC_CRYPT + /* Handle WC_PENDING_E */ + if (ret == WC_PENDING_E) { + /* Store variables needed for async */ + XMEMSET(&ssl->async, 0, sizeof(ssl->async)); + ssl->async.output = output; + ssl->async.sendSz = sendSz; + ssl->async.idx = idx; + ssl->async.length = length; + ssl->async.sigSz = sigSz; - switch(ssl->specs.kea) - { - #ifndef NO_PSK - case psk_kea: - { - byte *output; - word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - int sendSz; - if (ssl->arrays->server_hint[0] == 0) return 0; /* don't send */ - - /* include size part */ - length = (word32)XSTRLEN(ssl->arrays->server_hint); - if (length > MAX_PSK_ID_LEN) { - return SERVER_HINT_ERROR; - } - - length += HINT_LEN_SZ; - sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - - #ifdef HAVE_QSH - length += qshSz; - sendSz += qshSz; - #endif - - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - } - #endif - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { - return ret; - } - - /* get output buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - AddHeaders(output, length, server_key_exchange, ssl); - - /* key data */ - #ifdef HAVE_QSH - c16toa((word16)(length - qshSz - HINT_LEN_SZ), output + idx); - #else - c16toa((word16)(length - HINT_LEN_SZ), output + idx); - #endif - idx += HINT_LEN_SZ; - XMEMCPY(output + idx, ssl->arrays->server_hint,length -HINT_LEN_SZ); - - #ifdef HAVE_QSH - if (ssl->peerQSHKeyPresent) { - if (qshSz > 0) { - idx = sendSz - qshSz; - if (QSH_KeyExchangeWrite(ssl, 1) != 0) { - return MEMORY_E; - } - - /* extension type */ - c16toa(TLSX_QUANTUM_SAFE_HYBRID, output + idx); - idx += OPAQUE16_LEN; - - /* write to output and check amount written */ - if (TLSX_QSHPK_Write(ssl->QSH_secret->list, output + idx) - > qshSz - OPAQUE16_LEN) { - return MEMORY_E; - } - } - } - #endif - - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) { - return ret; - } - } - #endif - - ret = HashOutput(ssl, output, sendSz, 0); - if (ret != 0) { - return ret; - } - - #ifdef WOLFSSL_CALLBACKS - if (ssl->hsInfoOn) { - AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); - } - if (ssl->toInfoOn) { - AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, output, - sendSz, ssl->heap); - } - #endif - - ssl->buffers.outputBuffer.length += sendSz; - if (ssl->options.groupMessages) { - ret = 0; - } - else { - ret = SendBuffered(ssl); - } - ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; - break; - } - #endif /*NO_PSK */ - - #if !defined(NO_DH) && !defined(NO_PSK) - case dhe_psk_kea: - { - byte *output; - word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - word32 hintLen; - int sendSz; - DhKey dhKey; - - if (ssl->buffers.serverDH_P.buffer == NULL || - ssl->buffers.serverDH_G.buffer == NULL) { - return NO_DH_PARAMS; - } - - if (ssl->buffers.serverDH_Pub.buffer == NULL) { - ssl->buffers.serverDH_Pub.buffer = (byte*)XMALLOC( - ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap, - DYNAMIC_TYPE_DH); - if (ssl->buffers.serverDH_Pub.buffer == NULL) { - return MEMORY_E; - } - } - - if (ssl->buffers.serverDH_Priv.buffer == NULL) { - ssl->buffers.serverDH_Priv.buffer = (byte*)XMALLOC( - ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap, - DYNAMIC_TYPE_DH); - if (ssl->buffers.serverDH_Priv.buffer == NULL) { - return MEMORY_E; - } - } - - wc_InitDhKey(&dhKey); - ret = wc_DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer, - ssl->buffers.serverDH_P.length, - ssl->buffers.serverDH_G.buffer, - ssl->buffers.serverDH_G.length); + /* Push event to queue */ + ret = wolfSSL_async_push(ssl, WOLF_EVENT_TYPE_ASYNC_ACCEPT); if (ret == 0) { - ret = wc_DhGenerateKeyPair(&dhKey, ssl->rng, - ssl->buffers.serverDH_Priv.buffer, - &ssl->buffers.serverDH_Priv.length, - ssl->buffers.serverDH_Pub.buffer, - &ssl->buffers.serverDH_Pub.length); + return WC_PENDING_E; } - wc_FreeDhKey(&dhKey); - if (ret != 0) { - return ret; - } - - length = LENGTH_SZ * 3 + /* p, g, pub */ - ssl->buffers.serverDH_P.length + - ssl->buffers.serverDH_G.length + - ssl->buffers.serverDH_Pub.length; - - /* include size part */ - hintLen = (word32)XSTRLEN(ssl->arrays->server_hint); - if (hintLen > MAX_PSK_ID_LEN) { - return SERVER_HINT_ERROR; - } - length += hintLen + HINT_LEN_SZ; - sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - - #ifdef HAVE_QSH - length += qshSz; - sendSz += qshSz; - #endif - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - } - #endif - - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { - return ret; - } - - /* get output buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - AddHeaders(output, length, server_key_exchange, ssl); - - /* key data */ - c16toa((word16)hintLen, output + idx); - idx += HINT_LEN_SZ; - XMEMCPY(output + idx, ssl->arrays->server_hint, hintLen); - idx += hintLen; - - /* add p, g, pub */ - c16toa((word16)ssl->buffers.serverDH_P.length, output + idx); - idx += LENGTH_SZ; - XMEMCPY(output + idx, ssl->buffers.serverDH_P.buffer, - ssl->buffers.serverDH_P.length); - idx += ssl->buffers.serverDH_P.length; - - /* g */ - c16toa((word16)ssl->buffers.serverDH_G.length, output + idx); - idx += LENGTH_SZ; - XMEMCPY(output + idx, ssl->buffers.serverDH_G.buffer, - ssl->buffers.serverDH_G.length); - idx += ssl->buffers.serverDH_G.length; - - /* pub */ - c16toa((word16)ssl->buffers.serverDH_Pub.length, output + idx); - idx += LENGTH_SZ; - XMEMCPY(output + idx, ssl->buffers.serverDH_Pub.buffer, - ssl->buffers.serverDH_Pub.length); - idx += ssl->buffers.serverDH_Pub.length; - (void)idx; /* suppress analyzer warning, and keep idx current */ - - #ifdef HAVE_QSH - if (ssl->peerQSHKeyPresent) { - if (qshSz > 0) { - idx = sendSz - qshSz; - QSH_KeyExchangeWrite(ssl, 1); - - /* extension type */ - c16toa(TLSX_QUANTUM_SAFE_HYBRID, output + idx); - idx += OPAQUE16_LEN; - - /* write to output and check amount written */ - if (TLSX_QSHPK_Write(ssl->QSH_secret->list, output + idx) - > qshSz - OPAQUE16_LEN) { - return MEMORY_E; - } - } - } - #endif - - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) { - return ret; - } - } - #endif - - ret = HashOutput(ssl, output, sendSz, 0); - - if (ret != 0) { - return ret; - } - - #ifdef WOLFSSL_CALLBACKS - if (ssl->hsInfoOn) { - AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); - } - if (ssl->toInfoOn) { - AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, output, - sendSz, ssl->heap); - } - #endif - - ssl->buffers.outputBuffer.length += sendSz; - if (ssl->options.groupMessages) { - ret = 0; - } - else { - ret = SendBuffered(ssl); - } - ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; - break; } - #endif /* !NO_DH && !NO_PSK */ - - #if defined(HAVE_ECC) && !defined(NO_PSK) - case ecdhe_psk_kea: - { - word32 hintLen; - word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - int sendSz; - byte *output; - ecc_key dsaKey; - #ifdef WOLFSSL_SMALL_STACK - byte* exportBuf = NULL; - #else - byte exportBuf[MAX_EXPORT_ECC_SZ]; - #endif - word32 expSz = MAX_EXPORT_ECC_SZ; - - /* curve type, named curve, length(1) */ - length = ENUM_LEN + CURVE_LEN + ENUM_LEN; - /* pub key size */ - WOLFSSL_MSG("Using ephemeral ECDH"); - - /* need ephemeral key now, create it if missing */ - if (ssl->eccTempKey == NULL) { - /* alloc/init on demand */ - ssl->eccTempKey = (ecc_key*)XMALLOC(sizeof(ecc_key), - ssl->ctx->heap, DYNAMIC_TYPE_ECC); - if (ssl->eccTempKey == NULL) { - WOLFSSL_MSG("EccTempKey Memory error"); - return MEMORY_E; - } - wc_ecc_init(ssl->eccTempKey); - } - if (ssl->eccTempKeyPresent == 0) { - if (wc_ecc_make_key(ssl->rng, ssl->eccTempKeySz, - ssl->eccTempKey) != 0) { - return ECC_MAKEKEY_ERROR; - } - ssl->eccTempKeyPresent = 1; - } - - #ifdef WOLFSSL_SMALL_STACK - exportBuf = (byte*)XMALLOC(MAX_EXPORT_ECC_SZ, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (exportBuf == NULL) { - return MEMORY_E; - } - #endif - - if (wc_ecc_export_x963(ssl->eccTempKey, exportBuf, &expSz) != 0) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(exportBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return ECC_EXPORT_ERROR; - } - length += expSz; - - /* include size part */ - hintLen = (word32)XSTRLEN(ssl->arrays->server_hint); - if (hintLen > MAX_PSK_ID_LEN) { - #ifdef WOLFSSL_SMALL_STACK - XFREE(exportBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return SERVER_HINT_ERROR; - } - length += hintLen + HINT_LEN_SZ; - sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - - #ifdef HAVE_QSH - length += qshSz; - sendSz += qshSz; - #endif - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - } - #endif - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { - wc_ecc_free(&dsaKey); - #ifdef WOLFSSL_SMALL_STACK - XFREE(exportBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - return ret; - } - - /* get output buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - /* key data */ - c16toa((word16)hintLen, output + idx); - idx += HINT_LEN_SZ; - XMEMCPY(output + idx, ssl->arrays->server_hint, hintLen); - idx += hintLen; - - /* ECC key exchange data */ - output[idx++] = named_curve; - output[idx++] = 0x00; /* leading zero */ - output[idx++] = SetCurveId(wc_ecc_size(ssl->eccTempKey)); - output[idx++] = (byte)expSz; - XMEMCPY(output + idx, exportBuf, expSz); - #ifdef WOLFSSL_SMALL_STACK - XFREE(exportBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - - #ifdef HAVE_QSH - if (ssl->peerQSHKeyPresent) { - if (qshSz > 0) { - idx = sendSz - qshSz; - QSH_KeyExchangeWrite(ssl, 1); - - /* extension type */ - c16toa(TLSX_QUANTUM_SAFE_HYBRID, output + idx); - idx += OPAQUE16_LEN; - - /* write to output and check amount written */ - if (TLSX_QSHPK_Write(ssl->QSH_secret->list, output + idx) - > qshSz - OPAQUE16_LEN) { - return MEMORY_E; - } - } - } - #endif - - - AddHeaders(output, length, server_key_exchange, ssl); - - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) { - return ret; - } - } - #endif - - ret = HashOutput(ssl, output, sendSz, 0); - - if (ret != 0) { - return ret; - } - - #ifdef WOLFSSL_CALLBACKS - if (ssl->hsInfoOn) { - AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); - } - if (ssl->toInfoOn) { - AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, output, - sendSz, ssl->heap); - } - #endif - - ssl->buffers.outputBuffer.length += sendSz; - if (ssl->options.groupMessages) { - ret = 0; - } - else { - ret = SendBuffered(ssl); - } - ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; - break; - } - #endif /* HAVE_ECC && !NO_PSK */ - - #ifdef HAVE_ECC - case ecc_diffie_hellman_kea: - { - byte *output; - word32 length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - int sendSz; - word32 sigSz; - word32 preSigSz, preSigIdx; - #ifndef NO_RSA - RsaKey rsaKey; - #endif - ecc_key dsaKey; - #ifdef WOLFSSL_SMALL_STACK - byte* exportBuf = NULL; - #else - byte exportBuf[MAX_EXPORT_ECC_SZ]; - #endif - word32 expSz = MAX_EXPORT_ECC_SZ; - - #ifndef NO_OLD_TLS - byte doMd5 = 0; - byte doSha = 0; - #endif - #ifndef NO_SHA256 - byte doSha256 = 0; - #endif - #ifdef WOLFSSL_SHA384 - byte doSha384 = 0; - #endif - #ifdef WOLFSSL_SHA512 - byte doSha512 = 0; - #endif - - if (ssl->specs.static_ecdh) { - WOLFSSL_MSG("Using Static ECDH, not sending ServerKeyExchange"); - return 0; - } - - /* curve type, named curve, length(1) */ - length = ENUM_LEN + CURVE_LEN + ENUM_LEN; - /* pub key size */ - WOLFSSL_MSG("Using ephemeral ECDH"); - - /* need ephemeral key now, create it if missing */ - if (ssl->eccTempKey == NULL) { - /* alloc/init on demand */ - ssl->eccTempKey = (ecc_key*)XMALLOC(sizeof(ecc_key), - ssl->ctx->heap, DYNAMIC_TYPE_ECC); - if (ssl->eccTempKey == NULL) { - WOLFSSL_MSG("EccTempKey Memory error"); - return MEMORY_E; - } - wc_ecc_init(ssl->eccTempKey); - } - if (ssl->eccTempKeyPresent == 0) { - if (wc_ecc_make_key(ssl->rng, ssl->eccTempKeySz, - ssl->eccTempKey) != 0) { - return ECC_MAKEKEY_ERROR; - } - ssl->eccTempKeyPresent = 1; - } - - #ifdef WOLFSSL_SMALL_STACK - exportBuf = (byte*)XMALLOC(MAX_EXPORT_ECC_SZ, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (exportBuf == NULL) { - return MEMORY_E; - } - #endif - - if (wc_ecc_export_x963(ssl->eccTempKey, exportBuf, &expSz) != 0) { - ERROR_OUT(ECC_EXPORT_ERROR, done_a); - } - length += expSz; - - preSigSz = length; - preSigIdx = idx; - - #ifndef NO_RSA - ret = wc_InitRsaKey(&rsaKey, ssl->heap); - if (ret != 0) { - goto done_a; - } - #endif - - wc_ecc_init(&dsaKey); - - /* sig length */ - length += LENGTH_SZ; - - if (!ssl->buffers.key || !ssl->buffers.key->buffer) { - #ifndef NO_RSA - wc_FreeRsaKey(&rsaKey); - #endif - wc_ecc_free(&dsaKey); - ERROR_OUT(NO_PRIVATE_KEY, done_a); - } - - #ifndef NO_RSA - if (ssl->specs.sig_algo == rsa_sa_algo) { - /* rsa sig size */ - word32 i = 0; - ret = wc_RsaPrivateKeyDecode(ssl->buffers.key->buffer, &i, - &rsaKey, ssl->buffers.key->length); - if (ret != 0) { - goto done_a; - } - sigSz = wc_RsaEncryptSize(&rsaKey); - } else - #endif - - if (ssl->specs.sig_algo == ecc_dsa_sa_algo) { - /* ecdsa sig size */ - word32 i = 0; - ret = wc_EccPrivateKeyDecode(ssl->buffers.key->buffer, &i, - &dsaKey, ssl->buffers.key->length); - if (ret != 0) { - goto done_a; - } - sigSz = wc_ecc_sig_size(&dsaKey); /* worst case estimate */ - } - else { - #ifndef NO_RSA - wc_FreeRsaKey(&rsaKey); - #endif - wc_ecc_free(&dsaKey); - ERROR_OUT(ALGO_ID_E, done_a); /* unsupported type */ - } - length += sigSz; - - if (IsAtLeastTLSv1_2(ssl)) { - length += HASH_SIG_SIZE; - } - - sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - - #ifdef HAVE_QSH - length += qshSz; - sendSz += qshSz; - #endif - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - preSigIdx = idx; - } - #endif - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { - #ifndef NO_RSA - wc_FreeRsaKey(&rsaKey); - #endif - wc_ecc_free(&dsaKey); - goto done_a; - } - - /* get output buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - /* record and message headers will be added below, when we're sure - of the sig length */ - - /* key exchange data */ - output[idx++] = named_curve; - output[idx++] = 0x00; /* leading zero */ - output[idx++] = SetCurveId(wc_ecc_size(ssl->eccTempKey)); - output[idx++] = (byte)expSz; - XMEMCPY(output + idx, exportBuf, expSz); - idx += expSz; - if (IsAtLeastTLSv1_2(ssl)) { - byte setHash = 0; - - output[idx++] = ssl->suites->hashAlgo; - output[idx++] = ssl->suites->sigAlgo; - - switch (ssl->suites->hashAlgo) { - case sha512_mac: - #ifdef WOLFSSL_SHA512 - doSha512 = 1; - setHash = 1; - #endif - break; - - case sha384_mac: - #ifdef WOLFSSL_SHA384 - doSha384 = 1; - setHash = 1; - #endif - break; - - case sha256_mac: - #ifndef NO_SHA256 - doSha256 = 1; - setHash = 1; - #endif - break; - - case sha_mac: - #ifndef NO_OLD_TLS - doSha = 1; - setHash = 1; - #endif - break; - - default: - WOLFSSL_MSG("Bad hash sig algo"); - break; - } - - if (setHash == 0) { - #ifndef NO_RSA - wc_FreeRsaKey(&rsaKey); - #endif - wc_ecc_free(&dsaKey); - ERROR_OUT(ALGO_ID_E, done_a); - } - } else { - /* only using sha and md5 for rsa */ - #ifndef NO_OLD_TLS - doSha = 1; - if (ssl->suites->sigAlgo == rsa_sa_algo) { - doMd5 = 1; - } - #else - #ifndef NO_RSA - wc_FreeRsaKey(&rsaKey); - #endif - wc_ecc_free(&dsaKey); - ERROR_OUT(ALGO_ID_E, done_a); - #endif - } - - /* Signtaure length will be written later, when we're sure what it - is */ - - #ifdef HAVE_FUZZER - if (ssl->fuzzerCb) { - ssl->fuzzerCb(ssl, output + preSigIdx, preSigSz, - FUZZ_SIGNATURE, ssl->fuzzerCtx); - } - #endif - - /* do signature */ - { - #ifndef NO_OLD_TLS - #ifdef WOLFSSL_SMALL_STACK - Md5* md5 = NULL; - Sha* sha = NULL; - #else - Md5 md5[1]; - Sha sha[1]; - #endif - #endif - #ifdef WOLFSSL_SMALL_STACK - byte* hash = NULL; - #else - byte hash[FINISHED_SZ]; - #endif - #ifndef NO_SHA256 - #ifdef WOLFSSL_SMALL_STACK - Sha256* sha256 = NULL; - byte* hash256 = NULL; - #else - Sha256 sha256[1]; - byte hash256[SHA256_DIGEST_SIZE]; - #endif - #endif - #ifdef WOLFSSL_SHA384 - #ifdef WOLFSSL_SMALL_STACK - Sha384* sha384 = NULL; - byte* hash384 = NULL; - #else - Sha384 sha384[1]; - byte hash384[SHA384_DIGEST_SIZE]; - #endif - #endif - #ifdef WOLFSSL_SHA512 - #ifdef WOLFSSL_SMALL_STACK - Sha512* sha512 = NULL; - byte* hash512 = NULL; - #else - Sha512 sha512[1]; - byte hash512[SHA512_DIGEST_SIZE]; - #endif - #endif - - #ifdef WOLFSSL_SMALL_STACK - hash = (byte*)XMALLOC(FINISHED_SZ, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (hash == NULL) { - ERROR_OUT(MEMORY_E, done_a); - } - #endif - - #ifndef NO_OLD_TLS - /* md5 */ - #ifdef WOLFSSL_SMALL_STACK - if (doMd5) { - md5 = (Md5*)XMALLOC(sizeof(Md5), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (md5 == NULL) { - ERROR_OUT(MEMORY_E, done_a2); - } - } - #endif - if (doMd5) { - wc_InitMd5(md5); - wc_Md5Update(md5, ssl->arrays->clientRandom, RAN_LEN); - wc_Md5Update(md5, ssl->arrays->serverRandom, RAN_LEN); - wc_Md5Update(md5, output + preSigIdx, preSigSz); - wc_Md5Final(md5, hash); - } - /* sha */ - #ifdef WOLFSSL_SMALL_STACK - if (doSha) { - sha = (Sha*)XMALLOC(sizeof(Sha), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (sha == NULL) { - ERROR_OUT(MEMORY_E, done_a2); - } - } - #endif - if (doSha) { - ret = wc_InitSha(sha); - if (ret != 0) { - goto done_a2; - } - wc_ShaUpdate(sha, ssl->arrays->clientRandom, RAN_LEN); - wc_ShaUpdate(sha, ssl->arrays->serverRandom, RAN_LEN); - wc_ShaUpdate(sha, output + preSigIdx, preSigSz); - wc_ShaFinal(sha, &hash[MD5_DIGEST_SIZE]); - } - #endif - - #ifndef NO_SHA256 - #ifdef WOLFSSL_SMALL_STACK - if (doSha256) { - sha256 = (Sha256*)XMALLOC(sizeof(Sha256), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - hash256 = (byte*)XMALLOC(SHA256_DIGEST_SIZE, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (sha256 == NULL || hash256 == NULL) { - ERROR_OUT(MEMORY_E, done_a2); - } - } - #endif - - if (doSha256) { - if (!(ret = wc_InitSha256(sha256)) - && !(ret = wc_Sha256Update(sha256, - ssl->arrays->clientRandom, RAN_LEN)) - && !(ret = wc_Sha256Update(sha256, - ssl->arrays->serverRandom, RAN_LEN)) - && !(ret = wc_Sha256Update(sha256, - output + preSigIdx, preSigSz))) { - ret = wc_Sha256Final(sha256, hash256); - } - if (ret != 0) { - goto done_a2; - } - } - #endif - - #ifdef WOLFSSL_SHA384 - #ifdef WOLFSSL_SMALL_STACK - if (doSha384) { - sha384 = (Sha384*)XMALLOC(sizeof(Sha384), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - hash384 = (byte*)XMALLOC(SHA384_DIGEST_SIZE, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (sha384 == NULL || hash384 == NULL) { - ERROR_OUT(MEMORY_E, done_a2); - } - } - #endif - - if (doSha384) { - if (!(ret = wc_InitSha384(sha384)) - && !(ret = wc_Sha384Update(sha384, - ssl->arrays->clientRandom, RAN_LEN)) - && !(ret = wc_Sha384Update(sha384, - ssl->arrays->serverRandom, RAN_LEN)) - && !(ret = wc_Sha384Update(sha384, - output + preSigIdx, preSigSz))) { - ret = wc_Sha384Final(sha384, hash384); - } - if (ret != 0) { - goto done_a2; - } - } - #endif - - #ifdef WOLFSSL_SHA512 - #ifdef WOLFSSL_SMALL_STACK - if (doSha512) { - sha512 = (Sha512*)XMALLOC(sizeof(Sha512), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - hash512 = (byte*)XMALLOC(SHA512_DIGEST_SIZE, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (sha512 == NULL || hash512 == NULL) { - ERROR_OUT(MEMORY_E, done_a2); - } - } - #endif - - if (doSha512) { - if (!(ret = wc_InitSha512(sha512)) - && !(ret = wc_Sha512Update(sha512, - ssl->arrays->clientRandom, RAN_LEN)) - && !(ret = wc_Sha512Update(sha512, - ssl->arrays->serverRandom, RAN_LEN)) - && !(ret = wc_Sha512Update(sha512, - output + preSigIdx, preSigSz))) { - ret = wc_Sha512Final(sha512, hash512); - } - if (ret != 0) { - goto done_a2; - } - } - #endif - - #ifndef NO_RSA - if (ssl->suites->sigAlgo == rsa_sa_algo) { - byte* signBuffer = hash; - word32 signSz = FINISHED_SZ; - byte doUserRsa = 0; - #ifdef WOLFSSL_SMALL_STACK - byte* encodedSig = NULL; - #else - byte encodedSig[MAX_ENCODED_SIG_SZ]; - #endif - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->RsaSignCb) - doUserRsa = 1; - #endif - - #ifdef WOLFSSL_SMALL_STACK - encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (encodedSig == NULL) { - ERROR_OUT(MEMORY_E, done_a2); - } - #endif - - if (IsAtLeastTLSv1_2(ssl)) { - byte* digest = &hash[MD5_DIGEST_SIZE]; - int typeH = SHAh; - int digestSz = SHA_DIGEST_SIZE; - - if (ssl->suites->hashAlgo == sha256_mac) { - #ifndef NO_SHA256 - digest = hash256; - typeH = SHA256h; - digestSz = SHA256_DIGEST_SIZE; - #endif - } - else if (ssl->suites->hashAlgo == sha384_mac) { - #ifdef WOLFSSL_SHA384 - digest = hash384; - typeH = SHA384h; - digestSz = SHA384_DIGEST_SIZE; - #endif - } - else if (ssl->suites->hashAlgo == sha512_mac) { - #ifdef WOLFSSL_SHA512 - digest = hash512; - typeH = SHA512h; - digestSz = SHA512_DIGEST_SIZE; - #endif - } - - if (digest == NULL) { - #ifndef NO_RSA - wc_FreeRsaKey(&rsaKey); - #endif - wc_ecc_free(&dsaKey); - ERROR_OUT(ALGO_ID_E, done_a2); - } - signSz = wc_EncodeSignature(encodedSig, digest, - digestSz, typeH); - signBuffer = encodedSig; - } - /* write sig size here */ - c16toa((word16)sigSz, output + idx); - idx += LENGTH_SZ; - - if (doUserRsa) { - #ifdef HAVE_PK_CALLBACKS - word32 ioLen = sigSz; - ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz, - output + idx, &ioLen, - ssl->buffers.key->buffer, - ssl->buffers.key->length, - ssl->RsaSignCtx); - #endif /*HAVE_PK_CALLBACKS */ - } - else { - ret = wc_RsaSSL_Sign(signBuffer, signSz, output + idx, - sigSz, &rsaKey, ssl->rng); - } - - if (ret > 0) { - /* check for signature faults */ - ret = VerifyRsaSign(output + idx, ret, - signBuffer, signSz, &rsaKey); - } - wc_FreeRsaKey(&rsaKey); - wc_ecc_free(&dsaKey); - - #ifdef WOLFSSL_SMALL_STACK - XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - - if (ret < 0) { - goto done_a2; - } - } else - #endif - - if (ssl->suites->sigAlgo == ecc_dsa_sa_algo) { - #ifndef NO_OLD_TLS - byte* digest = &hash[MD5_DIGEST_SIZE]; - word32 digestSz = SHA_DIGEST_SIZE; - #else - byte* digest = hash256; - word32 digestSz = SHA256_DIGEST_SIZE; - #endif - word32 sz = sigSz; - byte doUserEcc = 0; - - #if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC) - if (ssl->ctx->EccSignCb) { - doUserEcc = 1; - } - #endif - - if (IsAtLeastTLSv1_2(ssl)) { - if (ssl->suites->hashAlgo == sha_mac) { - #ifndef NO_SHA - digest = &hash[MD5_DIGEST_SIZE]; - digestSz = SHA_DIGEST_SIZE; - #endif - } - else if (ssl->suites->hashAlgo == sha256_mac) { - #ifndef NO_SHA256 - digest = hash256; - digestSz = SHA256_DIGEST_SIZE; - #endif - } - else if (ssl->suites->hashAlgo == sha384_mac) { - #ifdef WOLFSSL_SHA384 - digest = hash384; - digestSz = SHA384_DIGEST_SIZE; - #endif - } - else if (ssl->suites->hashAlgo == sha512_mac) { - #ifdef WOLFSSL_SHA512 - digest = hash512; - digestSz = SHA512_DIGEST_SIZE; - #endif - } - } - - if (doUserEcc) { - #if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC) - ret = ssl->ctx->EccSignCb(ssl, digest, digestSz, - output + LENGTH_SZ + idx, - &sz, - ssl->buffers.key->buffer, - ssl->buffers.key->length, - ssl->EccSignCtx); - #endif - } - else { - ret = wc_ecc_sign_hash(digest, digestSz, - output + LENGTH_SZ + idx, &sz, ssl->rng, &dsaKey); - } - #ifndef NO_RSA - wc_FreeRsaKey(&rsaKey); - #endif - wc_ecc_free(&dsaKey); - - if (ret < 0) { - goto done_a2; - } - - /* Now that we know the real sig size, write it. */ - c16toa((word16)sz, output + idx); - - /* And adjust length and sendSz from estimates */ - length += sz - sigSz; - sendSz += sz - sigSz; - } - - done_a2: - #ifdef WOLFSSL_SMALL_STACK - #ifndef NO_OLD_TLS - XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - XFREE(hash, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #ifndef NO_SHA256 - XFREE(sha256, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(hash256, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - #ifdef WOLFSSL_SHA384 - XFREE(sha384, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(hash384, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - #ifdef WOLFSSL_SHA512 - XFREE(sha512, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(hash512, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - #endif - - if (ret < 0) - goto done_a; - } - -#ifdef HAVE_QSH - if (ssl->peerQSHKeyPresent) { - if (qshSz > 0) { - idx = sendSz - qshSz; - QSH_KeyExchangeWrite(ssl, 1); - - /* extension type */ - c16toa(TLSX_QUANTUM_SAFE_HYBRID, output + idx); - idx += OPAQUE16_LEN; - - /* write to output and check amount written */ - if (TLSX_QSHPK_Write(ssl->QSH_secret->list, output + idx) - > qshSz - OPAQUE16_LEN) { - return MEMORY_E; - } - } - } #endif - - AddHeaders(output, length, server_key_exchange, ssl); - - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) { - goto done_a; - } - } - #endif - - if ((ret = HashOutput(ssl, output, sendSz, 0)) != 0) { - goto done_a; - } - - #ifdef WOLFSSL_CALLBACKS - if (ssl->hsInfoOn) { - AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); - } - if (ssl->toInfoOn) { - AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, - output, sendSz, ssl->heap); - } - #endif - - ssl->buffers.outputBuffer.length += sendSz; - if (ssl->options.groupMessages) { - ret = 0; - } - else { - ret = SendBuffered(ssl); - } - ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; - - done_a: - #ifdef WOLFSSL_SMALL_STACK - XFREE(exportBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - - return ret; - } - #endif /* HAVE_ECC */ - - #if !defined(NO_DH) && !defined(NO_RSA) - case diffie_hellman_kea: - { - byte *output; - word32 length = 0, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; - int sendSz; - word32 sigSz = 0, i = 0; - word32 preSigSz = 0, preSigIdx = 0; - RsaKey rsaKey; - DhKey dhKey; - - if (ssl->buffers.serverDH_P.buffer == NULL || - ssl->buffers.serverDH_G.buffer == NULL) { - return NO_DH_PARAMS; - } - - if (ssl->buffers.serverDH_Pub.buffer == NULL) { - ssl->buffers.serverDH_Pub.buffer = (byte*)XMALLOC( - ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap, - DYNAMIC_TYPE_DH); - if (ssl->buffers.serverDH_Pub.buffer == NULL) { - return MEMORY_E; - } - } - - if (ssl->buffers.serverDH_Priv.buffer == NULL) { - ssl->buffers.serverDH_Priv.buffer = (byte*)XMALLOC( - ssl->buffers.serverDH_P.length + 2, ssl->ctx->heap, - DYNAMIC_TYPE_DH); - if (ssl->buffers.serverDH_Priv.buffer == NULL) { - return MEMORY_E; - } - } - - wc_InitDhKey(&dhKey); - ret = wc_DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer, - ssl->buffers.serverDH_P.length, - ssl->buffers.serverDH_G.buffer, - ssl->buffers.serverDH_G.length); - if (ret == 0) { - ret = wc_DhGenerateKeyPair(&dhKey, ssl->rng, - ssl->buffers.serverDH_Priv.buffer, - &ssl->buffers.serverDH_Priv.length, - ssl->buffers.serverDH_Pub.buffer, - &ssl->buffers.serverDH_Pub.length); - } - wc_FreeDhKey(&dhKey); - - if (ret != 0) { - return ret; - } - - length = LENGTH_SZ * 3; /* p, g, pub */ - length += ssl->buffers.serverDH_P.length + - ssl->buffers.serverDH_G.length + - ssl->buffers.serverDH_Pub.length; - - preSigIdx = idx; - preSigSz = length; - - if (!ssl->options.usingAnon_cipher) { - ret = wc_InitRsaKey(&rsaKey, ssl->heap); - if (ret != 0) { - return ret; - } - - /* sig length */ - length += LENGTH_SZ; - - if (!ssl->buffers.key || !ssl->buffers.key->buffer) { - return NO_PRIVATE_KEY; - } - - ret = wc_RsaPrivateKeyDecode(ssl->buffers.key->buffer, &i, - &rsaKey, ssl->buffers.key->length); - if (ret == 0) { - sigSz = wc_RsaEncryptSize(&rsaKey); - length += sigSz; - } - else { - wc_FreeRsaKey(&rsaKey); - return ret; - } - - if (IsAtLeastTLSv1_2(ssl)) { - length += HASH_SIG_SIZE; - } - } - - sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; - - #ifdef HAVE_QSH - length += qshSz; - sendSz += qshSz; - #endif - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - idx += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA; - preSigIdx = idx; - } - #endif - - /* check for available size */ - if ((ret = CheckAvailableSize(ssl, sendSz)) != 0) { - if (!ssl->options.usingAnon_cipher) { - wc_FreeRsaKey(&rsaKey); - } - return ret; - } - - /* get output buffer */ - output = ssl->buffers.outputBuffer.buffer + - ssl->buffers.outputBuffer.length; - - AddHeaders(output, length, server_key_exchange, ssl); - - /* add p, g, pub */ - c16toa((word16)ssl->buffers.serverDH_P.length, output + idx); - idx += LENGTH_SZ; - XMEMCPY(output + idx, ssl->buffers.serverDH_P.buffer, - ssl->buffers.serverDH_P.length); - idx += ssl->buffers.serverDH_P.length; - - /* g */ - c16toa((word16)ssl->buffers.serverDH_G.length, output + idx); - idx += LENGTH_SZ; - XMEMCPY(output + idx, ssl->buffers.serverDH_G.buffer, - ssl->buffers.serverDH_G.length); - idx += ssl->buffers.serverDH_G.length; - - /* pub */ - c16toa((word16)ssl->buffers.serverDH_Pub.length, output + idx); - idx += LENGTH_SZ; - XMEMCPY(output + idx, ssl->buffers.serverDH_Pub.buffer, - ssl->buffers.serverDH_Pub.length); - idx += ssl->buffers.serverDH_Pub.length; - - #ifdef HAVE_FUZZER - if (ssl->fuzzerCb) { - ssl->fuzzerCb(ssl, output + preSigIdx, preSigSz, - FUZZ_SIGNATURE, ssl->fuzzerCtx); - } - #endif - - /* Add signature */ - if (!ssl->options.usingAnon_cipher) { - #ifndef NO_OLD_TLS - #ifdef WOLFSSL_SMALL_STACK - Md5* md5 = NULL; - Sha* sha = NULL; - #else - Md5 md5[1]; - Sha sha[1]; - #endif - #endif - #ifdef WOLFSSL_SMALL_STACK - byte* hash = NULL; - #else - byte hash[FINISHED_SZ]; - #endif - #ifndef NO_SHA256 - #ifdef WOLFSSL_SMALL_STACK - Sha256* sha256 = NULL; - byte* hash256 = NULL; - #else - Sha256 sha256[1]; - byte hash256[SHA256_DIGEST_SIZE]; - #endif - #endif - #ifdef WOLFSSL_SHA384 - #ifdef WOLFSSL_SMALL_STACK - Sha384* sha384 = NULL; - byte* hash384 = NULL; - #else - Sha384 sha384[1]; - byte hash384[SHA384_DIGEST_SIZE]; - #endif - #endif - #ifdef WOLFSSL_SHA512 - #ifdef WOLFSSL_SMALL_STACK - Sha512* sha512 = NULL; - byte* hash512 = NULL; - #else - Sha512 sha512[1]; - byte hash512[SHA512_DIGEST_SIZE]; - #endif - #endif - - #ifndef NO_OLD_TLS - byte doMd5 = 0; - byte doSha = 0; - #endif - #ifndef NO_SHA256 - byte doSha256 = 0; - #endif - #ifdef WOLFSSL_SHA384 - byte doSha384 = 0; - #endif - #ifdef WOLFSSL_SHA512 - byte doSha512 = 0; - #endif - - /* Add hash/signature algo ID */ - if (IsAtLeastTLSv1_2(ssl)) { - byte setHash = 0; - - output[idx++] = ssl->suites->hashAlgo; - output[idx++] = ssl->suites->sigAlgo; - - switch (ssl->suites->hashAlgo) { - case sha512_mac: - #ifdef WOLFSSL_SHA512 - doSha512 = 1; - setHash = 1; - #endif - break; - - case sha384_mac: - #ifdef WOLFSSL_SHA384 - doSha384 = 1; - setHash = 1; - #endif - break; - - case sha256_mac: - #ifndef NO_SHA256 - doSha256 = 1; - setHash = 1; - #endif - break; - - case sha_mac: - #ifndef NO_OLD_TLS - doSha = 1; - setHash = 1; - #endif - break; - - default: - WOLFSSL_MSG("Bad hash sig algo"); - break; - } - - if (setHash == 0) { - wc_FreeRsaKey(&rsaKey); - return ALGO_ID_E; - } - } else { - /* only using sha and md5 for rsa */ - #ifndef NO_OLD_TLS - doSha = 1; - if (ssl->suites->sigAlgo == rsa_sa_algo) { - doMd5 = 1; - } - #else - wc_FreeRsaKey(&rsaKey); - return ALGO_ID_E; - #endif - } - - /* signature size */ - c16toa((word16)sigSz, output + idx); - idx += LENGTH_SZ; - - /* do signature */ - #ifdef WOLFSSL_SMALL_STACK - hash = (byte*)XMALLOC(FINISHED_SZ, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (hash == NULL) { - return MEMORY_E; /* No heap commitment before this point, - from now on, the resources are freed - at done_b. */ - } - #endif - - #ifndef NO_OLD_TLS - /* md5 */ - #ifdef WOLFSSL_SMALL_STACK - if (doMd5) { - md5 = (Md5*)XMALLOC(sizeof(Md5), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (md5 == NULL) { - ERROR_OUT(MEMORY_E, done_b); - } - } - #endif - if (doMd5) { - wc_InitMd5(md5); - wc_Md5Update(md5, ssl->arrays->clientRandom, RAN_LEN); - wc_Md5Update(md5, ssl->arrays->serverRandom, RAN_LEN); - wc_Md5Update(md5, output + preSigIdx, preSigSz); - wc_Md5Final(md5, hash); - } - - /* sha */ - #ifdef WOLFSSL_SMALL_STACK - if (doSha) { - sha = (Sha*)XMALLOC(sizeof(Sha), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (sha == NULL) { - ERROR_OUT(MEMORY_E, done_b); - } - } - #endif - - if (doSha) { - if ((ret = wc_InitSha(sha)) != 0) { - goto done_b; - } - wc_ShaUpdate(sha, ssl->arrays->clientRandom, RAN_LEN); - wc_ShaUpdate(sha, ssl->arrays->serverRandom, RAN_LEN); - wc_ShaUpdate(sha, output + preSigIdx, preSigSz); - wc_ShaFinal(sha, &hash[MD5_DIGEST_SIZE]); - } - #endif - - #ifndef NO_SHA256 - #ifdef WOLFSSL_SMALL_STACK - if (doSha256) { - sha256 = (Sha256*)XMALLOC(sizeof(Sha256), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - hash256 = (byte*)XMALLOC(SHA256_DIGEST_SIZE, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (sha256 == NULL || hash256 == NULL) { - ERROR_OUT(MEMORY_E, done_b); - } - } - #endif - - if (doSha256) { - if (!(ret = wc_InitSha256(sha256)) - && !(ret = wc_Sha256Update(sha256, - ssl->arrays->clientRandom, RAN_LEN)) - && !(ret = wc_Sha256Update(sha256, - ssl->arrays->serverRandom, RAN_LEN)) - && !(ret = wc_Sha256Update(sha256, - output + preSigIdx, preSigSz))) { - ret = wc_Sha256Final(sha256, hash256); - } - if (ret != 0) { - goto done_b; - } - } - #endif - - #ifdef WOLFSSL_SHA384 - #ifdef WOLFSSL_SMALL_STACK - if (doSha384) { - sha384 = (Sha384*)XMALLOC(sizeof(Sha384), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - hash384 = (byte*)XMALLOC(SHA384_DIGEST_SIZE, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (sha384 == NULL || hash384 == NULL) { - ERROR_OUT(MEMORY_E, done_b); - } - } - #endif - - if (doSha384) { - if (!(ret = wc_InitSha384(sha384)) - && !(ret = wc_Sha384Update(sha384, - ssl->arrays->clientRandom, RAN_LEN)) - && !(ret = wc_Sha384Update(sha384, - ssl->arrays->serverRandom, RAN_LEN)) - && !(ret = wc_Sha384Update(sha384, - output + preSigIdx, preSigSz))) { - ret = wc_Sha384Final(sha384, hash384); - } - if (ret != 0) { - goto done_b; - } - } - #endif - - #ifdef WOLFSSL_SHA512 - #ifdef WOLFSSL_SMALL_STACK - if (doSha512) { - sha512 = (Sha512*)XMALLOC(sizeof(Sha512), NULL, - DYNAMIC_TYPE_TMP_BUFFER); - hash512 = (byte*)XMALLOC(SHA512_DIGEST_SIZE, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (sha512 == NULL || hash512 == NULL) { - ERROR_OUT(MEMORY_E, done_b); - } - } - #endif - - if (doSha512) { - if (!(ret = wc_InitSha512(sha512)) - && !(ret = wc_Sha512Update(sha512, - ssl->arrays->clientRandom, RAN_LEN)) - && !(ret = wc_Sha512Update(sha512, - ssl->arrays->serverRandom, RAN_LEN)) - && !(ret = wc_Sha512Update(sha512, - output + preSigIdx, preSigSz))) { - ret = wc_Sha512Final(sha512, hash512); - } - if (ret != 0) { - goto done_b; - } - } - #endif - - #ifndef NO_RSA - if (ssl->suites->sigAlgo == rsa_sa_algo) { - byte* signBuffer = hash; - word32 signSz = FINISHED_SZ; - #ifdef WOLFSSL_SMALL_STACK - byte* encodedSig = NULL; - #else - byte encodedSig[MAX_ENCODED_SIG_SZ]; - #endif - byte doUserRsa = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->RsaSignCb) { - doUserRsa = 1; - } - #endif - - if (IsAtLeastTLSv1_2(ssl)) { - byte* digest = &hash[MD5_DIGEST_SIZE]; - int typeH = SHAh; - int digestSz = SHA_DIGEST_SIZE; - - #ifdef WOLFSSL_SMALL_STACK - encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, NULL, - DYNAMIC_TYPE_TMP_BUFFER); - if (encodedSig == NULL) - ERROR_OUT(MEMORY_E, done_b); - #endif - - if (ssl->suites->hashAlgo == sha256_mac) { - #ifndef NO_SHA256 - digest = hash256; - typeH = SHA256h; - digestSz = SHA256_DIGEST_SIZE; - #endif - } - else if (ssl->suites->hashAlgo == sha384_mac) { - #ifdef WOLFSSL_SHA384 - digest = hash384; - typeH = SHA384h; - digestSz = SHA384_DIGEST_SIZE; - #endif - } - else if (ssl->suites->hashAlgo == sha512_mac) { - #ifdef WOLFSSL_SHA512 - digest = hash512; - typeH = SHA512h; - digestSz = SHA512_DIGEST_SIZE; - #endif - } - - if (digest == NULL) { - ret = ALGO_ID_E; - } else { - signSz = wc_EncodeSignature(encodedSig, digest, - digestSz, typeH); - signBuffer = encodedSig; - } - } - if (doUserRsa && ret == 0) { - #ifdef HAVE_PK_CALLBACKS - word32 ioLen = sigSz; - ret = ssl->ctx->RsaSignCb(ssl, signBuffer, signSz, - output + idx, &ioLen, - ssl->buffers.key->buffer, - ssl->buffers.key->length, - ssl->RsaSignCtx); - #endif - } else if (ret == 0) { - ret = wc_RsaSSL_Sign(signBuffer, signSz, output + idx, - sigSz, &rsaKey, ssl->rng); - } - - if (ret > 0) { - /* check for signature faults */ - ret = VerifyRsaSign(output + idx, ret, - signBuffer, signSz, &rsaKey); - } - - wc_FreeRsaKey(&rsaKey); - - #ifdef WOLFSSL_SMALL_STACK - XFREE(encodedSig, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - } - #endif - - done_b: - #ifdef WOLFSSL_SMALL_STACK - #ifndef NO_OLD_TLS - XFREE(md5, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - XFREE(hash, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #ifndef NO_SHA256 - XFREE(sha256, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(hash256, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - #ifdef WOLFSSL_SHA384 - XFREE(sha384, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(hash384, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - #ifdef WOLFSSL_SHA512 - XFREE(sha512, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(hash512, NULL, DYNAMIC_TYPE_TMP_BUFFER); - #endif - #endif - - if (ret < 0) { - return ret; - } - } - - #ifdef HAVE_QSH - if (ssl->peerQSHKeyPresent) { - if (qshSz > 0) { - idx = sendSz - qshSz; - QSH_KeyExchangeWrite(ssl, 1); - - /* extension type */ - c16toa(TLSX_QUANTUM_SAFE_HYBRID, output + idx); - idx += OPAQUE16_LEN; - - /* write to output and check amount written */ - if (TLSX_QSHPK_Write(ssl->QSH_secret->list, output + idx) - > qshSz - OPAQUE16_LEN) { - return MEMORY_E; - } - } - } - #endif - - #ifdef WOLFSSL_DTLS - if (ssl->options.dtls) { - if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0) { - return ret; - } - } - #endif - - if ((ret = HashOutput(ssl, output, sendSz, 0)) != 0) { - return ret; - } - - #ifdef WOLFSSL_CALLBACKS - if (ssl->hsInfoOn) { - AddPacketName("ServerKeyExchange", &ssl->handShakeInfo); - } - if (ssl->toInfoOn) { - AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo, - output, sendSz, ssl->heap); - } - #endif - - ssl->buffers.outputBuffer.length += sendSz; - if (ssl->options.groupMessages) { - ret = 0; - } - else { - ret = SendBuffered(ssl); - } - ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE; - break; - } - #endif /* NO_DH */ - default: - break; - } /* switch(ssl->specs.kea) */ + /* Final cleanup */ + FreeKeyExchange(ssl); return ret; - #undef ERROR_OUT } @@ -16514,28 +16284,22 @@ int DoSessionTicket(WOLFSSL* ssl, if (ssl->peerRsaKey != NULL && ssl->peerRsaKeyPresent != 0) { byte* out = NULL; int outLen = 0; - byte doUserRsa = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->RsaVerifyCb) - doUserRsa = 1; - #endif /*HAVE_PK_CALLBACKS */ WOLFSSL_MSG("Doing RSA peer cert verify"); - if (doUserRsa) { - #ifdef HAVE_PK_CALLBACKS - outLen = ssl->ctx->RsaVerifyCb(ssl, input + *inOutIdx, sz, - &out, - ssl->buffers.peerRsaKey.buffer, - ssl->buffers.peerRsaKey.length, - ssl->RsaVerifyCtx); - #endif /*HAVE_PK_CALLBACKS */ - } - else { - outLen = wc_RsaSSL_VerifyInline(input + *inOutIdx, sz, &out, - ssl->peerRsaKey); - } + outLen = RsaVerify(ssl, + input + *inOutIdx, + sz, + &out, + ssl->peerRsaKey, +#ifdef HAVE_PK_CALLBACKS + ssl->buffers.peerRsaKey.buffer, + ssl->buffers.peerRsaKey.length, + ssl->RsaVerifyCtx +#else + NULL, 0, NULL +#endif + ); if (IsAtLeastTLSv1_2(ssl)) { #ifdef WOLFSSL_SMALL_STACK @@ -16602,16 +16366,8 @@ int DoSessionTicket(WOLFSSL* ssl, #endif #ifdef HAVE_ECC if (ssl->peerEccDsaKeyPresent) { - int verify = 0; - int err = -1; byte* digest = ssl->hsHashes->certHashes.sha; word32 digestSz = SHA_DIGEST_SIZE; - byte doUserEcc = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->EccVerifyCb) - doUserEcc = 1; - #endif WOLFSSL_MSG("Doing ECC peer cert verify"); @@ -16640,22 +16396,18 @@ int DoSessionTicket(WOLFSSL* ssl, } } - if (doUserEcc) { + ret = EccVerify(ssl, + input + *inOutIdx, sz, + digest, digestSz, + ssl->peerEccDsaKey, #ifdef HAVE_PK_CALLBACKS - ret = ssl->ctx->EccVerifyCb(ssl, input + *inOutIdx, sz, digest, - digestSz, - ssl->buffers.peerEccDsaKey.buffer, - ssl->buffers.peerEccDsaKey.length, - &verify, ssl->EccVerifyCtx); + ssl->buffers.peerEccDsaKey.buffer, + ssl->buffers.peerEccDsaKey.length, + ssl->EccVerifyCtx + #else + NULL, 0, NULL #endif - } - else { - err = wc_ecc_verify_hash(input + *inOutIdx, sz, digest, - digestSz, &verify, ssl->peerEccDsaKey); - } - - if (err == 0 && verify == 1) - ret = 0; /* verified */ + ); } #endif *inOutIdx += sz; @@ -16963,750 +16715,778 @@ int DoSessionTicket(WOLFSSL* ssl, static int DoClientKeyExchange(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 size) { - #ifdef HAVE_QSH - word16 name; - int qshSz; - #endif - int ret = 0; + int ret; word32 length = 0; - byte* out = NULL; - word32 begin = *inOutIdx; + word32 idx = *inOutIdx, begin = *inOutIdx; + byte* output_lcl = NULL; + byte** output = &output_lcl; - (void)length; /* shut up compiler warnings */ - (void)out; + /* suppress possible compiler warnings */ (void)input; (void)size; - (void)begin; + (void)length; + (void)idx; + (void)output; - if (ssl->options.side != WOLFSSL_SERVER_END) { - WOLFSSL_MSG("Client received client keyexchange, attack?"); - WOLFSSL_ERROR(ssl->error = SIDE_ERROR); - return SSL_FATAL_ERROR; - } + #ifdef WOLFSSL_ASYNC_CRYPT + /* Use async output pointer */ + output = &ssl->async.output; - if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { - WOLFSSL_MSG("Client sending keyexchange at wrong time"); - SendAlert(ssl, alert_fatal, unexpected_message); - return OUT_OF_ORDER_E; - } - - #ifndef NO_CERTS - if (ssl->options.verifyPeer && ssl->options.failNoCert) { - if (!ssl->options.havePeerCert) { - WOLFSSL_MSG("client didn't present peer cert"); - return NO_PEER_CERT; - } + ret = wolfSSL_async_pop(ssl, WOLF_EVENT_TYPE_ASYNC_ACCEPT); + if (ret != ASYNC_NOT_PENDING) { + /* Check for error */ + if (ret < 0) { + goto exit_dcke; } + else { + /* Restore variables needed for async */ + idx = ssl->async.idx; + length = ssl->async.length; - if (ssl->options.verifyPeer && ssl->options.failNoCertxPSK) { - if (!ssl->options.havePeerCert && + /* Advance state */ + ssl->options.keyShareState++; + } + } + else + #endif + { + /* Reset state */ + ret = 0; + ssl->options.keyShareState = KEYSHARE_BEGIN; + } + + /* Do Client Key Exchange State Machine */ + switch(ssl->options.keyShareState) + { + case KEYSHARE_BEGIN: + { + /* Sanity checks */ + if (ssl->options.side != WOLFSSL_SERVER_END) { + WOLFSSL_MSG("Client received client keyexchange, attack?"); + WOLFSSL_ERROR(ssl->error = SIDE_ERROR); + ERROR_OUT(SSL_FATAL_ERROR, exit_dcke); + } + + if (ssl->options.clientState < CLIENT_HELLO_COMPLETE) { + WOLFSSL_MSG("Client sending keyexchange at wrong time"); + SendAlert(ssl, alert_fatal, unexpected_message); + ERROR_OUT(OUT_OF_ORDER_E, exit_dcke); + } + + #ifndef NO_CERTS + if (ssl->options.verifyPeer && ssl->options.failNoCert) { + if (!ssl->options.havePeerCert) { + WOLFSSL_MSG("client didn't present peer cert"); + ERROR_OUT(NO_PEER_CERT, exit_dcke); + } + } + + if (ssl->options.verifyPeer && ssl->options.failNoCertxPSK) { + if (!ssl->options.havePeerCert && !ssl->options.usingPSK_cipher){ - WOLFSSL_MSG("client didn't present peer cert"); - return NO_PEER_CERT; - } - } - #endif - - #ifdef WOLFSSL_CALLBACKS - if (ssl->hsInfoOn) { - AddPacketName("ClientKeyExchange", &ssl->handShakeInfo); - } - if (ssl->toInfoOn) { - AddLateName("ClientKeyExchange", &ssl->timeoutInfo); - } - #endif - - switch (ssl->specs.kea) { - #ifndef NO_RSA - case rsa_kea: - { - word32 idx = 0; - RsaKey key; - byte doUserRsa = 0; - - #ifdef HAVE_PK_CALLBACKS - if (ssl->ctx->RsaDecCb) { - doUserRsa = 1; + WOLFSSL_MSG("client didn't present peer cert"); + return NO_PEER_CERT; } - #endif + } + #endif - ret = wc_InitRsaKey(&key, ssl->heap); + #ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) { + AddPacketName("ClientKeyExchange", &ssl->handShakeInfo); + } + if (ssl->toInfoOn) { + AddLateName("ClientKeyExchange", &ssl->timeoutInfo); + } + #endif + + switch (ssl->specs.kea) { + #ifndef NO_RSA + case rsa_kea: + { + if (!ssl->buffers.key->buffer) { + ERROR_OUT(NO_PRIVATE_KEY, exit_dcke); + } + break; + } /* rsa_kea */ + #endif /* !NO_RSA */ + #ifndef NO_PSK + case psk_kea: + { + /* sanity check that PSK server callback has been set */ + if (ssl->options.server_psk_cb == NULL) { + WOLFSSL_MSG("No server PSK callback set"); + ERROR_OUT(PSK_KEY_ERROR, exit_dcke); + } + break; + } + #endif /* !NO_PSK */ + #ifdef HAVE_NTRU + case ntru_kea: + { + if (!ssl->buffers.key->buffer) { + ERROR_OUT(NO_PRIVATE_KEY, exit_dcke); + } + break; + } + #endif /* HAVE_NTRU */ + #ifdef HAVE_ECC + case ecc_diffie_hellman_kea: + { + break; + } + #endif /* HAVE_ECC */ + #ifndef NO_DH + case diffie_hellman_kea: + { + break; + } + #endif /* !NO_DH */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + /* sanity check that PSK server callback has been set */ + if (ssl->options.server_psk_cb == NULL) { + WOLFSSL_MSG("No server PSK callback set"); + ERROR_OUT(PSK_KEY_ERROR, exit_dcke); + } + break; + } + #endif /* !NO_DH && !NO_PSK */ + #if defined(HAVE_ECC) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + /* sanity check that PSK server callback has been set */ + if (ssl->options.server_psk_cb == NULL) { + WOLFSSL_MSG("No server PSK callback set"); + ERROR_OUT(PSK_KEY_ERROR, exit_dcke); + } + break; + } + #endif /* HAVE_ECC && !NO_PSK */ + default: + WOLFSSL_MSG("Bad kea type"); + ret = BAD_KEA_TYPE_E; + } /* switch (ssl->specs.kea) */ + + /* Check for error */ if (ret != 0) { - return ret; + goto exit_dcke; } - if (!ssl->buffers.key || !ssl->buffers.key->buffer) { - return NO_PRIVATE_KEY; - } + /* Advance state and proceed */ + ssl->options.keyShareState = KEYSHARE_BUILD; + } /* KEYSHARE_BEGIN */ - ret = wc_RsaPrivateKeyDecode(ssl->buffers.key->buffer, &idx, - &key, ssl->buffers.key->length); + case KEYSHARE_BUILD: + { + switch (ssl->specs.kea) { + #ifndef NO_RSA + case rsa_kea: + { + word32 i = 0; + ssl->sigKey = XMALLOC(sizeof(RsaKey), NULL, DYNAMIC_TYPE_RSA); + if (ssl->sigKey == NULL) { + ERROR_OUT(MEMORY_E, exit_dcke); + } + ssl->sigType = DYNAMIC_TYPE_RSA; - if (ret == 0) { - length = wc_RsaEncryptSize(&key); - ssl->arrays->preMasterSz = SECRET_LEN; - - if (ssl->options.tls) { - word16 check; - - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) { - return BUFFER_ERROR; + ret = wc_InitRsaKey((RsaKey*)ssl->sigKey, ssl->heap); + if (ret != 0) { + goto exit_dcke; } - ato16(input + *inOutIdx, &check); - *inOutIdx += OPAQUE16_LEN; - - if ((word32) check != length) { - WOLFSSL_MSG("RSA explicit size doesn't match"); - wc_FreeRsaKey(&key); - return RSA_PRIVATE_ERROR; + ret = wc_RsaPrivateKeyDecode(ssl->buffers.key->buffer, &i, + (RsaKey*)ssl->sigKey, ssl->buffers.key->length); + if (ret != 0) { + goto exit_dcke; } - } + length = wc_RsaEncryptSize((RsaKey*)ssl->sigKey); + ssl->arrays->preMasterSz = SECRET_LEN; - if ((*inOutIdx - begin) + length > size) { - WOLFSSL_MSG("RSA message too big"); - wc_FreeRsaKey(&key); - return BUFFER_ERROR; - } + if (ssl->options.tls) { + word16 check; - if (doUserRsa) { - #ifdef HAVE_PK_CALLBACKS - ret = ssl->ctx->RsaDecCb(ssl, - input + *inOutIdx, length, &out, - ssl->buffers.key->buffer, - ssl->buffers.key->length, - ssl->RsaDecCtx); - #endif - } - else { - ret = wc_RsaPrivateDecryptInline(input + *inOutIdx, length, - &out, &key); - } - - *inOutIdx += length; - - if (ret == SECRET_LEN) { - XMEMCPY(ssl->arrays->preMasterSecret, out, SECRET_LEN); - if (ssl->arrays->preMasterSecret[0] != - ssl->chVersion.major - || ssl->arrays->preMasterSecret[1] != - ssl->chVersion.minor) { - ret = PMS_VERSION_ERROR; - } - else - { - #ifdef HAVE_QSH - if (ssl->options.haveQSH) { - /* extension name */ - ato16(input + *inOutIdx, &name); - *inOutIdx += OPAQUE16_LEN; - - if (name == TLSX_QUANTUM_SAFE_HYBRID) { - /* if qshSz is larger than 0 it is the - length of buffer used */ - if ((qshSz = TLSX_QSHCipher_Parse(ssl, input - + *inOutIdx, size - *inOutIdx - + begin, 1)) < 0) { - return qshSz; - } - *inOutIdx += qshSz; - } - else { - /* unknown extension sent client ignored - handshake */ - return BUFFER_ERROR; - } + if ((idx - begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); } - #endif - ret = MakeMasterSecret(ssl); - } - } - else { - ret = RSA_PRIVATE_ERROR; - } - } - wc_FreeRsaKey(&key); - } - break; - #endif - #ifndef NO_PSK - case psk_kea: - { - byte* pms = ssl->arrays->preMasterSecret; - word16 ci_sz; + ato16(input + idx, &check); + idx += OPAQUE16_LEN; - /* sanity check that PSK server callback has been set */ - if (ssl->options.server_psk_cb == NULL) { - WOLFSSL_MSG("No server PSK callback set"); - return PSK_KEY_ERROR; - } - - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) { - return BUFFER_ERROR; - } - - ato16(input + *inOutIdx, &ci_sz); - *inOutIdx += OPAQUE16_LEN; - - if (ci_sz > MAX_PSK_ID_LEN) { - return CLIENT_ID_ERROR; - } - - if ((*inOutIdx - begin) + ci_sz > size) { - return BUFFER_ERROR; - } - - XMEMCPY(ssl->arrays->client_identity, input + *inOutIdx, ci_sz); - *inOutIdx += ci_sz; - - ssl->arrays->client_identity[min(ci_sz, MAX_PSK_ID_LEN-1)] = 0; - ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, - ssl->arrays->client_identity, ssl->arrays->psk_key, - MAX_PSK_KEY_LEN); - - if (ssl->arrays->psk_keySz == 0 || - ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { - return PSK_KEY_ERROR; - } - - /* make psk pre master secret */ - /* length of key + length 0s + length of key + key */ - c16toa((word16) ssl->arrays->psk_keySz, pms); - pms += OPAQUE16_LEN; - - XMEMSET(pms, 0, ssl->arrays->psk_keySz); - pms += ssl->arrays->psk_keySz; - - c16toa((word16) ssl->arrays->psk_keySz, pms); - pms += OPAQUE16_LEN; - - XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); - ssl->arrays->preMasterSz = ssl->arrays->psk_keySz * 2 + 4; - - #ifdef HAVE_QSH - if (ssl->options.haveQSH) { - /* extension name */ - ato16(input + *inOutIdx, &name); - *inOutIdx += OPAQUE16_LEN; - - if (name == TLSX_QUANTUM_SAFE_HYBRID) { - /* if qshSz is larger than 0 it is the length of - buffer used */ - if ((qshSz = TLSX_QSHCipher_Parse(ssl, input + *inOutIdx, - size - *inOutIdx + begin, 1)) < 0) { - return qshSz; + if ((word32)check != length) { + WOLFSSL_MSG("RSA explicit size doesn't match"); + ERROR_OUT(RSA_PRIVATE_ERROR, exit_dcke); + } } - *inOutIdx += qshSz; - } - else { - /* unknown extension sent client ignored - handshake */ - return BUFFER_ERROR; - } - } - #endif - ret = MakeMasterSecret(ssl); - /* No further need for PSK */ - ForceZero(ssl->arrays->psk_key, ssl->arrays->psk_keySz); - ssl->arrays->psk_keySz = 0; - } - break; - #endif /* NO_PSK */ - #ifdef HAVE_NTRU - case ntru_kea: - { - word16 cipherLen; - word16 plainLen = sizeof(ssl->arrays->preMasterSecret); - - if (!ssl->buffers.key || !ssl->buffers.key->buffer) { - return NO_PRIVATE_KEY; - } - - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) { - return BUFFER_ERROR; - } - - ato16(input + *inOutIdx, &cipherLen); - *inOutIdx += OPAQUE16_LEN; - - if (cipherLen > MAX_NTRU_ENCRYPT_SZ) { - return NTRU_KEY_ERROR; - } - - if ((*inOutIdx - begin) + cipherLen > size) { - return BUFFER_ERROR; - } - - if (NTRU_OK != ntru_crypto_ntru_decrypt( - (word16) ssl->buffers.key->length, - ssl->buffers.key->buffer, cipherLen, - input + *inOutIdx, &plainLen, - ssl->arrays->preMasterSecret)) { - return NTRU_DECRYPT_ERROR; - } - - if (plainLen != SECRET_LEN) { - return NTRU_DECRYPT_ERROR; - } - - *inOutIdx += cipherLen; - - #ifdef HAVE_QSH - if (ssl->options.haveQSH) { - /* extension name */ - ato16(input + *inOutIdx, &name); - *inOutIdx += OPAQUE16_LEN; - - if (name == TLSX_QUANTUM_SAFE_HYBRID) { - /* if qshSz is larger than 0 it is the length of - buffer used */ - if ((qshSz = TLSX_QSHCipher_Parse(ssl, input + *inOutIdx, - size - *inOutIdx + begin, 1)) < 0) { - return qshSz; + if ((idx - begin) + length > size) { + WOLFSSL_MSG("RSA message too big"); + ERROR_OUT(BUFFER_ERROR, exit_dcke); } - *inOutIdx += qshSz; + + /* These RSA variables persist throughout DoClientKeyExchange */ + *output = NULL; + ret = RsaDec(ssl, + input + idx, + length, + output, + &ssl->sigLen, + (RsaKey*)ssl->sigKey, + #if defined(HAVE_PK_CALLBACKS) + ssl->buffers.key->buffer, + ssl->buffers.key->length, + ssl->RsaDecCtx + #else + NULL, 0, NULL + #endif + ); + break; + } /* rsa_kea */ + #endif /* !NO_RSA */ + #ifndef NO_PSK + case psk_kea: + { + byte* pms = ssl->arrays->preMasterSecret; + word16 ci_sz; + + if ((idx - begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + ato16(input + idx, &ci_sz); + idx += OPAQUE16_LEN; + + if (ci_sz > MAX_PSK_ID_LEN) { + ERROR_OUT(CLIENT_ID_ERROR, exit_dcke); + } + + if ((idx - begin) + ci_sz > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + XMEMCPY(ssl->arrays->client_identity, input + idx, ci_sz); + idx += ci_sz; + + ssl->arrays->client_identity[min(ci_sz, MAX_PSK_ID_LEN-1)] = 0; + ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, + ssl->arrays->client_identity, ssl->arrays->psk_key, + MAX_PSK_KEY_LEN); + + if (ssl->arrays->psk_keySz == 0 || + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { + ERROR_OUT(PSK_KEY_ERROR, exit_dcke); + } + + /* make psk pre master secret */ + /* length of key + length 0s + length of key + key */ + c16toa((word16) ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + + XMEMSET(pms, 0, ssl->arrays->psk_keySz); + pms += ssl->arrays->psk_keySz; + + c16toa((word16) ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + + XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); + ssl->arrays->preMasterSz = ssl->arrays->psk_keySz * 2 + 4; + break; } - else { - /* unknown extension sent client ignored - handshake */ - return BUFFER_ERROR; + #endif /* !NO_PSK */ + #ifdef HAVE_NTRU + case ntru_kea: + { + word16 cipherLen; + word16 plainLen = sizeof(ssl->arrays->preMasterSecret); + + if ((idx - begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + ato16(input + idx, &cipherLen); + idx += OPAQUE16_LEN; + + if (cipherLen > MAX_NTRU_ENCRYPT_SZ) { + ERROR_OUT(NTRU_KEY_ERROR, exit_dcke); + } + + if ((idx - begin) + cipherLen > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + if (NTRU_OK != ntru_crypto_ntru_decrypt( + (word16) ssl->buffers.key->length, + ssl->buffers.key->buffer, cipherLen, + input + idx, &plainLen, + ssl->arrays->preMasterSecret)) { + ERROR_OUT(NTRU_DECRYPT_ERROR, exit_dcke); + } + + if (plainLen != SECRET_LEN) { + ERROR_OUT(NTRU_DECRYPT_ERROR, exit_dcke); + } + + idx += cipherLen; + ssl->arrays->preMasterSz = plainLen; + + break; } - } - #endif - ssl->arrays->preMasterSz = plainLen; - ret = MakeMasterSecret(ssl); - } - break; - #endif /* HAVE_NTRU */ - #ifdef HAVE_ECC - case ecc_diffie_hellman_kea: - { - if ((*inOutIdx - begin) + OPAQUE8_LEN > size) { - return BUFFER_ERROR; - } + #endif /* HAVE_NTRU */ + #ifdef HAVE_ECC + case ecc_diffie_hellman_kea: + { + ecc_key* private_key = ssl->eccTempKey; - length = input[(*inOutIdx)++]; + if ((idx - begin) + OPAQUE8_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } - if ((*inOutIdx - begin) + length > size) { - return BUFFER_ERROR; - } + length = input[idx++]; - if (ssl->peerEccKey == NULL) { - /* alloc/init on demand */ - ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key), + if ((idx - begin) + length > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + if (ssl->peerEccKey == NULL) { + /* alloc/init on demand */ + ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key), + ssl->ctx->heap, DYNAMIC_TYPE_ECC); + if (ssl->peerEccKey == NULL) { + WOLFSSL_MSG("PeerEccKey Memory error"); + ERROR_OUT(MEMORY_E, exit_dcke); + } + wc_ecc_init(ssl->peerEccKey); + } else if (ssl->peerEccKeyPresent) { /* don't leak on reuse */ + wc_ecc_free(ssl->peerEccKey); + ssl->peerEccKeyPresent = 0; + wc_ecc_init(ssl->peerEccKey); + } + + if (wc_ecc_import_x963(input + idx, length, ssl->peerEccKey)) { + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dcke); + } + + idx += length; + ssl->peerEccKeyPresent = 1; + + ssl->sigLen = sizeof(ssl->arrays->preMasterSecret); + + if (ssl->specs.static_ecdh) { + word32 i = 0; + + ssl->sigKey = XMALLOC(sizeof(ecc_key), NULL, DYNAMIC_TYPE_ECC); + if (ssl->sigKey == NULL) { + ERROR_OUT(MEMORY_E, exit_dcke); + } + ssl->sigType = DYNAMIC_TYPE_ECC; + + wc_ecc_init((ecc_key*)ssl->sigKey); + + ret = wc_EccPrivateKeyDecode( + ssl->buffers.key->buffer, + &i, + (ecc_key*)ssl->sigKey, + ssl->buffers.key->length); + if (ret == 0) { + private_key = (ecc_key*)ssl->sigKey; + } + } + else if (ssl->eccTempKeyPresent == 0) { + WOLFSSL_MSG("Ecc ephemeral key not made correctly"); + ERROR_OUT(ECC_MAKEKEY_ERROR, exit_dcke); + } + if (ret != 0) { + ERROR_OUT(ECC_SHARED_ERROR, exit_dcke); + } + + /* Generate shared secret */ + ret = EccSharedSecret(ssl, private_key, ssl->peerEccKey, + ssl->arrays->preMasterSecret, &ssl->sigLen); + break; + } + #endif /* HAVE_ECC */ + #ifndef NO_DH + case diffie_hellman_kea: + { + word16 clientPubSz; + + if ((idx - begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + ato16(input + idx, &clientPubSz); + idx += OPAQUE16_LEN; + + if ((idx - begin) + clientPubSz > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + ret = DhAgree(ssl, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length, + ssl->buffers.serverDH_Priv.buffer, + &ssl->buffers.serverDH_Priv.length, + NULL, + 0, + input + idx, + clientPubSz, + ssl->arrays->preMasterSecret, + &ssl->arrays->preMasterSz); + + idx += clientPubSz; + break; + } + #endif /* !NO_DH */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + byte* pms = ssl->arrays->preMasterSecret; + word16 clientSz; + + /* Read in the PSK hint */ + if ((idx - begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + ato16(input + idx, &clientSz); + idx += OPAQUE16_LEN; + if (clientSz > MAX_PSK_ID_LEN) { + ERROR_OUT(CLIENT_ID_ERROR, exit_dcke); + } + + if ((idx - begin) + clientSz > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + XMEMCPY(ssl->arrays->client_identity, input + idx, clientSz); + idx += clientSz; + ssl->arrays->client_identity[ + min(clientSz, MAX_PSK_ID_LEN-1)] = 0; + + /* Read in the DHE business */ + if ((idx - begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + ato16(input + idx, &clientSz); + idx += OPAQUE16_LEN; + + if ((idx - begin) + clientSz > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + ret = DhAgree(ssl, + ssl->buffers.serverDH_P.buffer, + ssl->buffers.serverDH_P.length, + ssl->buffers.serverDH_G.buffer, + ssl->buffers.serverDH_G.length, + ssl->buffers.serverDH_Priv.buffer, + &ssl->buffers.serverDH_Priv.length, + NULL, + 0, + input + idx, + clientSz, + pms + OPAQUE16_LEN, + &ssl->arrays->preMasterSz); + + idx += clientSz; + c16toa((word16)ssl->arrays->preMasterSz, pms); + ssl->arrays->preMasterSz += OPAQUE16_LEN; + pms += ssl->arrays->preMasterSz; + + /* Use the PSK hint to look up the PSK and add it to the + * preMasterSecret here. */ + ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, + ssl->arrays->client_identity, ssl->arrays->psk_key, + MAX_PSK_KEY_LEN); + + if (ssl->arrays->psk_keySz == 0 || + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { + ERROR_OUT(PSK_KEY_ERROR, exit_dcke); + } + + c16toa((word16) ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + + XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); + ssl->arrays->preMasterSz += ssl->arrays->psk_keySz + OPAQUE16_LEN; + break; + } + #endif /* !NO_DH && !NO_PSK */ + #if defined(HAVE_ECC) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + word16 clientSz; + + /* Read in the PSK hint */ + if ((idx - begin) + OPAQUE16_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + ato16(input + idx, &clientSz); + idx += OPAQUE16_LEN; + if (clientSz > MAX_PSK_ID_LEN) { + ERROR_OUT(CLIENT_ID_ERROR, exit_dcke); + } + if ((idx - begin) + clientSz > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + XMEMCPY(ssl->arrays->client_identity, + input + idx, clientSz); + idx += clientSz; + ssl->arrays->client_identity[ + min(clientSz, MAX_PSK_ID_LEN-1)] = 0; + + /* ECC key */ + if ((idx - begin) + OPAQUE8_LEN > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + length = input[idx++]; + + if ((idx - begin) + length > size) { + ERROR_OUT(BUFFER_ERROR, exit_dcke); + } + + if (ssl->peerEccKey == NULL) { + /* alloc/init on demand */ + ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key), ssl->ctx->heap, DYNAMIC_TYPE_ECC); - if (ssl->peerEccKey == NULL) { - WOLFSSL_MSG("PeerEccKey Memory error"); - return MEMORY_E; + if (ssl->peerEccKey == NULL) { + WOLFSSL_MSG("PeerEccKey Memory error"); + ERROR_OUT(MEMORY_E, exit_dcke); + } + wc_ecc_init(ssl->peerEccKey); + } else if (ssl->peerEccKeyPresent) { /* don't leak on reuse */ + wc_ecc_free(ssl->peerEccKey); + ssl->peerEccKeyPresent = 0; + wc_ecc_init(ssl->peerEccKey); + } + if (wc_ecc_import_x963(input + idx, length, + ssl->peerEccKey)) { + ERROR_OUT(ECC_PEERKEY_ERROR, exit_dcke); + } + + idx += length; + ssl->peerEccKeyPresent = 1; + + /* Note sizeof preMasterSecret is ENCRYPT_LEN currently 512 */ + ssl->sigLen = sizeof(ssl->arrays->preMasterSecret); + + if (ssl->eccTempKeyPresent == 0) { + WOLFSSL_MSG("Ecc ephemeral key not made correctly"); + ERROR_OUT(ECC_MAKEKEY_ERROR, exit_dcke); + } + + /* Generate shared secret */ + ret = EccSharedSecret(ssl, + ssl->eccTempKey, + ssl->peerEccKey, + ssl->arrays->preMasterSecret + OPAQUE16_LEN, + &ssl->sigLen); + break; } - wc_ecc_init(ssl->peerEccKey); - } else if (ssl->peerEccKeyPresent) { /* don't leak on reuse */ - wc_ecc_free(ssl->peerEccKey); - ssl->peerEccKeyPresent = 0; - wc_ecc_init(ssl->peerEccKey); - } - - if (wc_ecc_import_x963(input + *inOutIdx, length, ssl->peerEccKey)) { - return ECC_PEERKEY_ERROR; - } - - *inOutIdx += length; - ssl->peerEccKeyPresent = 1; - - length = sizeof(ssl->arrays->preMasterSecret); - - if (ssl->specs.static_ecdh) { - ecc_key staticKey; - word32 i = 0; - - wc_ecc_init(&staticKey); - ret = wc_EccPrivateKeyDecode(ssl->buffers.key->buffer, &i, - &staticKey, ssl->buffers.key->length); - - if (ret == 0) { - ret = wc_ecc_shared_secret(&staticKey, ssl->peerEccKey, - ssl->arrays->preMasterSecret, &length); - } - - wc_ecc_free(&staticKey); - } - else { - if (ssl->eccTempKeyPresent == 0) { - WOLFSSL_MSG("Ecc ephemeral key not made correctly"); - ret = ECC_MAKEKEY_ERROR; - } else { - ret = wc_ecc_shared_secret(ssl->eccTempKey,ssl->peerEccKey, - ssl->arrays->preMasterSecret, &length); - } - } + #endif /* HAVE_ECC && !NO_PSK */ + default: + ret = BAD_KEA_TYPE_E; + } /* switch (ssl->specs.kea) */ + /* Check for error */ if (ret != 0) { - return ECC_SHARED_ERROR; + goto exit_dcke; } - ssl->arrays->preMasterSz = length; + /* Advance state and proceed */ + ssl->options.keyShareState = KEYSHARE_VERIFY; + } /* KEYSHARE_BUILD */ + + case KEYSHARE_VERIFY: + { + switch (ssl->specs.kea) { + #ifndef NO_RSA + case rsa_kea: + { + /* Add the signature length to idx */ + idx += length; + + if (ssl->sigLen == SECRET_LEN && *output != NULL) { + XMEMCPY(ssl->arrays->preMasterSecret, *output, SECRET_LEN); + if (ssl->arrays->preMasterSecret[0] != ssl->chVersion.major || + ssl->arrays->preMasterSecret[1] != ssl->chVersion.minor) { + ERROR_OUT(PMS_VERSION_ERROR, exit_dcke); + } + } + else { + ERROR_OUT(RSA_PRIVATE_ERROR, exit_dcke); + } + break; + } /* rsa_kea */ + #endif /* !NO_RSA */ + #ifndef NO_PSK + case psk_kea: + { + break; + } + #endif /* !NO_PSK */ + #ifdef HAVE_NTRU + case ntru_kea: + { + break; + } + #endif /* HAVE_NTRU */ + #ifdef HAVE_ECC + case ecc_diffie_hellman_kea: + { + ssl->arrays->preMasterSz = ssl->sigLen; + break; + } + #endif /* HAVE_ECC */ + #ifndef NO_DH + case diffie_hellman_kea: + { + break; + } + #endif /* !NO_DH */ + #if !defined(NO_DH) && !defined(NO_PSK) + case dhe_psk_kea: + { + break; + } + #endif /* !NO_DH && !NO_PSK */ + #if defined(HAVE_ECC) && !defined(NO_PSK) + case ecdhe_psk_kea: + { + byte* pms = ssl->arrays->preMasterSecret; + + /* Add preMasterSecret */ + c16toa((word16)ssl->sigLen, pms); + ssl->arrays->preMasterSz += OPAQUE16_LEN + ssl->sigLen; + pms += ssl->arrays->preMasterSz; + + /* Use the PSK hint to look up the PSK and add it to the + * preMasterSecret here. */ + ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, + ssl->arrays->client_identity, ssl->arrays->psk_key, + MAX_PSK_KEY_LEN); + + if (ssl->arrays->psk_keySz == 0 || + ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { + ERROR_OUT(PSK_KEY_ERROR, exit_dcke); + } + + c16toa((word16) ssl->arrays->psk_keySz, pms); + pms += OPAQUE16_LEN; + + XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); + ssl->arrays->preMasterSz += + ssl->arrays->psk_keySz + OPAQUE16_LEN; + break; + } + #endif /* HAVE_ECC && !NO_PSK */ + default: + ret = BAD_KEA_TYPE_E; + } /* switch (ssl->specs.kea) */ + + /* Check for error */ + if (ret != 0) { + goto exit_dcke; + } + + /* Advance state and proceed */ + ssl->options.keyShareState = KEYSHARE_FINALIZE; + } /* KEYSHARE_VERIFY */ + + case KEYSHARE_FINALIZE: + { #ifdef HAVE_QSH + word16 name; + int qshSz; + if (ssl->options.haveQSH) { /* extension name */ - ato16(input + *inOutIdx, &name); - *inOutIdx += OPAQUE16_LEN; + ato16(input + idx, &name); + idx += OPAQUE16_LEN; if (name == TLSX_QUANTUM_SAFE_HYBRID) { - /* if qshSz is larger than 0 it is the length of - buffer used */ - if ((qshSz = TLSX_QSHCipher_Parse(ssl, input + *inOutIdx, - size - *inOutIdx + begin, 1)) < 0) { - return qshSz; + /* if qshSz is larger than 0 it is the + length of buffer used */ + if ((qshSz = TLSX_QSHCipher_Parse(ssl, + input + idx, + size - idx + begin, 1)) < 0) { + ERROR_OUT(qshSz, exit_dcke); } - *inOutIdx += qshSz; + idx += qshSz; } else { - /* unknown extension sent client ignored - handshake */ - return BUFFER_ERROR; + /* unknown extension sent client ignored handshake */ + ERROR_OUT(BUFFER_ERROR, exit_dcke); } } #endif ret = MakeMasterSecret(ssl); - } - break; - #endif /* HAVE_ECC */ - #ifndef NO_DH - case diffie_hellman_kea: - { - word16 clientPubSz; - DhKey dhKey; - - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) { - return BUFFER_ERROR; - } - - ato16(input + *inOutIdx, &clientPubSz); - *inOutIdx += OPAQUE16_LEN; - - if ((*inOutIdx - begin) + clientPubSz > size) { - return BUFFER_ERROR; - } - - wc_InitDhKey(&dhKey); - ret = wc_DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer, - ssl->buffers.serverDH_P.length, - ssl->buffers.serverDH_G.buffer, - ssl->buffers.serverDH_G.length); - if (ret == 0) { - ret = wc_DhAgree(&dhKey, ssl->arrays->preMasterSecret, - &ssl->arrays->preMasterSz, - ssl->buffers.serverDH_Priv.buffer, - ssl->buffers.serverDH_Priv.length, - input + *inOutIdx, clientPubSz); - } - wc_FreeDhKey(&dhKey); - - *inOutIdx += clientPubSz; - - #ifdef HAVE_QSH - if (ssl->options.haveQSH) { - /* extension name */ - ato16(input + *inOutIdx, &name); - *inOutIdx += OPAQUE16_LEN; - - if (name == TLSX_QUANTUM_SAFE_HYBRID) { - /* if qshSz is larger than 0 it is the length of - buffer used */ - if ((qshSz = TLSX_QSHCipher_Parse(ssl, input + *inOutIdx, - size - *inOutIdx + begin, 1)) < 0) { - return qshSz; - } - *inOutIdx += qshSz; - } - else { - /* unknown extension sent client ignored - handshake */ - return BUFFER_ERROR; - } - } - #endif - if (ret == 0) { - ret = MakeMasterSecret(ssl); - } - } - break; - #endif /* NO_DH */ - #if !defined(NO_DH) && !defined(NO_PSK) - case dhe_psk_kea: - { - byte* pms = ssl->arrays->preMasterSecret; - word16 clientSz; - DhKey dhKey; - - /* sanity check that PSK server callback has been set */ - if (ssl->options.server_psk_cb == NULL) { - WOLFSSL_MSG("No server PSK callback set"); - return PSK_KEY_ERROR; - } - - /* Read in the PSK hint */ - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) { - return BUFFER_ERROR; - } - - ato16(input + *inOutIdx, &clientSz); - *inOutIdx += OPAQUE16_LEN; - if (clientSz > MAX_PSK_ID_LEN) { - return CLIENT_ID_ERROR; - } - - if ((*inOutIdx - begin) + clientSz > size) { - return BUFFER_ERROR; - } - - XMEMCPY(ssl->arrays->client_identity, - input + *inOutIdx, clientSz); - *inOutIdx += clientSz; - ssl->arrays->client_identity[min(clientSz, MAX_PSK_ID_LEN-1)] = - 0; - - /* Read in the DHE business */ - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) { - return BUFFER_ERROR; - } - - ato16(input + *inOutIdx, &clientSz); - *inOutIdx += OPAQUE16_LEN; - - if ((*inOutIdx - begin) + clientSz > size) { - return BUFFER_ERROR; - } - - wc_InitDhKey(&dhKey); - ret = wc_DhSetKey(&dhKey, ssl->buffers.serverDH_P.buffer, - ssl->buffers.serverDH_P.length, - ssl->buffers.serverDH_G.buffer, - ssl->buffers.serverDH_G.length); - if (ret == 0) { - ret = wc_DhAgree(&dhKey, pms + OPAQUE16_LEN, - &ssl->arrays->preMasterSz, - ssl->buffers.serverDH_Priv.buffer, - ssl->buffers.serverDH_Priv.length, - input + *inOutIdx, clientSz); - } - wc_FreeDhKey(&dhKey); - - *inOutIdx += clientSz; - c16toa((word16)ssl->arrays->preMasterSz, pms); - ssl->arrays->preMasterSz += OPAQUE16_LEN; - pms += ssl->arrays->preMasterSz; - - /* Use the PSK hint to look up the PSK and add it to the - * preMasterSecret here. */ - ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, - ssl->arrays->client_identity, ssl->arrays->psk_key, - MAX_PSK_KEY_LEN); - - if (ssl->arrays->psk_keySz == 0 || - ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { - return PSK_KEY_ERROR; - } - - c16toa((word16) ssl->arrays->psk_keySz, pms); - pms += OPAQUE16_LEN; - - XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); - ssl->arrays->preMasterSz += - ssl->arrays->psk_keySz + OPAQUE16_LEN; - #ifdef HAVE_QSH - if (ssl->options.haveQSH) { - /* extension name */ - ato16(input + *inOutIdx, &name); - *inOutIdx += OPAQUE16_LEN; - - if (name == TLSX_QUANTUM_SAFE_HYBRID) { - /* if qshSz is larger than 0 it is the length of - buffer used */ - if ((qshSz = TLSX_QSHCipher_Parse(ssl, input + *inOutIdx, - size - *inOutIdx + begin, 1)) < 0) { - return qshSz; - } - *inOutIdx += qshSz; - } - else { - /* unknown extension sent client ignored - handshake */ - return BUFFER_ERROR; - } - } - #endif - if (ret == 0) - ret = MakeMasterSecret(ssl); - - /* No further need for PSK */ - ForceZero(ssl->arrays->psk_key, ssl->arrays->psk_keySz); - ssl->arrays->psk_keySz = 0; - } - break; - #endif /* !NO_DH && !NO_PSK */ - #if defined(HAVE_ECC) && !defined(NO_PSK) - case ecdhe_psk_kea: - { - byte* pms = ssl->arrays->preMasterSecret; - word16 clientSz; - - /* sanity check that PSK server callback has been set */ - if (ssl->options.server_psk_cb == NULL) { - WOLFSSL_MSG("No server PSK callback set"); - return PSK_KEY_ERROR; - } - - /* Read in the PSK hint */ - if ((*inOutIdx - begin) + OPAQUE16_LEN > size) { - return BUFFER_ERROR; - } - - ato16(input + *inOutIdx, &clientSz); - *inOutIdx += OPAQUE16_LEN; - if (clientSz > MAX_PSK_ID_LEN) { - return CLIENT_ID_ERROR; - } - - if ((*inOutIdx - begin) + clientSz > size) { - return BUFFER_ERROR; - } - - XMEMCPY(ssl->arrays->client_identity, - input + *inOutIdx, clientSz); - *inOutIdx += clientSz; - ssl->arrays->client_identity[min(clientSz, MAX_PSK_ID_LEN-1)] = - 0; - - /* ECC key */ - if ((*inOutIdx - begin) + OPAQUE8_LEN > size) { - return BUFFER_ERROR; - } - - length = input[(*inOutIdx)++]; - - if ((*inOutIdx - begin) + length > size) { - return BUFFER_ERROR; - } - - if (ssl->peerEccKey == NULL) { - /* alloc/init on demand */ - ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key), - ssl->ctx->heap, DYNAMIC_TYPE_ECC); - if (ssl->peerEccKey == NULL) { - WOLFSSL_MSG("PeerEccKey Memory error"); - return MEMORY_E; - } - wc_ecc_init(ssl->peerEccKey); - } else if (ssl->peerEccKeyPresent) { /* don't leak on reuse */ - wc_ecc_free(ssl->peerEccKey); - ssl->peerEccKeyPresent = 0; - wc_ecc_init(ssl->peerEccKey); - } - - if (wc_ecc_import_x963(input + *inOutIdx, length, - ssl->peerEccKey)) { - return ECC_PEERKEY_ERROR; - } - - *inOutIdx += length; - ssl->peerEccKeyPresent = 1; - - /* Note sizeof preMasterSecret is ENCRYPT_LEN currently 512 */ - length = sizeof(ssl->arrays->preMasterSecret); - - if (ssl->eccTempKeyPresent == 0) { - WOLFSSL_MSG("Ecc ephemeral key not made correctly"); - ret = ECC_MAKEKEY_ERROR; - } else { - ret = wc_ecc_shared_secret(ssl->eccTempKey, - ssl->peerEccKey, ssl->arrays->preMasterSecret + - OPAQUE16_LEN, &length); - } + /* Check for error */ if (ret != 0) { - return ECC_SHARED_ERROR; + goto exit_dcke; } - c16toa((word16)length, pms); - ssl->arrays->preMasterSz += OPAQUE16_LEN + length; - pms += ssl->arrays->preMasterSz; + /* Advance state and proceed */ + ssl->options.keyShareState = KEYSHARE_END; + } /* KEYSHARE_FINALIZE */ - /* Use the PSK hint to look up the PSK and add it to the - * preMasterSecret here. */ - ssl->arrays->psk_keySz = ssl->options.server_psk_cb(ssl, - ssl->arrays->client_identity, ssl->arrays->psk_key, - MAX_PSK_KEY_LEN); - - if (ssl->arrays->psk_keySz == 0 || - ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) { - return PSK_KEY_ERROR; - } - - c16toa((word16) ssl->arrays->psk_keySz, pms); - pms += OPAQUE16_LEN; - - XMEMCPY(pms, ssl->arrays->psk_key, ssl->arrays->psk_keySz); - ssl->arrays->preMasterSz += - ssl->arrays->psk_keySz + OPAQUE16_LEN; - - #ifdef HAVE_QSH - if (ssl->options.haveQSH) { - /* extension name */ - ato16(input + *inOutIdx, &name); - *inOutIdx += OPAQUE16_LEN; - - if (name == TLSX_QUANTUM_SAFE_HYBRID) { - /* if qshSz is larger than 0 it is the length of - buffer used */ - if ((qshSz = TLSX_QSHCipher_Parse(ssl, input + *inOutIdx, - size - *inOutIdx + begin, 1)) < 0) { - return qshSz; - } - *inOutIdx += qshSz; - } - else { - /* unknown extension sent client ignored - handshake */ - return BUFFER_ERROR; - } - } - #endif - if (ret == 0) - ret = MakeMasterSecret(ssl); - - /* No further need for PSK */ - ForceZero(ssl->arrays->psk_key, ssl->arrays->psk_keySz); - ssl->arrays->psk_keySz = 0; - } - break; - #endif /* HAVE_ECC && !NO_PSK */ - default: + case KEYSHARE_END: { - WOLFSSL_MSG("Bad kea type"); - ret = BAD_KEA_TYPE_E; - } - break; - } + /* Set final index */ + *inOutIdx = idx; - /* No further need for PMS */ - ForceZero(ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz); - ssl->arrays->preMasterSz = 0; - - if (ret == 0) { - ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; + ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE; #ifndef NO_CERTS if (ssl->options.verifyPeer) { ret = BuildCertHashes(ssl, &ssl->hsHashes->certHashes); } #endif + break; + } /* KEYSHARE_END */ + default: + ret = INPUT_CASE_ERROR; + } /* switch(ssl->options.keyShareState) */ + + exit_dcke: + #ifdef WOLFSSL_ASYNC_CRYPT + /* Handle WC_PENDING_E */ + if (ret == WC_PENDING_E) { + /* Store variables needed for async */ + XMEMSET(&ssl->async, 0, sizeof(ssl->async)); + ssl->async.idx = idx; + ssl->async.length = length; + + /* Adjust the index so header will be re-evaluated */ + *inOutIdx -= HANDSHAKE_HEADER_SZ; + /* Mark message as not recevied so it can process again */ + ssl->msgsReceived.got_client_key_exchange = 0; + + /* Push event to queue */ + ret = wolfSSL_async_push(ssl, WOLF_EVENT_TYPE_ASYNC_ACCEPT); + if (ret == 0) { + return WC_PENDING_E; + } } + #endif + + /* Cleanup PMS */ + ForceZero(ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz); + ssl->arrays->preMasterSz = 0; + + /* Final cleanup */ + FreeKeyExchange(ssl); return ret; } + #ifdef HAVE_STUNNEL static int SNI_Callback(WOLFSSL* ssl) { @@ -17725,4 +17505,7 @@ int DoSessionTicket(WOLFSSL* ssl, } #endif /* HAVE_STUNNEL */ #endif /* NO_WOLFSSL_SERVER */ + +#undef ERROR_OUT + #endif /* WOLFCRYPT_ONLY */ diff --git a/src/ssl.c b/src/ssl.c index 5e462e1c0..78ae3edcb 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -17826,4 +17826,119 @@ void* wolfSSL_get_jobject(WOLFSSL* ssl) #endif /* WOLFSSL_JNI */ +#ifdef HAVE_WOLF_EVENT +int wolfssl_CTX_poll_peek(WOLFSSL_CTX* ctx, int* eventCount) +{ + WOLF_EVENT* event; + int count = 0; + + if (ctx == NULL) { + return BAD_FUNC_ARG; + } + +#ifndef SINGLE_THREADED + if (LockMutex(&ctx->event_queue.lock) != 0) { + return BAD_MUTEX_E; + } +#endif + + /* Itterate event queue */ + for (event = ctx->event_queue.head; event != NULL; event = event->next) { + count++; + } + +#ifndef SINGLE_THREADED + UnLockMutex(&ctx->event_queue.lock); +#endif + + if (eventCount) { + *eventCount = count; + } + + return 0; +} + +int wolfSSL_CTX_poll(WOLFSSL_CTX* ctx, WOLF_EVENT* events, int maxEvents, + unsigned char flags, int* eventCount) +{ + WOLF_EVENT* event, *event_prev = NULL; + int count = 0, ret = SSL_ERROR_NONE; + + if (ctx == NULL || events == NULL || maxEvents <= 0) { + return BAD_FUNC_ARG; + } + +#ifndef SINGLE_THREADED + if (LockMutex(&ctx->event_queue.lock) != 0) { + return BAD_MUTEX_E; + } +#endif + + /* Itterate event queue */ + for (event = ctx->event_queue.head; event != NULL; event = event->next) + { + byte removeEvent = 0; + + #ifdef WOLFSSL_ASYNC_CRYPT + if (event->type >= WOLF_EVENT_TYPE_ASYNC_FIRST && + event->type <= WOLF_EVENT_TYPE_ASYNC_LAST) + { + ret = wolfSSL_async_poll(event, flags); + } + #endif /* WOLFSSL_ASYNC_CRYPT */ + + /* If event is done add to returned event data */ + if (event->done) { + /* Check to make sure we have room for event */ + if (count >= maxEvents) { + break; /* Exit for */ + } + + /* Copy event data to provided buffer */ + XMEMCPY(&events[count], event, sizeof(WOLF_EVENT)); + count++; + removeEvent = 1; + } + + if (removeEvent) { + /* Remove from queue list */ + if (event_prev == NULL) { + ctx->event_queue.head = event->next; + if (ctx->event_queue.head == NULL) { + ctx->event_queue.tail = NULL; + } + } + else { + event_prev->next = event->next; + } + } + else { + /* Leave in queue, save prev pointer */ + event_prev = event; + } + + /* Check for error */ + if (ret < 0) { + break; /* Exit for */ + } + } + +#ifndef SINGLE_THREADED + UnLockMutex(&ctx->event_queue.lock); +#endif + + /* Return number of poperly populated events */ + if (eventCount) { + *eventCount = count; + } + + /* Make sure success returns 0 */ + if (ret > 0) { + ret = 0; + } + + return ret; +} +#endif /* HAVE_WOLF_EVENT */ + #endif /* WOLFCRYPT_ONLY */ diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 79ed25d03..e23ae37b2 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -788,7 +788,7 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) switch (type) { - case hashType: + case oidHashType: switch (id) { case MD2h: oid = hashMd2hOid; @@ -817,7 +817,7 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) } break; - case sigType: + case oidSigType: switch (id) { #ifndef NO_DSA case CTC_SHAwDSA: @@ -874,7 +874,7 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) } break; - case keyType: + case oidKeyType: switch (id) { #ifndef NO_DSA case DSAk: @@ -906,7 +906,7 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) break; #ifdef HAVE_ECC - case curveType: + case oidCurveType: switch (id) { #if defined(HAVE_ALL_CURVES) || !defined(NO_ECC256) case ECC_256R1: @@ -950,7 +950,7 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) break; #endif /* HAVE_ECC */ - case blkType: + case oidBlkType: switch (id) { case DESb: oid = blkDesCbcOid; @@ -964,7 +964,7 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) break; #ifdef HAVE_OCSP - case ocspType: + case oidOcspType: switch (id) { case OCSP_BASIC_OID: oid = ocspBasicOid; @@ -978,7 +978,7 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) break; #endif /* HAVE_OCSP */ - case certExtType: + case oidCertExtType: switch (id) { case BASIC_CA_OID: oid = extBasicCaOid; @@ -1027,7 +1027,7 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) } break; - case certAuthInfoType: + case oidCertAuthInfoType: switch (id) { case AIA_OCSP_OID: oid = extAuthInfoOcspOid; @@ -1040,7 +1040,7 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) } break; - case certPolicyType: + case oidCertPolicyType: switch (id) { case CP_ANY_OID: oid = extCertPolicyAnyOid; @@ -1049,7 +1049,7 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) } break; - case certAltNameType: + case oidCertAltNameType: switch (id) { case HW_NAME_OID: oid = extAltNamesHwNameOid; @@ -1058,7 +1058,7 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) } break; - case certKeyUseType: + case oidCertKeyUseType: switch (id) { case EKU_ANY_OID: oid = extExtKeyUsageAnyOid; @@ -1078,7 +1078,7 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) break; } - case kdfType: + case oidKdfType: switch (id) { case PBKDF2_OID: oid = pbkdf2Oid; @@ -1087,7 +1087,7 @@ static const byte* OidFromId(word32 id, word32 type, word32* oidSz) } break; - case ignoreType: + case oidIgnoreType: default: break; } @@ -1138,7 +1138,7 @@ WOLFSSL_LOCAL int GetObjectId(const byte* input, word32* inOutIdx, word32* oid, const byte* checkOid = NULL; word32 checkOidSz; - if (oidType != ignoreType) { + if (oidType != oidIgnoreType) { checkOid = OidFromId(*oid, oidType, &checkOidSz); if (checkOid != NULL && @@ -1317,7 +1317,7 @@ int ToTraditional(byte* input, word32 sz) if (GetMyVersion(input, &inOutIdx, &version) < 0) return ASN_PARSE_E; - if (GetAlgoId(input, &inOutIdx, &oid, sigType, sz) < 0) + if (GetAlgoId(input, &inOutIdx, &oid, oidSigType, sz) < 0) return ASN_PARSE_E; if (input[inOutIdx] == ASN_OBJECT_ID) { @@ -1594,7 +1594,7 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz) if (GetSequence(input, &inOutIdx, &length, sz) < 0) return ASN_PARSE_E; - if (GetAlgoId(input, &inOutIdx, &oid, sigType, sz) < 0) + if (GetAlgoId(input, &inOutIdx, &oid, oidSigType, sz) < 0) return ASN_PARSE_E; first = input[inOutIdx - 2]; /* PKCS version always 2nd to last byte */ @@ -1608,7 +1608,7 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz) if (GetSequence(input, &inOutIdx, &length, sz) < 0) return ASN_PARSE_E; - if (GetAlgoId(input, &inOutIdx, &oid, kdfType, sz) < 0) + if (GetAlgoId(input, &inOutIdx, &oid, oidKdfType, sz) < 0) return ASN_PARSE_E; if (oid != PBKDF2_OID) @@ -1654,7 +1654,7 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz) if (version == PKCS5v2) { /* get encryption algo */ /* JOHN: New type. Need a little more research. */ - if (GetAlgoId(input, &inOutIdx, &oid, blkType, sz) < 0) { + if (GetAlgoId(input, &inOutIdx, &oid, oidBlkType, sz) < 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER); XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -2352,7 +2352,7 @@ static int GetKey(DecodedCert* cert) return ASN_PARSE_E; if (GetAlgoId(cert->source, &cert->srcIdx, - &cert->keyOID, keyType, cert->maxIdx) < 0) + &cert->keyOID, oidKeyType, cert->maxIdx) < 0) return ASN_PARSE_E; switch (cert->keyOID) { @@ -2443,7 +2443,7 @@ static int GetKey(DecodedCert* cert) byte b; if (GetObjectId(cert->source, &cert->srcIdx, - &cert->pkCurveOID, curveType, cert->maxIdx) < 0) + &cert->pkCurveOID, oidCurveType, cert->maxIdx) < 0) return ASN_PARSE_E; if (CheckCurve(cert->pkCurveOID) < 0) @@ -3146,7 +3146,7 @@ int DecodeToKey(DecodedCert* cert, int verify) WOLFSSL_MSG("Got Cert Header"); if ( (ret = GetAlgoId(cert->source, &cert->srcIdx, &cert->signatureOID, - sigType, cert->maxIdx)) < 0) + oidSigType, cert->maxIdx)) < 0) return ret; WOLFSSL_MSG("Got Algo ID"); @@ -3377,8 +3377,8 @@ WOLFSSL_LOCAL word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz) byte ID_Length[MAX_LENGTH_SZ]; byte seqArray[MAX_SEQ_SZ + 1]; /* add object_id to end */ - tagSz = (type == hashType || type == sigType || - (type == keyType && algoOID == RSAk)) ? 2 : 0; + tagSz = (type == oidHashType || type == oidSigType || + (type == oidKeyType && algoOID == RSAk)) ? 2 : 0; algoName = OidFromId(algoOID, type, &algoSz); @@ -3414,7 +3414,7 @@ word32 wc_EncodeSignature(byte* out, const byte* digest, word32 digSz, word32 encDigSz, algoSz, seqSz; encDigSz = SetDigest(digest, digSz, digArray); - algoSz = SetAlgoID(hashOID, algoArray, hashType, 0); + algoSz = SetAlgoID(hashOID, algoArray, oidHashType, 0); seqSz = SetSequence(encDigSz + algoSz, seqArray); XMEMCPY(out, seqArray, seqSz); @@ -3986,7 +3986,7 @@ static int DecodeAltNames(byte* input, int sz, DecodedCert* cert) /* Consume the rest of this sequence. */ length -= (strLen + idx - lenStartIdx); - if (GetObjectId(input, &idx, &oid, certAltNameType, sz) < 0) { + if (GetObjectId(input, &idx, &oid, oidCertAltNameType, sz) < 0) { WOLFSSL_MSG("\tbad OID"); return ASN_PARSE_E; } @@ -4237,7 +4237,7 @@ static int DecodeAuthInfo(byte* input, int sz, DecodedCert* cert) return ASN_PARSE_E; oid = 0; - if (GetObjectId(input, &idx, &oid, certAuthInfoType, sz) < 0) + if (GetObjectId(input, &idx, &oid, oidCertAuthInfoType, sz) < 0) return ASN_PARSE_E; /* Only supporting URIs right now. */ @@ -4383,7 +4383,7 @@ static int DecodeExtKeyUsage(byte* input, int sz, DecodedCert* cert) #endif while (idx < (word32)sz) { - if (GetObjectId(input, &idx, &oid, certKeyUseType, sz) < 0) + if (GetObjectId(input, &idx, &oid, oidCertKeyUseType, sz) < 0) return ASN_PARSE_E; switch (oid) { @@ -4718,7 +4718,7 @@ static int DecodeCertExtensions(DecodedCert* cert) } oid = 0; - if (GetObjectId(input, &idx, &oid, certExtType, sz) < 0) { + if (GetObjectId(input, &idx, &oid, oidCertExtType, sz) < 0) { WOLFSSL_MSG("\tfail: OBJECT ID"); return ASN_PARSE_E; } @@ -4970,7 +4970,7 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, void* cm) } if ((ret = GetAlgoId(cert->source, &cert->srcIdx, &confirmOID, - sigType, cert->maxIdx)) < 0) + oidSigType, cert->maxIdx)) < 0) return ret; if ((ret = GetSignature(cert)) < 0) @@ -5522,7 +5522,7 @@ static int SetRsaPublicKey(byte* output, RsaKey* key, #else byte algo[MAX_ALGO_SZ]; #endif - algoSz = SetAlgoID(RSAk, algo, keyType, 0); + algoSz = SetAlgoID(RSAk, algo, oidKeyType, 0); lenSz = SetLength(seqSz + nSz + eSz + 1, len); len[lenSz++] = 0; /* trailing 0 */ @@ -5938,7 +5938,7 @@ static int SetEccPublicKey(byte* output, ecc_key* key, int with_header) return MEMORY_E; } #endif - algoSz = SetAlgoID(ECDSAk, algo, keyType, curveSz); + algoSz = SetAlgoID(ECDSAk, algo, oidKeyType, curveSz); lenSz = SetLength(pubSz + 1, len); len[lenSz++] = 0; /* trailing 0 */ @@ -6787,7 +6787,7 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, der->serialSz = SetSerial(cert->serial, der->serial); /* signature algo */ - der->sigAlgoSz = SetAlgoID(cert->sigType, der->sigAlgo, sigType, 0); + der->sigAlgoSz = SetAlgoID(cert->sigType, der->sigAlgo, oidSigType, 0); if (der->sigAlgoSz == 0) return ALGO_ID_E; @@ -7179,7 +7179,7 @@ static int AddSignature(byte* buffer, int bodySz, const byte* sig, int sigSz, int idx = bodySz, seqSz; /* algo */ - idx += SetAlgoID(sigAlgoType, buffer + idx, sigType, 0); + idx += SetAlgoID(sigAlgoType, buffer + idx, oidSigType, 0); /* bit string */ buffer[idx++] = ASN_BIT_STRING; /* length */ @@ -7986,7 +7986,7 @@ static int SetAltNamesFromCert(Cert* cert, const byte* der, int derSz) decoded->srcIdx = startIdx; if (GetAlgoId(decoded->source, &decoded->srcIdx, &oid, - certExtType, decoded->maxIdx) < 0) { + oidCertExtType, decoded->maxIdx) < 0) { ret = ASN_PARSE_E; break; } @@ -8745,7 +8745,7 @@ static int DecodeSingleResponse(byte* source, if (GetSequence(source, &idx, &length, size) < 0) return ASN_PARSE_E; /* Skip the hash algorithm */ - if (GetAlgoId(source, &idx, &oid, ignoreType, size) < 0) + if (GetAlgoId(source, &idx, &oid, oidIgnoreType, size) < 0) return ASN_PARSE_E; /* Save reference to the hash of CN */ if (source[idx++] != ASN_OCTET_STRING) @@ -8867,7 +8867,7 @@ static int DecodeOcspRespExtensions(byte* source, } oid = 0; - if (GetObjectId(source, &idx, &oid, ocspType, sz) < 0) { + if (GetObjectId(source, &idx, &oid, oidOcspType, sz) < 0) { WOLFSSL_MSG("\tfail: OBJECT ID"); return ASN_PARSE_E; } @@ -9020,7 +9020,7 @@ static int DecodeBasicOcspResponse(byte* source, word32* ioIndex, return ASN_PARSE_E; /* Get the signature algorithm */ - if (GetAlgoId(source, &idx, &resp->sigOID, sigType, size) < 0) + if (GetAlgoId(source, &idx, &resp->sigOID, oidSigType, size) < 0) return ASN_PARSE_E; /* Obtain pointer to the start of the signature, and save the size */ @@ -9126,7 +9126,7 @@ int OcspResponseDecode(OcspResponse* resp, void* cm) return ASN_PARSE_E; /* Check ObjectID for the resposeBytes */ - if (GetObjectId(source, &idx, &oid, ocspType, size) < 0) + if (GetObjectId(source, &idx, &oid, oidOcspType, size) < 0) return ASN_PARSE_E; if (oid != OCSP_BASIC_OID) return ASN_PARSE_E; @@ -9212,9 +9212,9 @@ int EncodeOcspRequest(OcspRequest* req, byte* output, word32 size) WOLFSSL_ENTER("EncodeOcspRequest"); #ifdef NO_SHA - algoSz = SetAlgoID(SHA256h, algoArray, hashType, 0); + algoSz = SetAlgoID(SHA256h, algoArray, oidHashType, 0); #else - algoSz = SetAlgoID(SHAh, algoArray, hashType, 0); + algoSz = SetAlgoID(SHAh, algoArray, oidHashType, 0); #endif issuerSz = SetDigest(req->issuerHash, KEYID_SIZE, issuerArray); @@ -9604,7 +9604,7 @@ int ParseCRL(DecodedCRL* dcrl, const byte* buff, word32 sz, void* cm) return ASN_PARSE_E; } - if (GetAlgoId(buff, &idx, &oid, ignoreType, sz) < 0) + if (GetAlgoId(buff, &idx, &oid, oidIgnoreType, sz) < 0) return ASN_PARSE_E; if (GetNameHash(buff, &idx, dcrl->issuerHash, sz) < 0) @@ -9648,7 +9648,7 @@ int ParseCRL(DecodedCRL* dcrl, const byte* buff, word32 sz, void* cm) if (idx != dcrl->sigIndex) idx = dcrl->sigIndex; /* skip extensions */ - if (GetAlgoId(buff, &idx, &dcrl->signatureOID, sigType, sz) < 0) + if (GetAlgoId(buff, &idx, &dcrl->signatureOID, oidSigType, sz) < 0) return ASN_PARSE_E; if (GetCRL_Signature(buff, &idx, dcrl, sz) < 0) diff --git a/wolfcrypt/src/error.c b/wolfcrypt/src/error.c index f9c02690a..071ecf4b9 100644 --- a/wolfcrypt/src/error.c +++ b/wolfcrypt/src/error.c @@ -373,6 +373,9 @@ const char* wc_GetErrorString(int error) case HASH_TYPE_E: return "Hash type not enabled/available"; + case WC_PENDING_E: + return "wolfCrypt Operation Pending (would block / eagain) error"; + default: return "unknown error number"; diff --git a/wolfcrypt/src/hash.c b/wolfcrypt/src/hash.c index 5469580ee..1f00528a8 100644 --- a/wolfcrypt/src/hash.c +++ b/wolfcrypt/src/hash.c @@ -44,6 +44,7 @@ int wc_HashGetOID(enum wc_HashType hash_type) oid = MD2h; #endif break; + case WC_HASH_TYPE_MD5_SHA: case WC_HASH_TYPE_MD5: #ifndef NO_MD5 oid = MD5h; @@ -110,6 +111,11 @@ int wc_HashGetDigestSize(enum wc_HashType hash_type) case WC_HASH_TYPE_SHA512: #ifdef WOLFSSL_SHA512 dig_size = SHA512_DIGEST_SIZE; +#endif + break; + case WC_HASH_TYPE_MD5_SHA: +#if !defined(NO_MD5) && !defined(NO_SHA) + dig_size = MD5_DIGEST_SIZE + SHA_DIGEST_SIZE; #endif break; @@ -168,6 +174,14 @@ int wc_Hash(enum wc_HashType hash_type, const byte* data, case WC_HASH_TYPE_SHA512: #ifdef WOLFSSL_SHA512 ret = wc_Sha512Hash(data, data_len, hash); +#endif + break; + case WC_HASH_TYPE_MD5_SHA: +#if !defined(NO_MD5) && !defined(NO_SHA) + ret = wc_Md5Hash(data, data_len, hash); + if (ret == 0) { + ret = wc_ShaHash(data, data_len, &hash[MD5_DIGEST_SIZE]); + } #endif break; diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index 00c213416..dbc99261f 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -130,7 +130,7 @@ int wc_GetContentType(const byte* input, word32* inOutIdx, word32* oid, word32 maxIdx) { WOLFSSL_ENTER("wc_GetContentType"); - if (GetObjectId(input, inOutIdx, oid, ignoreType, maxIdx) < 0) + if (GetObjectId(input, inOutIdx, oid, oidIgnoreType, maxIdx) < 0) return ASN_PARSE_E; return 0; @@ -396,10 +396,10 @@ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) esd->signerVersionSz = SetMyVersion(1, esd->signerVersion, 0); signerInfoSz += esd->signerVersionSz; esd->signerDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->signerDigAlgoId, - hashType, 0); + oidHashType, 0); signerInfoSz += esd->signerDigAlgoIdSz; esd->digEncAlgoIdSz = SetAlgoID(pkcs7->encryptOID, esd->digEncAlgoId, - keyType, 0); + oidKeyType, 0); signerInfoSz += esd->digEncAlgoIdSz; if (pkcs7->signedAttribsSz != 0) { @@ -576,7 +576,7 @@ int wc_PKCS7_EncodeSignedData(PKCS7* pkcs7, byte* output, word32 outputSz) esd->certsSet); esd->singleDigAlgoIdSz = SetAlgoID(pkcs7->hashOID, esd->singleDigAlgoId, - hashType, 0); + oidHashType, 0); esd->digAlgoIdSetSz = SetSet(esd->singleDigAlgoIdSz, esd->digAlgoIdSet); @@ -1033,7 +1033,7 @@ WOLFSSL_LOCAL int wc_CreateRecipientInfo(const byte* cert, word32 certSz, return ALGO_ID_E; } - keyEncAlgSz = SetAlgoID(keyEncAlgo, keyAlgArray, keyType, 0); + keyEncAlgSz = SetAlgoID(keyEncAlgo, keyAlgArray, oidKeyType, 0); if (keyEncAlgSz == 0) { FreeDecodedCert(decoded); #ifdef WOLFSSL_SMALL_STACK @@ -1319,7 +1319,7 @@ int wc_PKCS7_EncodeEnvelopedData(PKCS7* pkcs7, byte* output, word32 outputSz) /* build up our ContentEncryptionAlgorithmIdentifier sequence, * adding (ivOctetStringSz + DES_BLOCK_SIZE) for IV OCTET STRING */ contentEncAlgoSz = SetAlgoID(pkcs7->encryptOID, contentEncAlgo, - blkType, ivOctetStringSz + DES_BLOCK_SIZE); + oidBlkType, ivOctetStringSz + DES_BLOCK_SIZE); if (contentEncAlgoSz == 0) { XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -1592,7 +1592,7 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, XFREE(serialNum, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif - if (GetAlgoId(pkiMsg, &idx, &encOID, keyType, pkiMsgSz) < 0) { + if (GetAlgoId(pkiMsg, &idx, &encOID, oidKeyType, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif @@ -1653,7 +1653,7 @@ WOLFSSL_API int wc_PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, return ASN_PARSE_E; } - if (GetAlgoId(pkiMsg, &idx, &encOID, blkType, pkiMsgSz) < 0) { + if (GetAlgoId(pkiMsg, &idx, &encOID, oidBlkType, pkiMsgSz) < 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(encryptedKey, NULL, DYNAMIC_TYPE_TMP_BUFFER); #endif diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 577103f73..593b45729 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -141,6 +141,7 @@ enum wolfSSL_ErrorCodes { UNKNOWN_ALPN_PROTOCOL_NAME_E = -405, /* Unrecognized protocol name Error*/ BAD_CERTIFICATE_STATUS_ERROR = -406, /* Bad certificate status message */ OCSP_INVALID_STATUS = -407, /* Invalid OCSP Status */ + ASYNC_NOT_PENDING = -408, /* Async operation not pending */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 1bdad174d..893169000 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -153,6 +153,10 @@ #include "zlib.h" #endif +#ifdef WOLFSSL_ASYNC_CRYPT + #include +#endif + #ifdef _MSC_VER /* 4996 warning to use MS extensions e.g., strcpy_s instead of strncpy */ #pragma warning(disable: 4996) @@ -1818,6 +1822,22 @@ WOLFSSL_LOCAL int TLSX_ValidateQSHScheme(TLSX** extensions, word16 name); #endif /* HAVE_QSH */ + +#ifdef HAVE_WOLF_EVENT +typedef struct { + WOLF_EVENT* head; /* head of queue */ + WOLF_EVENT* tail; /* tail of queue */ +#ifndef SINGLE_THREADED + wolfSSL_Mutex lock; /* queue lock */ +#endif +} WOLF_EVENT_QUEUE; + +WOLFSSL_LOCAL int wolfSSL_EventInit(WOLFSSL* ssl, WOLF_EVENT_TYPE type); + +WOLFSSL_LOCAL int wolfSSL_CTX_EventPush(WOLFSSL_CTX* ctx, WOLF_EVENT* event); +#endif /* HAVE_WOLF_EVENT */ + + /* wolfSSL context type */ struct WOLFSSL_CTX { WOLFSSL_METHOD* method; @@ -1924,6 +1944,9 @@ struct WOLFSSL_CTX { CallbackRsaDec RsaDecCb; /* User Rsa Private Decrypt handler */ #endif /* NO_RSA */ #endif /* HAVE_PK_CALLBACKS */ +#ifdef HAVE_WOLF_EVENT + WOLF_EVENT_QUEUE event_queue; +#endif /* HAVE_WOLF_EVENT */ }; @@ -2188,12 +2211,22 @@ enum AcceptState { ACCEPT_THIRD_REPLY_DONE }; +/* sub-states for send/do key share (key exchange) */ +enum KeyShareState { + KEYSHARE_BEGIN = 0, + KEYSHARE_BUILD, + KEYSHARE_VERIFY, + KEYSHARE_FINALIZE, + KEYSHARE_END +}; +/* buffers for struct WOLFSSL */ typedef struct Buffers { bufferStatic inputBuffer; bufferStatic outputBuffer; buffer domainName; /* for client check */ buffer clearOutputBuffer; + buffer sig; /* signature data */ int prevSent; /* previous plain text bytes sent when got WANT_WRITE */ int plainSz; /* plain text bytes in buffer to send @@ -2301,6 +2334,8 @@ typedef struct Options { byte minDowngrade; /* minimum downgrade version */ byte connectState; /* nonblocking resume */ byte acceptState; /* nonblocking resume */ + byte keyShareState; /* sub-state for key share (key exchange). + See enum KeyShareState. */ #ifndef NO_DH word16 minDhKeySz; /* minimum DH key size */ word16 dhKeySz; /* actual DH key size */ @@ -2535,6 +2570,12 @@ struct WOLFSSL { HandShakeDoneCb hsDoneCb; /* notify user handshake done */ void* hsDoneCtx; /* user handshake cb context */ #endif +#ifdef WOLFSSL_ASYNC_CRYPT + AsyncCrypt async; +#endif + void* sigKey; /* RsaKey or ecc_key allocated from heap */ + word32 sigType; /* Type of sigKey */ + word32 sigLen; /* Actual signature length */ WOLFSSL_CIPHER cipher; hmacfp hmac; Ciphers encrypt; @@ -2683,6 +2724,12 @@ struct WOLFSSL { #ifdef WOLFSSL_JNI void* jObjectRef; /* reference to WolfSSLSession in JNI wrapper */ #endif /* WOLFSSL_JNI */ +#ifdef HAVE_WOLF_EVENT + WOLF_EVENT event; +#endif /* HAVE_WOLF_EVENT */ +#ifdef WOLFSSL_ASYNC_CRYPT_TEST + AsyncCryptTests asyncCryptTest; +#endif /* WOLFSSL_ASYNC_CRYPT_TEST */ }; @@ -2834,10 +2881,29 @@ WOLFSSL_LOCAL void ShrinkOutputBuffer(WOLFSSL* ssl); WOLFSSL_LOCAL int VerifyClientSuite(WOLFSSL* ssl); #ifndef NO_CERTS #ifndef NO_RSA - WOLFSSL_LOCAL int VerifyRsaSign(const byte* sig, word32 sigSz, + WOLFSSL_LOCAL int VerifyRsaSign(WOLFSSL* ssl, + const byte* sig, word32 sigSz, const byte* plain, word32 plainSz, RsaKey* key); - #endif + WOLFSSL_LOCAL int RsaSign(WOLFSSL* ssl, const byte* in, word32 inSz, byte* out, + word32* outSz, RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx); + WOLFSSL_LOCAL int RsaVerify(WOLFSSL* ssl, byte* in, word32 inSz, + byte** out, RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx); + WOLFSSL_LOCAL int RsaDec(WOLFSSL* ssl, byte* in, word32 inSz, byte** out, + word32* outSz, RsaKey* key, const byte* keyBuf, word32 keySz, void* ctx); + #endif /* !NO_RSA */ + + #ifdef HAVE_ECC + WOLFSSL_LOCAL int EccSign(WOLFSSL* ssl, const byte* in, word32 inSz, + byte* out, word32* outSz, ecc_key* key, byte* keyBuf, word32 keySz, + void* ctx); + WOLFSSL_LOCAL int EccVerify(WOLFSSL* ssl, const byte* in, word32 inSz, + byte* out, word32 outSz, ecc_key* key, byte* keyBuf, word32 keySz, + void* ctx); + WOLFSSL_LOCAL int EccSharedSecret(WOLFSSL* ssl, ecc_key* priv_key, + ecc_key* pub_key, byte* out, word32* outSz); + #endif /* HAVE_ECC */ + #ifdef WOLFSSL_TRUST_PEER_CERT /* options for searching hash table for a matching trusted peer cert */ @@ -2849,11 +2915,12 @@ WOLFSSL_LOCAL int VerifyClientSuite(WOLFSSL* ssl); WOLFSSL_LOCAL int MatchTrustedPeer(TrustedPeerCert* tp, DecodedCert* cert); #endif + WOLFSSL_LOCAL Signer* GetCA(void* cm, byte* hash); #ifndef NO_SKID WOLFSSL_LOCAL Signer* GetCAByName(void* cm, byte* hash); #endif -#endif +#endif /* !NO_CERTS */ WOLFSSL_LOCAL int BuildTlsFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender); WOLFSSL_LOCAL void FreeArrays(WOLFSSL* ssl, int keep); @@ -2928,6 +2995,25 @@ enum encrypt_side { WOLFSSL_LOCAL int SetKeysSide(WOLFSSL*, enum encrypt_side); +#ifndef NO_DH + WOLFSSL_LOCAL int DhGenKeyPair(WOLFSSL* ssl, + byte* p, word32 pSz, + byte* g, word32 gSz, + byte* priv, word32* privSz, + byte* pub, word32* pubSz); + WOLFSSL_LOCAL int DhAgree(WOLFSSL* ssl, + byte* p, word32 pSz, + byte* g, word32 gSz, + byte* priv, word32* privSz, + byte* pub, word32* pubSz, + const byte* otherPub, word32 otherPubSz, + byte* agree, word32* agreeSz); +#endif + +#ifdef HAVE_ECC + WOLFSSL_LOCAL int EccMakeTempKey(WOLFSSL* ssl); +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index ea9ba0801..046176542 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1780,6 +1780,39 @@ WOLFSSL_API int wolfSSL_set_jobject(WOLFSSL* ssl, void* objPtr); WOLFSSL_API void* wolfSSL_get_jobject(WOLFSSL* ssl); #endif /* WOLFSSL_JNI */ +#ifdef HAVE_WOLF_EVENT +typedef enum WOLF_EVENT_TYPE { + WOLF_EVENT_TYPE_NONE, + #ifdef WOLFSSL_ASYNC_CRYPT + WOLF_EVENT_TYPE_ASYNC_ACCEPT, + WOLF_EVENT_TYPE_ASYNC_CONNECT, + WOLF_EVENT_TYPE_ASYNC_READ, + WOLF_EVENT_TYPE_ASYNC_WRITE, + WOLF_EVENT_TYPE_ASYNC_FIRST = WOLF_EVENT_TYPE_ASYNC_ACCEPT, + WOLF_EVENT_TYPE_ASYNC_LAST = WOLF_EVENT_TYPE_ASYNC_WRITE, + #endif +} WOLF_EVENT_TYPE; + +typedef struct WOLF_EVENT WOLF_EVENT; +struct WOLF_EVENT { + WOLF_EVENT* next; /* To support event linked list */ + WOLFSSL* ssl; /* Reference back to SSL object */ + int ret; /* Async return code */ + WOLF_EVENT_TYPE type; + unsigned short pending:1; + unsigned short done:1; + /* Future event flags can go here */ +}; + +enum WOLF_POLL_FLAGS { + WOLF_POLL_FLAG_CHECK_HW = 0x01, +}; + +WOLFSSL_API int wolfssl_CTX_poll_peek(WOLFSSL_CTX* ctx, int* eventCount); +WOLFSSL_API int wolfSSL_CTX_poll(WOLFSSL_CTX* ctx, WOLF_EVENT* events, int maxEvents, + unsigned char flags, int* eventCount); +#endif /* HAVE_WOLF_EVENT */ + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/test.h b/wolfssl/test.h index ba571237c..6d1ed6cd8 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -1907,4 +1907,24 @@ static INLINE const char* mymktemp(char *tempfn, int len, int num) #endif /* HAVE_SESSION_TICKET && CHACHA20 && POLY1305 */ +#ifdef WOLFSSL_ASYNC_CRYPT + static INLINE int AsyncCryptPoll(WOLFSSL_CTX* ctx, WOLFSSL* ssl) + { + int ret, eventCount = 0; + WOLF_EVENT events[1]; + + printf("Connect/Accept got WC_PENDING_E\n"); + + ret = wolfSSL_CTX_poll(ctx, events, sizeof(events)/sizeof(WOLF_EVENT), WOLF_POLL_FLAG_CHECK_HW, &eventCount); + if (ret == 0 && eventCount > 0) { + /* Check the SSL context in the event matches ours */ + if (events[0].ssl == ssl) { + ret = 1; /* Success */ + } + } + + return ret; + } +#endif + #endif /* wolfSSL_TEST_H */ diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index c7a4e340b..a1d311af8 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -199,19 +199,19 @@ enum Misc_ASN { enum Oid_Types { - hashType = 0, - sigType = 1, - keyType = 2, - curveType = 3, - blkType = 4, - ocspType = 5, - certExtType = 6, - certAuthInfoType = 7, - certPolicyType = 8, - certAltNameType = 9, - certKeyUseType = 10, - kdfType = 11, - ignoreType + oidHashType = 0, + oidSigType = 1, + oidKeyType = 2, + oidCurveType = 3, + oidBlkType = 4, + oidOcspType = 5, + oidCertExtType = 6, + oidCertAuthInfoType = 7, + oidCertPolicyType = 8, + oidCertAltNameType = 9, + oidCertKeyUseType = 10, + oidKdfType = 11, + oidIgnoreType }; diff --git a/wolfssl/wolfcrypt/error-crypt.h b/wolfssl/wolfcrypt/error-crypt.h index b7a3c89ac..ff153f495 100644 --- a/wolfssl/wolfcrypt/error-crypt.h +++ b/wolfssl/wolfcrypt/error-crypt.h @@ -166,6 +166,7 @@ enum { BAD_COND_E = -230, /* Bad condition variable operation */ SIG_TYPE_E = -231, /* Signature Type not enabled/available */ HASH_TYPE_E = -232, /* Hash Type not enabled/available */ + WC_PENDING_E = -233, /* wolfCrypt operation pending (would block) */ MIN_CODE_E = -300 /* errors -101 - -299 */ diff --git a/wolfssl/wolfcrypt/hash.h b/wolfssl/wolfcrypt/hash.h index 2c9acec3a..5a5d44259 100644 --- a/wolfssl/wolfcrypt/hash.h +++ b/wolfssl/wolfcrypt/hash.h @@ -38,6 +38,7 @@ enum wc_HashType { WC_HASH_TYPE_SHA256 = 5, WC_HASH_TYPE_SHA384 = 6, WC_HASH_TYPE_SHA512 = 7, + WC_HASH_TYPE_MD5_SHA = 8, }; /* Find largest possible digest size diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index a24579cb7..cf812145c 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -135,6 +135,9 @@ /* Uncomment next line if building for ARDUINO */ /* #define WOLFSSL_ARDUINO */ +/* Uncomment next line to enable asynchronous crypto WC_PENDING_E */ +/* #define WOLFSSL_ASYNC_CRYPT */ + #include #ifdef WOLFSSL_USER_SETTINGS @@ -1147,6 +1150,18 @@ static char *fgets(char *buff, int sz, FILE *fp) #undef NO_DH #endif +/* Asynchronous Crypto */ +#ifdef WOLFSSL_ASYNC_CRYPT + /* Make sure wolf events are enabled */ + #undef HAVE_WOLF_EVENT + #define HAVE_WOLF_EVENT +#else + #ifdef WOLFSSL_ASYNC_CRYPT_TEST + #error Must have WOLFSSL_ASYNC_CRYPT enabled with WOLFSSL_ASYNC_CRYPT_TEST + #endif +#endif /* WOLFSSL_ASYNC_CRYPT */ + + /* Place any other flags or defines here */