From ce231e0cbc12e80d5e9e2d08fd22597cd55475f8 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 8 Jun 2017 14:55:28 -0700 Subject: [PATCH 1/2] Fixes for asynchronous TLS 1.3. Fixes for PK_CALLBACKS with async. New helper API's for `wolfSSL_CTX_GetDevId` and `wolfSSL_CTX_GetHeap`. Fix for build to not include tls13.c if not enabled to suppress empty object file warning. Fix typo in fe_low_mem.c. General cleanup. Extra tls13.c debug messages. --- src/include.am | 7 +- src/internal.c | 85 +++-- src/ssl.c | 62 ++- src/tls.c | 4 +- src/tls13.c | 737 ++++++++++++++++++++++++------------ wolfcrypt/src/asn.c | 4 +- wolfcrypt/src/fe_low_mem.c | 2 +- wolfssl/internal.h | 27 +- wolfssl/ssl.h | 4 + wolfssl/test.h | 11 + wolfssl/wolfcrypt/ed25519.h | 7 + 11 files changed, 653 insertions(+), 297 deletions(-) diff --git a/src/include.am b/src/include.am index be2e6ac9b..22bb8edfe 100644 --- a/src/include.am +++ b/src/include.am @@ -266,8 +266,11 @@ src_libwolfssl_la_SOURCES += \ src/io.c \ src/keys.c \ src/ssl.c \ - src/tls.c \ - src/tls13.c + src/tls.c + +if BUILD_TLS13 +src_libwolfssl_la_SOURCES += src/tls13.c +endif if BUILD_OCSP src_libwolfssl_la_SOURCES += src/ocsp.c diff --git a/src/internal.c b/src/internal.c index a78a3a114..3bdf53e60 100755 --- a/src/internal.c +++ b/src/internal.c @@ -127,21 +127,6 @@ enum processReply { runProcessingOneMessage }; -/* sub-states for build message */ -enum buildMsgState { - BUILD_MSG_BEGIN = 0, - BUILD_MSG_SIZE, - BUILD_MSG_HASH, - BUILD_MSG_VERIFY_MAC, - BUILD_MSG_ENCRYPT, -}; - -/* sub-states for cipher operations */ -enum cipherState { - CIPHER_STATE_BEGIN = 0, - CIPHER_STATE_DO, - CIPHER_STATE_END, -}; /* Server random bytes for TLS v1.3 described downgrade protection mechanism. */ static const byte tls13Downgrade[7] = { @@ -2919,7 +2904,8 @@ static int TypeHash(int hashAlgo) } #if defined(WC_RSA_PSS) -static int ConvertHashPss(int hashAlgo, enum wc_HashType* hashType, int* mgf) { +int ConvertHashPss(int hashAlgo, enum wc_HashType* hashType, int* mgf) +{ switch (hashAlgo) { #ifdef WOLFSSL_SHA512 case sha512_mac: @@ -3105,10 +3091,11 @@ int VerifyRsaSign(WOLFSSL* ssl, byte* verifySig, word32 sigSz, return ret; ret = wc_RsaPSS_VerifyInline(verifySig, sigSz, &out, hashType, mgf, key); - if (ret > 0) + if (ret > 0) { ret = wc_RsaPSS_CheckPadding(plain, plainSz, out, ret, hashType); if (ret != 0) ret = VERIFY_CERT_ERROR; + } } else #endif @@ -3362,7 +3349,9 @@ int EccSharedSecret(WOLFSSL* ssl, ecc_key* priv_key, ecc_key* pub_key, int side, void* ctx) { int ret; - +#ifdef WOLFSSL_ASYNC_CRYPT + WC_ASYNC_DEV* asyncDev; +#endif (void)ssl; (void)pubKeyDer; (void)pubKeySz; @@ -3380,18 +3369,23 @@ int EccSharedSecret(WOLFSSL* ssl, ecc_key* priv_key, ecc_key* pub_key, ret = ssl->ctx->EccSharedSecretCb(ssl, otherKey, pubKeyDer, pubKeySz, out, outlen, side, ctx); } + #ifdef WOLFSSL_ASYNC_CRYPT + asyncDev = &otherKey->asyncDev; + #endif } else #endif { ret = wc_ecc_shared_secret(priv_key, pub_key, out, outlen); + #ifdef WOLFSSL_ASYNC_CRYPT + asyncDev = &priv_key->asyncDev; + #endif } /* Handle async pending response */ #if defined(WOLFSSL_ASYNC_CRYPT) if (ret == WC_PENDING_E) { - ret = wolfSSL_AsyncPush(ssl, &priv_key->asyncDev, - WC_ASYNC_FLAG_CALL_AGAIN); + ret = wolfSSL_AsyncPush(ssl, asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); } #endif /* WOLFSSL_ASYNC_CRYPT */ @@ -5558,6 +5552,9 @@ int HashOutputRaw(WOLFSSL* ssl, const byte* output, int sz) (void)output; (void)sz; + if (ssl->hsHashes == NULL) + return BAD_FUNC_ARG; + #ifdef HAVE_FUZZER if (ssl->fuzzerCb) ssl->fuzzerCb(ssl, output, sz, FUZZ_HASH, ssl->fuzzerCtx); @@ -9307,7 +9304,7 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, #ifdef WOLFSSL_ASYNC_CRYPT /* if async, offset index so this msg will be processed again */ - if (ret == WC_PENDING_E) { + if (ret == WC_PENDING_E && *inOutIdx > 0) { *inOutIdx -= HANDSHAKE_HEADER_SZ; #ifdef WOLFSSL_DTLS if (ssl->options.dtls) { @@ -9575,6 +9572,10 @@ static int DtlsMsgDrain(WOLFSSL* ssl) ssl->keys.dtls_expected_peer_handshake_number++; ret = DoHandShakeMsgType(ssl, item->msg, &idx, item->type, item->sz, item->sz); + if (ret == WC_PENDING_E) { + ssl->keys.dtls_expected_peer_handshake_number--; + break; + } ssl->dtls_rx_msg_list = item->next; DtlsMsgDelete(item, ssl->heap); item = ssl->dtls_rx_msg_list; @@ -9594,10 +9595,24 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, int ret = 0; WOLFSSL_ENTER("DoDtlsHandShakeMsg()"); + + /* process any pending DTLS messages - this flow can happen with async */ + if (ssl->dtls_rx_msg_list != NULL) { + ret = DtlsMsgDrain(ssl); + if (ret != 0) + return ret; + + /* if done processing fragment exit with success */ + if (totalSz == *inOutIdx) + return ret; + } + + /* parse header */ if (GetDtlsHandShakeHeader(ssl, input, inOutIdx, &type, &size, &fragOffset, &fragSz, totalSz) != 0) return PARSE_ERROR; + /* check that we have complete fragment */ if (*inOutIdx + fragSz > totalSz) return INCOMPLETE_DATA; @@ -10209,7 +10224,7 @@ static INLINE int Encrypt(WOLFSSL* ssl, byte* out, const byte* input, word16 sz, int ret = 0; #ifdef WOLFSSL_ASYNC_CRYPT - if (asyncOkay && ssl->error == WC_PENDING_E) { + if (ssl->error == WC_PENDING_E) { ssl->error = 0; /* clear async */ } #endif @@ -11956,12 +11971,12 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, int inSz, int type, int hashOutput, int sizeOnly, int asyncOkay) { int ret = 0; + BuildMsgArgs* args; + BuildMsgArgs lcl_args; #ifdef WOLFSSL_ASYNC_CRYPT - BuildMsgArgs* args = (BuildMsgArgs*)ssl->async.args; + args = (BuildMsgArgs*)ssl->async.args; typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; (void)sizeof(args_test); -#else - BuildMsgArgs args[1]; #endif WOLFSSL_ENTER("BuildMessage"); @@ -11973,7 +11988,7 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, #ifdef WOLFSSL_TLS13 if (ssl->options.tls1_3) { return BuildTls13Message(ssl, output, outSz, input, inSz, type, - hashOutput, sizeOnly); + hashOutput, sizeOnly, asyncOkay); } #endif @@ -11987,7 +12002,11 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, goto exit_buildmsg; } } + else #endif + { + args = &lcl_args; + } /* Reset state */ if (ret == WC_NOT_PENDING_E) { @@ -13189,7 +13208,7 @@ int SendData(WOLFSSL* ssl, const void* data, int sz) else { #ifdef WOLFSSL_TLS13 sendSz = BuildTls13Message(ssl, out, outputSz, sendBuffer, buffSz, - application_data, 0, 0); + application_data, 0, 0, 1); #else sendSz = BUFFER_ERROR; #endif @@ -17921,7 +17940,7 @@ int SendClientKeyExchange(WOLFSSL* ssl) { ecc_key* peerKey; - #ifdef HAVE_PK_CALLBACKS + #ifdef HAVE_PK_CALLBACKS /* if callback then use it for shared secret */ #ifdef HAVE_CURVE25519 if (ssl->ecdhCurveOID == ECC_X25519_OID) { @@ -17933,7 +17952,7 @@ int SendClientKeyExchange(WOLFSSL* ssl) if (ssl->ctx->EccSharedSecretCb != NULL) { break; } - #endif + #endif /* HAVE_PK_CALLBACKS */ #ifdef HAVE_CURVE25519 if (ssl->peerX25519KeyPresent) { @@ -18261,7 +18280,7 @@ int SendClientKeyExchange(WOLFSSL* ssl) break; } #endif - #ifdef HAVE_PK_CALLBACKS + #ifdef HAVE_PK_CALLBACKS /* if callback then use it for shared secret */ if (ssl->ctx->EccSharedSecretCb != NULL) { break; @@ -18679,11 +18698,7 @@ int SendClientKeyExchange(WOLFSSL* ssl) { if (IsEncryptionOn(ssl, 1)) { ret = BuildMessage(ssl, args->output, args->sendSz, - args->input, args->inputSz, handshake, 1, 0, 1); - #ifdef WOLFSSL_ASYNC_CRYPT - if (ret == WC_PENDING_E) - goto exit_scke; - #endif + args->input, args->inputSz, handshake, 1, 0, 0); XFREE(args->input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); args->input = NULL; /* make sure its not double free'd on cleanup */ diff --git a/src/ssl.c b/src/ssl.c index a589d2a32..a67836d15 100755 --- a/src/ssl.c +++ b/src/ssl.c @@ -1439,6 +1439,27 @@ int wolfSSL_CTX_UseAsync(WOLFSSL_CTX* ctx, int devId) #endif /* WOLFSSL_ASYNC_CRYPT */ +/* helpers to get device id and heap */ +int wolfSSL_CTX_GetDevId(WOLFSSL_CTX* ctx, WOLFSSL* ssl) +{ + int devId = INVALID_DEVID; + if (ctx != NULL) + devId = ctx->devId; + else if (ssl != NULL) + devId = ssl->devId; + return devId; +} +void* wolfSSL_CTX_GetHeap(WOLFSSL_CTX* ctx, WOLFSSL* ssl) +{ + void* heap = NULL; + if (ctx != NULL) + heap = ctx->heap; + else if (ssl != NULL) + heap = ssl->heap; + return heap; +} + + #ifdef HAVE_SNI int wolfSSL_UseSNI(WOLFSSL* ssl, byte type, const void* data, word16 size) @@ -4260,7 +4281,7 @@ static int ProcessUserChain(WOLFSSL_CTX* ctx, const unsigned char* buff, long* used, EncryptedInfo* info) { int ret = 0; - void* heap = ctx ? ctx->heap : ((ssl) ? ssl->heap : NULL); + void* heap = wolfSSL_CTX_GetHeap(ctx, ssl); #ifdef WOLFSSL_TLS13 int cnt = 0; #endif @@ -4401,8 +4422,8 @@ int ProcessBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, int ed25519Key = 0; int rsaKey = 0; int resetSuites = 0; - void* heap = ctx ? ctx->heap : ((ssl) ? ssl->heap : NULL); - int devId = ctx ? ctx->devId : ((ssl) ? ssl->devId : INVALID_DEVID); + void* heap = wolfSSL_CTX_GetHeap(ctx, ssl); + int devId = wolfSSL_CTX_GetDevId(ctx, ssl); #ifdef WOLFSSL_SMALL_STACK EncryptedInfo* info = NULL; #else @@ -4965,7 +4986,7 @@ static int ProcessChainBuffer(WOLFSSL_CTX* ctx, const unsigned char* buff, NULL) == 0) { WOLFSSL_MSG(" Proccessed a CRL"); wolfSSL_CertManagerLoadCRLBuffer(ctx->cm, der->buffer, - der->length,SSL_FILETYPE_ASN1); + der->length, SSL_FILETYPE_ASN1); FreeDer(&der); used += info.consumed; continue; @@ -5525,7 +5546,7 @@ int ProcessFile(WOLFSSL_CTX* ctx, const char* fname, int format, int type, int ret; long sz = 0; XFILE file; - void* heapHint = ctx ? ctx->heap : ((ssl) ? ssl->heap : NULL); + void* heapHint = wolfSSL_CTX_GetHeap(ctx, ssl); (void)crl; (void)heapHint; @@ -8199,6 +8220,11 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, return SSL_FATAL_ERROR; } + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); + #endif + #ifdef WOLFSSL_DTLS if (ssl->version.major == DTLS_MAJOR) { ssl->options.dtls = 1; @@ -8274,10 +8300,10 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, if (ssl->options.certOnly) return SSL_SUCCESS; -#ifdef WOLFSSL_TLS13 + #ifdef WOLFSSL_TLS13 if (ssl->options.tls1_3) return wolfSSL_connect_TLSv13(ssl); -#endif + #endif #ifdef WOLFSSL_DTLS if (IsDtlsNotSctpMode(ssl)) { @@ -8322,6 +8348,10 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, FALL_THROUGH; case FIRST_REPLY_DONE : + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); + #endif #ifndef NO_CERTS if (ssl->options.sendVerify) { if ( (ssl->error = SendCertificate(ssl)) != 0) { @@ -8337,6 +8367,10 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, FALL_THROUGH; case FIRST_REPLY_FIRST : + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) + return wolfSSL_connect_TLSv13(ssl); + #endif if (!ssl->options.resuming) { if ( (ssl->error = SendClientKeyExchange(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); @@ -8620,11 +8654,11 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, FALL_THROUGH; case ACCEPT_FIRST_REPLY_DONE : -#ifdef WOLFSSL_TLS13 + #ifdef WOLFSSL_TLS13 if (ssl->options.tls1_3) { return wolfSSL_accept_TLSv13(ssl); } -#endif + #endif if ( (ssl->error = SendServerHello(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); return SSL_FATAL_ERROR; @@ -8634,6 +8668,11 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, FALL_THROUGH; case SERVER_HELLO_SENT : + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + return wolfSSL_accept_TLSv13(ssl); + } + #endif #ifndef NO_CERTS if (!ssl->options.resuming) if ( (ssl->error = SendCertificate(ssl)) != 0) { @@ -8658,6 +8697,11 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl, FALL_THROUGH; case CERT_STATUS_SENT : + #ifdef WOLFSSL_TLS13 + if (ssl->options.tls1_3) { + return wolfSSL_accept_TLSv13(ssl); + } + #endif if (!ssl->options.resuming) if ( (ssl->error = SendServerKeyExchange(ssl)) != 0) { WOLFSSL_ERROR(ssl->error); diff --git a/src/tls.c b/src/tls.c index a06f0fb5d..0fb7f249b 100755 --- a/src/tls.c +++ b/src/tls.c @@ -4775,7 +4775,7 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse) kse->key = key; #ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("Public ECC Key"); + WOLFSSL_MSG("Public Curve25519 Key"); WOLFSSL_BUFFER(keyData, dataSize); #endif @@ -5130,7 +5130,7 @@ static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) if (ret != 0) return ret; #ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("Peer ECC Key"); + WOLFSSL_MSG("Peer Curve25519 Key"); WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen); #endif diff --git a/src/tls13.c b/src/tls13.c index f8cf9d2bb..6bbd1d05f 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -1292,6 +1292,10 @@ static int HashInputRaw(WOLFSSL* ssl, const byte* input, int sz) { int ret = BAD_FUNC_ARG; + if (ssl->hsHashes == NULL) { + return BAD_FUNC_ARG; + } + #ifndef NO_OLD_TLS #ifndef NO_SHA ret = wc_ShaUpdate(&ssl->hsHashes->hashSha, input, sz); @@ -1593,73 +1597,135 @@ static int ChaCha20Poly1305_Encrypt(WOLFSSL* ssl, byte* output, * returns 0 on success, otherwise failure. */ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, - word16 sz) + word16 sz, int asyncOkay) { int ret = 0; word16 dataSz = sz - ssl->specs.aead_mac_size; word16 macSz = ssl->specs.aead_mac_size; - byte nonce[AEAD_NONCE_SZ]; + word32 nonceSz = 0; +#ifdef WOLFSSL_ASYNC_CRYPT + WC_ASYNC_DEV* asyncDev = NULL; + word32 event_flags = WC_ASYNC_FLAG_CALL_AGAIN; +#endif + + WOLFSSL_ENTER("EncryptTls13"); (void)output; (void)input; (void)sz; (void)dataSz; (void)macSz; + (void)asyncOkay; + (void)nonceSz; -#ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("Data to encrypt"); - WOLFSSL_BUFFER(input, dataSz); +#ifdef WOLFSSL_ASYNC_CRYPT + if (ssl->error == WC_PENDING_E) { + ssl->error = 0; /* clear async */ + } #endif - BuildTls13Nonce(ssl, nonce, ssl->keys.aead_enc_imp_IV, CUR_ORDER); - - switch (ssl->specs.bulk_cipher_algorithm) { - #ifdef BUILD_AESGCM - case wolfssl_aes_gcm: -#ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("Nonce"); - WOLFSSL_BUFFER(nonce, AESGCM_NONCE_SZ); -#endif - ret = wc_AesGcmEncrypt(ssl->encrypt.aes, output, input, dataSz, - nonce, AESGCM_NONCE_SZ, output + dataSz, macSz, NULL, 0); - break; + switch (ssl->encrypt.state) { + case CIPHER_STATE_BEGIN: + { + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Data to encrypt"); + WOLFSSL_BUFFER(input, dataSz); #endif - #ifdef HAVE_AESCCM - case wolfssl_aes_ccm: -#ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("Nonce"); - WOLFSSL_BUFFER(nonce, AESCCM_NONCE_SZ); -#endif - ret = wc_AesCcmEncrypt(ssl->encrypt.aes, output, input, dataSz, - nonce, AESCCM_NONCE_SZ, output + dataSz, macSz, NULL, 0); - break; - #endif + if (ssl->encrypt.nonce == NULL) + ssl->encrypt.nonce = (byte*)XMALLOC(AEAD_NONCE_SZ, + ssl->heap, DYNAMIC_TYPE_AES); + if (ssl->encrypt.nonce == NULL) + return MEMORY_E; - #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) - case wolfssl_chacha: -#ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("Nonce"); - WOLFSSL_BUFFER(nonce, CHACHA_IV_BYTES); -#endif - ret = ChaCha20Poly1305_Encrypt(ssl, output, input, dataSz, nonce, - output + dataSz); - break; - #endif + BuildTls13Nonce(ssl, ssl->encrypt.nonce, ssl->keys.aead_enc_imp_IV, + CUR_ORDER); - default: - WOLFSSL_MSG("wolfSSL Encrypt programming error"); - return ENCRYPT_ERROR; + /* Advance state and proceed */ + ssl->encrypt.state = CIPHER_STATE_DO; + } + FALL_THROUGH; + + case CIPHER_STATE_DO: + { + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_AESGCM + case wolfssl_aes_gcm: + nonceSz = AESGCM_NONCE_SZ; + ret = wc_AesGcmEncrypt(ssl->encrypt.aes, output, input, + dataSz, ssl->encrypt.nonce, nonceSz, + output + dataSz, macSz, NULL, 0); + #ifdef WOLFSSL_ASYNC_CRYPT + asyncDev = &ssl->encrypt.aes->asyncDev; + #endif + break; + #endif + + #ifdef HAVE_AESCCM + case wolfssl_aes_ccm: + nonceSz = AESCCM_NONCE_SZ; + ret = wc_AesCcmEncrypt(ssl->encrypt.aes, output, input, + dataSz, ssl->encrypt.nonce, nonceSz, + output + dataSz, macSz, NULL, 0); + #ifdef WOLFSSL_ASYNC_CRYPT + asyncDev = &ssl->encrypt.aes->asyncDev; + #endif + break; + #endif + + #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + case wolfssl_chacha: + nonceSz = CHACHA_IV_BYTES; + ret = ChaCha20Poly1305_Encrypt(ssl, output, input, dataSz, + ssl->encrypt.nonce, output + dataSz); + break; + #endif + + default: + WOLFSSL_MSG("wolfSSL Encrypt programming error"); + return ENCRYPT_ERROR; + } + + /* Advance state */ + ssl->encrypt.state = CIPHER_STATE_END; + + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + /* if async is not okay, then block */ + if (!asyncOkay) { + ret = wc_AsyncWait(ret, asyncDev, event_flags); + } + else { + /* If pending, then leave and return will resume below */ + ret = wolfSSL_AsyncPush(ssl, asyncDev, event_flags); + + return ret; + } + } + #endif + } + FALL_THROUGH; + + case CIPHER_STATE_END: + { + if (ssl->encrypt.nonce) + ForceZero(ssl->encrypt.nonce, AEAD_NONCE_SZ); + + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Nonce"); + WOLFSSL_BUFFER(ssl->encrypt.nonce, ssl->specs.iv_size); + WOLFSSL_MSG("Encrypted data"); + WOLFSSL_BUFFER(output, dataSz); + WOLFSSL_MSG("Authentication Tag"); + WOLFSSL_BUFFER(output + dataSz, macSz); + #endif + + break; + } } - ForceZero(nonce, AEAD_NONCE_SZ); - -#ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("Encrypted data"); - WOLFSSL_BUFFER(output, dataSz); - WOLFSSL_MSG("Authentication Tag"); - WOLFSSL_BUFFER(output + dataSz, macSz); -#endif + /* Reset state */ + ssl->encrypt.state = CIPHER_STATE_BEGIN; return ret; } @@ -1732,76 +1798,160 @@ int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, word16 sz) int ret = 0; word16 dataSz = sz - ssl->specs.aead_mac_size; word16 macSz = ssl->specs.aead_mac_size; - byte nonce[AEAD_NONCE_SZ]; + word32 nonceSz = 0; + + WOLFSSL_ENTER("DecryptTls13"); + +#ifdef WOLFSSL_ASYNC_CRYPT + ret = wolfSSL_AsyncPop(ssl, &ssl->decrypt.state); + if (ret != WC_NOT_PENDING_E) { + /* check for still pending */ + if (ret == WC_PENDING_E) + return ret; + + ssl->error = 0; /* clear async */ + + /* let failures through so CIPHER_STATE_END logic is run */ + } + else +#endif + { + /* Reset state */ + ret = 0; + ssl->decrypt.state = CIPHER_STATE_BEGIN; + } (void)output; (void)input; (void)sz; (void)dataSz; (void)macSz; + (void)nonceSz; -#ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("Data to decrypt"); - WOLFSSL_BUFFER(input, dataSz); - WOLFSSL_MSG("Authentication tag"); - WOLFSSL_BUFFER(input + dataSz, macSz); -#endif - - BuildTls13Nonce(ssl, nonce, ssl->keys.aead_dec_imp_IV, PEER_ORDER); - - switch (ssl->specs.bulk_cipher_algorithm) { - #ifdef BUILD_AESGCM - case wolfssl_aes_gcm: -#ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("Nonce"); - WOLFSSL_BUFFER(nonce, AESGCM_NONCE_SZ); -#endif - ret = wc_AesGcmDecrypt(ssl->decrypt.aes, output, input, dataSz, - nonce, AESGCM_NONCE_SZ, input + dataSz, macSz, NULL, 0); - break; + switch (ssl->decrypt.state) { + case CIPHER_STATE_BEGIN: + { + #ifdef WOLFSSL_DEBUG_TLS + WOLFSSL_MSG("Data to decrypt"); + WOLFSSL_BUFFER(input, dataSz); + WOLFSSL_MSG("Authentication tag"); + WOLFSSL_BUFFER(input + dataSz, macSz); #endif - #ifdef HAVE_AESCCM - case wolfssl_aes_ccm: -#ifdef WOLFSSL_DEBUG_TLS + if (ssl->decrypt.nonce == NULL) + ssl->decrypt.nonce = (byte*)XMALLOC(AEAD_NONCE_SZ, + ssl->heap, DYNAMIC_TYPE_AES); + if (ssl->decrypt.nonce == NULL) + return MEMORY_E; + + BuildTls13Nonce(ssl, ssl->decrypt.nonce, ssl->keys.aead_dec_imp_IV, + PEER_ORDER); + + /* Advance state and proceed */ + ssl->decrypt.state = CIPHER_STATE_DO; + } + FALL_THROUGH; + + case CIPHER_STATE_DO: + { + switch (ssl->specs.bulk_cipher_algorithm) { + #ifdef BUILD_AESGCM + case wolfssl_aes_gcm: + nonceSz = AESGCM_NONCE_SZ; + ret = wc_AesGcmDecrypt(ssl->decrypt.aes, output, input, + dataSz, ssl->decrypt.nonce, nonceSz, + input + dataSz, macSz, NULL, 0); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &ssl->decrypt.aes->asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + } + #endif + break; + #endif + + #ifdef HAVE_AESCCM + case wolfssl_aes_ccm: + nonceSz = AESCCM_NONCE_SZ; + ret = wc_AesCcmDecrypt(ssl->decrypt.aes, output, input, + dataSz, ssl->decrypt.nonce, nonceSz, + input + dataSz, macSz, NULL, 0); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wolfSSL_AsyncPush(ssl, &ssl->decrypt.aes->asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + } + #endif + break; + #endif + + #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) + case wolfssl_chacha: + nonceSz = CHACHA_IV_BYTES; + ret = ChaCha20Poly1305_Decrypt(ssl, output, input, dataSz, + ssl->decrypt.nonce, input + dataSz); + break; + #endif + + default: + WOLFSSL_MSG("wolfSSL Decrypt programming error"); + return DECRYPT_ERROR; + } + + /* Advance state */ + ssl->decrypt.state = CIPHER_STATE_END; + + #ifdef WOLFSSL_ASYNC_CRYPT + /* If pending, leave now */ + if (ret == WC_PENDING_E) { + return ret; + } + #endif + } + FALL_THROUGH; + + case CIPHER_STATE_END: + { + if (ssl->decrypt.nonce) + ForceZero(ssl->decrypt.nonce, AEAD_NONCE_SZ); + + #ifdef WOLFSSL_DEBUG_TLS WOLFSSL_MSG("Nonce"); - WOLFSSL_BUFFER(nonce, AESCCM_NONCE_SZ); -#endif - ret = wc_AesCcmDecrypt(ssl->decrypt.aes, output, input, dataSz, - nonce, AESCCM_NONCE_SZ, input + dataSz, macSz, NULL, 0); - break; + WOLFSSL_BUFFER(ssl->decrypt.nonce, ssl->specs.iv_size); + WOLFSSL_MSG("Decrypted data"); + WOLFSSL_BUFFER(output, dataSz); #endif - #if defined(HAVE_CHACHA) && defined(HAVE_POLY1305) - case wolfssl_chacha: -#ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("Nonce"); - WOLFSSL_BUFFER(nonce, CHACHA_IV_BYTES); -#endif - ret = ChaCha20Poly1305_Decrypt(ssl, output, input, dataSz, nonce, - input + dataSz); break; - #endif - - default: - WOLFSSL_MSG("wolfSSL Decrypt programming error"); - return DECRYPT_ERROR; + } } - ForceZero(nonce, AEAD_NONCE_SZ); if (ret < 0 && !ssl->options.dtls) { SendAlert(ssl, alert_fatal, bad_record_mac); ret = VERIFY_MAC_ERROR; } -#ifdef WOLFSSL_DEBUG_TLS - WOLFSSL_MSG("Decrypted data"); - WOLFSSL_BUFFER(output, dataSz); -#endif - return ret; } +/* Persistable BuildMessage arguments */ +typedef struct BuildMsg13Args { + word32 sz; + word32 idx; + word32 headerSz; + word16 size; +} BuildMsg13Args; + +static void FreeBuildMsg13Args(WOLFSSL* ssl, void* pArgs) +{ + BuildMsg13Args* args = (BuildMsg13Args*)pArgs; + + (void)ssl; + (void)args; + + /* no allocations in BuildTls13Message */ +} + /* Build SSL Message, encrypted. * TLS v1.3 encryption is AEAD only. * @@ -1816,83 +1966,151 @@ int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, word16 sz) * returns the size of the encrypted record message or negative value on error. */ int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, - int inSz, int type, int hashOutput, int sizeOnly) + int inSz, int type, int hashOutput, int sizeOnly, int asyncOkay) { - word32 sz = RECORD_HEADER_SZ + inSz; - word32 idx = RECORD_HEADER_SZ; - word32 headerSz = RECORD_HEADER_SZ; - word16 size; - int ret = 0; - int atomicUser = 0; - - if (ssl == NULL) - return BAD_FUNC_ARG; - if (!sizeOnly && (output == NULL || input == NULL)) - return BAD_FUNC_ARG; - /* catch mistaken sizeOnly parameter */ - if (sizeOnly && (output || input)) { - WOLFSSL_MSG("BuildMessage with sizeOnly doesn't need input or output"); - return BAD_FUNC_ARG; - } - - /* Record layer content type at the end of record data. */ - sz++; - /* Authentication data at the end. */ - sz += ssl->specs.aead_mac_size; - - if (sizeOnly) - return sz; - - if (sz > (word32)outSz) { - WOLFSSL_MSG("Oops, want to write past output buffer size"); - return BUFFER_E; - } - - /* Record data length. */ - size = (word16)(sz - headerSz); - /* Write/update the record header with the new size. - * Always have the content type as application data for encrypted - * messages in TLS v1.3. - */ - AddTls13RecordHeader(output, size, application_data, ssl); - - /* TLS v1.3 can do in place encryption. */ - if (input != output + idx) - XMEMCPY(output + idx, input, inSz); - idx += inSz; - - if (hashOutput) { - ret = HashOutput(ssl, output, headerSz + inSz, 0); - if (ret != 0) - return ret; - } - - /* The real record content type goes at the end of the data. */ - output[idx++] = type; - -#ifdef ATOMIC_USER - if (ssl->ctx->MacEncryptCb) - atomicUser = 1; + int ret = 0; + BuildMsg13Args* args; + BuildMsg13Args lcl_args; +#ifdef WOLFSSL_ASYNC_CRYPT + args = (BuildMsg13Args*)ssl->async.args; + typedef char args_test[sizeof(ssl->async.args) >= sizeof(*args) ? 1 : -1]; + (void)sizeof(args_test); #endif - if (atomicUser) { /* User Record Layer Callback handling */ -#ifdef ATOMIC_USER - byte* mac = output + idx; - output += headerSz; + WOLFSSL_ENTER("BuildTls13Message"); - if ((ret = ssl->ctx->MacEncryptCb(ssl, mac, output, inSz, type, 0, - output, output, size, ssl->MacEncryptCtx)) != 0) { - return ret; + if (ssl == NULL) { + return BAD_FUNC_ARG; + } + + ret = WC_NOT_PENDING_E; +#ifdef WOLFSSL_ASYNC_CRYPT + if (asyncOkay) { + ret = wolfSSL_AsyncPop(ssl, &ssl->options.buildMsgState); + if (ret != WC_NOT_PENDING_E) { + /* Check for error */ + if (ret < 0) + goto exit_buildmsg; } -#endif } - else { - output += headerSz; - if ((ret = EncryptTls13(ssl, output, output, size)) != 0) - return ret; + else +#endif + { + args = &lcl_args; } - return sz; + /* Reset state */ + if (ret == WC_NOT_PENDING_E) { + ret = 0; + ssl->options.buildMsgState = BUILD_MSG_BEGIN; + XMEMSET(args, 0, sizeof(BuildMsg13Args)); + + args->sz = RECORD_HEADER_SZ + inSz; + args->idx = RECORD_HEADER_SZ; + args->headerSz = RECORD_HEADER_SZ; + #ifdef WOLFSSL_ASYNC_CRYPT + ssl->async.freeArgs = FreeBuildMsg13Args; + #endif + } + + switch (ssl->options.buildMsgState) { + case BUILD_MSG_BEGIN: + { + if (!sizeOnly && (output == NULL || input == NULL)) + return BAD_FUNC_ARG; + /* catch mistaken sizeOnly parameter */ + if (sizeOnly && (output || input)) { + WOLFSSL_MSG("BuildMessage with sizeOnly doesn't need input or output"); + return BAD_FUNC_ARG; + } + + /* Record layer content type at the end of record data. */ + args->sz++; + /* Authentication data at the end. */ + args->sz += ssl->specs.aead_mac_size; + + if (sizeOnly) + return args->sz; + + if (args->sz > (word32)outSz) { + WOLFSSL_MSG("Oops, want to write past output buffer size"); + return BUFFER_E; + } + + /* Record data length. */ + args->size = (word16)(args->sz - args->headerSz); + /* Write/update the record header with the new size. + * Always have the content type as application data for encrypted + * messages in TLS v1.3. + */ + AddTls13RecordHeader(output, args->size, application_data, ssl); + + /* TLS v1.3 can do in place encryption. */ + if (input != output + args->idx) + XMEMCPY(output + args->idx, input, inSz); + args->idx += inSz; + + ssl->options.buildMsgState = BUILD_MSG_HASH; + } + FALL_THROUGH; + + case BUILD_MSG_HASH: + { + if (hashOutput) { + ret = HashOutput(ssl, output, args->headerSz + inSz, 0); + if (ret != 0) + goto exit_buildmsg; + } + + ssl->options.buildMsgState = BUILD_MSG_ENCRYPT; + } + FALL_THROUGH; + + case BUILD_MSG_ENCRYPT: + { + /* The real record content type goes at the end of the data. */ + output[args->idx++] = type; + + #ifdef ATOMIC_USER + if (ssl->ctx->MacEncryptCb) { + /* User Record Layer Callback handling */ + byte* mac = output + args->idx; + output += args->headerSz; + + ret = ssl->ctx->MacEncryptCb(ssl, mac, output, inSz, type, 0, + output, output, args->size, ssl->MacEncryptCtx); + } + else + #endif + { + output += args->headerSz; + ret = EncryptTls13(ssl, output, output, args->size, asyncOkay); + } + break; + } + } + +exit_buildmsg: + + WOLFSSL_LEAVE("BuildTls13Message", ret); + +#ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + return ret; + } +#endif + + /* make sure build message state is reset */ + ssl->options.buildMsgState = BUILD_MSG_BEGIN; + + /* return sz on success */ + if (ret == 0) + ret = args->sz; + + /* Final cleanup */ + FreeBuildMsg13Args(ssl, args); + + return ret; } #ifndef NO_WOLFSSL_CLIENT @@ -2043,6 +2261,8 @@ int SendTls13ClientHello(WOLFSSL* ssl) int sendSz; int ret; + WOLFSSL_ENTER("SendTls13ClientHello"); + #if defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) if (ssl->options.resuming && (ssl->session.version.major != ssl->version.major || @@ -2166,6 +2386,8 @@ static int DoTls13HelloRetryRequest(WOLFSSL* ssl, const byte* input, word16 totalExtSz; ProtocolVersion pv; + WOLFSSL_ENTER("DoTls13HelloRetryRequest"); + #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("HelloRetryRequest", &ssl->handShakeInfo); if (ssl->toInfoOn) AddLateName("HelloRetryRequest", &ssl->timeoutInfo); @@ -2234,6 +2456,8 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, int ret; word16 totalExtSz; + WOLFSSL_ENTER("DoTls13ServerHello"); + #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo); if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo); @@ -2337,6 +2561,8 @@ static int DoTls13EncryptedExtensions(WOLFSSL* ssl, const byte* input, word32 i = begin; word16 totalExtSz; + WOLFSSL_ENTER("DoTls13EncryptedExtensions"); + #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("EncryptedExtensions", &ssl->handShakeInfo); @@ -2362,7 +2588,7 @@ static int DoTls13EncryptedExtensions(WOLFSSL* ssl, const byte* input, /* Always encrypted. */ *inOutIdx += ssl->keys.padSz; - return 0; + return ret; } /* Handle a TLS v1.3 CertificateRequest message. @@ -2384,11 +2610,12 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, int ret; Suites peerSuites; - #ifdef WOLFSSL_CALLBACKS - if (ssl->hsInfoOn) AddPacketName("CertificateRequest", - &ssl->handShakeInfo); - if (ssl->toInfoOn) AddLateName("CertificateRequest", &ssl->timeoutInfo); - #endif + WOLFSSL_ENTER("DoTls13CertificateRequest"); + +#ifdef WOLFSSL_CALLBACKS + if (ssl->hsInfoOn) AddPacketName("CertificateRequest", &ssl->handShakeInfo); + if (ssl->toInfoOn) AddLateName("CertificateRequest", &ssl->timeoutInfo); +#endif if ((*inOutIdx - begin) + OPAQUE8_LEN > size) return BUFFER_ERROR; @@ -2427,7 +2654,7 @@ static int DoTls13CertificateRequest(WOLFSSL* ssl, const byte* input, /* This message is always encrypted so add encryption padding. */ *inOutIdx += ssl->keys.padSz; - return 0; + return ret; } #endif /* !NO_WOLFSSL_CLIENT */ @@ -2646,6 +2873,8 @@ static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word16 totalExtSz; int usingPSK = 0; + WOLFSSL_ENTER("DoTls13ClientHello"); + #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo); if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo); @@ -2674,7 +2903,6 @@ static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, WOLFSSL_BUFFER(ssl->arrays->clientRandom, RAN_LEN); #endif - /* Session id - empty in TLS v1.3 */ b = input[i++]; if (b != 0) { @@ -2787,7 +3015,7 @@ static int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ssl->options.clientState = CLIENT_HELLO_COMPLETE; - return 0; + return ret; } /* Send the HelloRetryRequest message to indicate the negotiated protocol @@ -2806,6 +3034,8 @@ int SendTls13HelloRetryRequest(WOLFSSL* ssl) word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; int sendSz; + WOLFSSL_ENTER("SendTls13HelloRetryRequest"); + /* Get the length of the extensions that will be written. */ len = TLSX_GetResponseSize(ssl, hello_retry_request); /* There must be extensions sent to indicate what client needs to do. */ @@ -2884,6 +3114,8 @@ int SendTls13ServerHello(WOLFSSL* ssl) int sendSz; int ret; + WOLFSSL_ENTER("SendTls13ServerHello"); + /* Protocol version, server random, cipher suite and extensions. */ length = VERSION_SZ + RAN_LEN + SUITE_LEN + TLSX_GetResponseSize(ssl, server_hello); @@ -2968,6 +3200,8 @@ int SendTls13EncryptedExtensions(WOLFSSL* ssl) word32 idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; int sendSz; + WOLFSSL_ENTER("SendTls13EncryptedExtensions"); + ssl->keys.encryptionOn = 1; /* Derive the handshake secret now that we are at first message to be @@ -3013,7 +3247,7 @@ int SendTls13EncryptedExtensions(WOLFSSL* ssl) /* This handshake message is always encrypted. */ sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, - idx - RECORD_HEADER_SZ, handshake, 1, 0); + idx - RECORD_HEADER_SZ, handshake, 1, 0, 0); if (sendSz < 0) return sendSz; @@ -3041,15 +3275,19 @@ int SendTls13CertificateRequest(WOLFSSL* ssl) int ret; int sendSz; int reqCtxLen = 0; - word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + word32 i; + int reqSz; - int reqSz = OPAQUE8_LEN + reqCtxLen + - TLSX_GetResponseSize(ssl, certificate_request); + WOLFSSL_ENTER("SendTls13CertificateRequest"); if (ssl->options.usingPSK_cipher || ssl->options.usingAnon_cipher) return 0; /* not needed */ - sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz; + i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ; + reqSz = OPAQUE8_LEN + reqCtxLen + + TLSX_GetResponseSize(ssl, certificate_request); + + sendSz = i + reqSz; /* Always encrypted and make room for padding. */ sendSz += MAX_MSG_EXTRA; @@ -3075,7 +3313,7 @@ int SendTls13CertificateRequest(WOLFSSL* ssl) /* Always encrypted. */ sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, - i - RECORD_HEADER_SZ, handshake, 1, 0); + i - RECORD_HEADER_SZ, handshake, 1, 0, 0); if (sendSz < 0) return sendSz; @@ -3178,24 +3416,31 @@ static INLINE void DecodeSigAlg(byte* input, byte* hashAlgo, byte* hsType) */ static INLINE int GetMsgHash(WOLFSSL* ssl, byte* hash) { + int ret = 0; switch (ssl->specs.mac_algorithm) { #ifndef NO_SHA256 case sha256_mac: - wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash); + ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash); + if (ret != 0) + break; return SHA256_DIGEST_SIZE; #endif /* !NO_SHA256 */ #ifdef WOLFSSL_SHA384 case sha384_mac: - wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash); + ret = wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash); + if (ret != 0) + break; return SHA384_DIGEST_SIZE; #endif /* WOLFSSL_SHA384 */ #ifdef WOLFSSL_SHA512 case sha512_mac: - wc_Sha512GetHash(&ssl->hsHashes->hashSha512, hash); + ret = wc_Sha512GetHash(&ssl->hsHashes->hashSha512, hash); + if (ret != 0) + break; return SHA512_DIGEST_SIZE; #endif /* WOLFSSL_SHA512 */ } - return 0; + return ret; } /* The length of the certificate verification label - client and server. */ @@ -3223,11 +3468,12 @@ static const byte clientCertVfyLabel[CERT_VFY_LABEL_SZ] = * sigDataSz The length of the signature data. * check Indicates this is a check not create. */ -static void CreateSigData(WOLFSSL* ssl, byte* sigData, word16* sigDataSz, +static int CreateSigData(WOLFSSL* ssl, byte* sigData, word16* sigDataSz, int check) { word16 idx; int side = ssl->options.side; + int ret; /* Signature Data = Prefix | Label | Handshake Hash */ XMEMSET(sigData, SIGNING_DATA_PREFIX_BYTE, SIGNING_DATA_PREFIX_SZ); @@ -3247,7 +3493,14 @@ static void CreateSigData(WOLFSSL* ssl, byte* sigData, word16* sigDataSz, #endif idx += CERT_VFY_LABEL_SZ; - *sigDataSz = idx + GetMsgHash(ssl, &sigData[idx]); + ret = GetMsgHash(ssl, &sigData[idx]); + if (ret < 0) + return ret; + + *sigDataSz = idx + ret; + ret = 0; + + return ret; } #ifndef NO_RSA @@ -3419,63 +3672,53 @@ static int CheckRSASignature(WOLFSSL* ssl, int sigAlgo, int hashAlgo, #endif word32 sigSz; - CreateSigData(ssl, sigData, &sigDataSz, 1); + ret = CreateSigData(ssl, sigData, &sigDataSz, 1); + if (ret != 0) + return ret; + #ifdef WC_RSA_PSS if (sigAlgo == rsa_pss_sa_algo) { enum wc_HashType hashType = WC_HASH_TYPE_NONE; - switch (hashAlgo) { - case sha512_mac: - #ifdef WOLFSSL_SHA512 - hashType = WC_HASH_TYPE_SHA512; - #endif - break; - case sha384_mac: - #ifdef WOLFSSL_SHA384 - hashType = WC_HASH_TYPE_SHA384; - #endif - break; - case sha256_mac: - #ifndef NO_SHA256 - hashType = WC_HASH_TYPE_SHA256; - #endif - break; - } - - ret = sigSz = CreateRSAEncodedSig(sigData, sigData, sigDataSz, - rsa_pss_sa_algo, hashAlgo); + ret = ConvertHashPss(hashAlgo, &hashType, NULL); if (ret < 0) return ret; + /* PSS signature can be done in-pace */ + ret = CreateRSAEncodedSig(sigData, sigData, sigDataSz, + sigAlgo, hashAlgo); + if (ret < 0) + return ret; + sigSz = ret; + ret = wc_RsaPSS_CheckPadding(sigData, sigSz, decSig, decSigSz, hashType); } else #endif { -#ifdef WOLFSSL_SMALL_STACK + #ifdef WOLFSSL_SMALL_STACK encodedSig = (byte*)XMALLOC(MAX_ENCODED_SIG_SZ, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); if (encodedSig == NULL) { - ret = MEMORY_E; - goto end; + return MEMORY_E; } -#endif + #endif + + sigSz = CreateRSAEncodedSig(encodedSig, sigData, sigDataSz, sigAlgo, + hashAlgo); - sigSz = CreateRSAEncodedSig(encodedSig, sigData, sigDataSz, - DYNAMIC_TYPE_RSA, hashAlgo); /* Check the encoded and decrypted signature data match. */ if (decSigSz != sigSz || decSig == NULL || XMEMCMP(decSig, encodedSig, sigSz) != 0) { ret = VERIFY_CERT_ERROR; } - } -#ifdef WOLFSSL_SMALL_STACK -end: - if (encodedSig != NULL) - XFREE(encodedSig, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); -#endif + #ifdef WOLFSSL_SMALL_STACK + if (encodedSig != NULL) + XFREE(encodedSig, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + #endif + } return ret; } @@ -3556,6 +3799,7 @@ int SendTls13Certificate(WOLFSSL* ssl) word32 offset = OPAQUE16_LEN; byte* p = NULL; + WOLFSSL_ENTER("SendTls13Certificate"); /* TODO: [TLS13] Request context for post-handshake auth. * Taken from request if post-handshake. @@ -3707,7 +3951,7 @@ int SendTls13Certificate(WOLFSSL* ssl) /* This message is always encrypted. */ sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, - i - RECORD_HEADER_SZ, handshake, 1, 0); + i - RECORD_HEADER_SZ, handshake, 1, 0, 0); if (sendSz < 0) return sendSz; @@ -3873,7 +4117,9 @@ int SendTls13CertificateVerify(WOLFSSL* ssl) ERROR_OUT(MEMORY_E, exit_scv); } - CreateSigData(ssl, args->sigData, &args->sigDataSz, 0); + ret = CreateSigData(ssl, args->sigData, &args->sigDataSz, 0); + if (ret != 0) + goto exit_scv; #ifndef NO_RSA if (ssl->hsType == DYNAMIC_TYPE_RSA) { @@ -3954,8 +4200,6 @@ int SendTls13CertificateVerify(WOLFSSL* ssl) #endif #ifndef NO_RSA if (ssl->hsType == DYNAMIC_TYPE_RSA) { - /* restore verify pointer */ - args->verify = &args->output[args->idx]; ret = RsaSign(ssl, sig->buffer, sig->length, args->verify + HASH_SIG_SIZE + VERIFY_HEADER, &args->sigLen, @@ -3987,9 +4231,6 @@ int SendTls13CertificateVerify(WOLFSSL* ssl) case TLS_ASYNC_VERIFY: { - /* restore verify pointer */ - args->verify = &args->output[args->idx]; - #ifndef NO_RSA if (ssl->hsType == DYNAMIC_TYPE_RSA) { if (args->verifySig == NULL) { @@ -4029,17 +4270,6 @@ int SendTls13CertificateVerify(WOLFSSL* ssl) args->sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + args->length + HASH_SIG_SIZE + VERIFY_HEADER; - /* This message is always encrypted. */ - args->sendSz = BuildTls13Message(ssl, args->output, - MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA, - args->output + RECORD_HEADER_SZ, - args->sendSz - RECORD_HEADER_SZ, handshake, - 1, 0); - if (args->sendSz < 0) { - ret = args->sendSz; - goto exit_scv; - } - /* Advance state and proceed */ ssl->options.asyncState = TLS_ASYNC_END; } /* case TLS_ASYNC_FINALIZE */ @@ -4047,6 +4277,21 @@ int SendTls13CertificateVerify(WOLFSSL* ssl) case TLS_ASYNC_END: { + /* This message is always encrypted. */ + ret = BuildTls13Message(ssl, args->output, + MAX_CERT_VERIFY_SZ + MAX_MSG_EXTRA, + args->output + RECORD_HEADER_SZ, + args->sendSz - RECORD_HEADER_SZ, handshake, + 1, 0, 0); + + if (ret < 0) { + goto exit_scv; + } + else { + args->sendSz = ret; + ret = 0; + } + #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName("CertificateVerify", &ssl->handShakeInfo); @@ -4248,7 +4493,9 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, ERROR_OUT(MEMORY_E, exit_dcv); } - CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); + ret = CreateSigData(ssl, args->sigData, &args->sigDataSz, 1); + if (ret != 0) + goto exit_dcv; ret = CreateECCEncodedSig(args->sigData, args->sigDataSz, args->hashAlgo); if (ret < 0) @@ -4280,7 +4527,7 @@ static int DoTls13CertificateVerify(WOLFSSL* ssl, byte* input, case TLS_ASYNC_DO: { #ifndef NO_RSA - if (args->sigAlgo == rsa_sa_algo || + if (args->sigAlgo == rsa_sa_algo || args->sigAlgo == rsa_pss_sa_algo) { WOLFSSL_MSG("Doing RSA peer cert verify"); @@ -4550,7 +4797,7 @@ int SendTls13Finished(WOLFSSL* ssl) /* This message is always encrypted. */ sendSz = BuildTls13Message(ssl, output, outputSz, input, - headerSz + finishedSz, handshake, 1, 0); + headerSz + finishedSz, handshake, 1, 0, 0); if (sendSz < 0) return BUILD_MSG_ERROR; @@ -4642,7 +4889,7 @@ static int SendTls13KeyUpdate(WOLFSSL* ssl) /* This message is always encrypted. */ sendSz = BuildTls13Message(ssl, output, outputSz, input, - headerSz + OPAQUE8_LEN, handshake, 0, 0); + headerSz + OPAQUE8_LEN, handshake, 0, 0, 0); if (sendSz < 0) return BUILD_MSG_ERROR; @@ -4886,7 +5133,7 @@ int SendTls13NewSessionTicket(WOLFSSL* ssl) /* This message is always encrypted. */ sendSz = BuildTls13Message(ssl, output, sendSz, output + RECORD_HEADER_SZ, - idx - RECORD_HEADER_SZ, handshake, 0, 0); + idx - RECORD_HEADER_SZ, handshake, 0, 0, 0); if (sendSz < 0) return sendSz; @@ -5175,6 +5422,11 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, break; } + /* reset error */ + if (ret == 0 && ssl->error == WC_PENDING_E) + ssl->error = 0; + + if (ret == 0 && type != client_hello && type != session_ticket && type != key_update && ssl->error != WC_PENDING_E) { ret = HashInput(ssl, input + inIdx, size); @@ -5429,7 +5681,8 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl) FALL_THROUGH; case HELLO_AGAIN_REPLY: - if (ssl->options.serverState == NULL_STATE) { + if (ssl->options.serverState == NULL_STATE || + ssl->error == WC_PENDING_E) { neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE : SERVER_HELLODONE_COMPLETE; diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 2e853a828..08afa3b62 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -5835,8 +5835,8 @@ static int DecodePolicyOID(char *out, word32 outSz, byte *in, word32 inSz) break; #elif defined(WOLFSSL_CERT_EXT) /* decode cert policy */ - if (DecodePolicyOID(cert->extCertPolicies[cert->extCertPoliciesNb], MAX_CERTPOL_SZ, - input + idx, length) != 0) { + if (DecodePolicyOID(cert->extCertPolicies[cert->extCertPoliciesNb], + MAX_CERTPOL_SZ, input + idx, length) != 0) { WOLFSSL_MSG("\tCouldn't decode CertPolicy"); return ASN_PARSE_E; } diff --git a/wolfcrypt/src/fe_low_mem.c b/wolfcrypt/src/fe_low_mem.c index aa6a44996..0f0f1be44 100644 --- a/wolfcrypt/src/fe_low_mem.c +++ b/wolfcrypt/src/fe_low_mem.c @@ -20,7 +20,7 @@ */ -/* Based from Daniel Beer's public domain word. */ +/* Based from Daniel Beer's public domain work. */ #ifdef HAVE_CONFIG_H #include diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 4293dd873..42d6376ab 100755 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2672,6 +2672,22 @@ enum asyncState { TLS_ASYNC_END }; +/* sub-states for build message */ +enum buildMsgState { + BUILD_MSG_BEGIN = 0, + BUILD_MSG_SIZE, + BUILD_MSG_HASH, + BUILD_MSG_VERIFY_MAC, + BUILD_MSG_ENCRYPT, +}; + +/* sub-states for cipher operations */ +enum cipherState { + CIPHER_STATE_BEGIN = 0, + CIPHER_STATE_DO, + CIPHER_STATE_END, +}; + typedef struct Options { #ifndef NO_PSK wc_psk_client_callback client_psk_cb; @@ -3468,9 +3484,12 @@ WOLFSSL_LOCAL void ShrinkOutputBuffer(WOLFSSL* ssl); WOLFSSL_LOCAL int VerifyClientSuite(WOLFSSL* ssl); #ifndef NO_CERTS #ifndef NO_RSA - WOLFSSL_LOCAL int CheckRsaPssPadding(const byte* plain, word32 plainSz, - byte* out, word32 sigSz, - enum wc_HashType hashType); + #ifdef WC_RSA_PSS + WOLFSSL_LOCAL int CheckRsaPssPadding(const byte* plain, word32 plainSz, + byte* out, word32 sigSz, + enum wc_HashType hashType); + WOLFSSL_LOCAL int ConvertHashPss(int hashAlgo, enum wc_HashType* hashType, int* mgf); + #endif WOLFSSL_LOCAL int VerifyRsaSign(WOLFSSL* ssl, byte* verifySig, word32 sigSz, const byte* plain, word32 plainSz, @@ -3637,7 +3656,7 @@ WOLFSSL_LOCAL int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, #ifdef WOLFSSL_TLS13 int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input, - int inSz, int type, int hashOutput, int sizeOnly); + int inSz, int type, int hashOutput, int sizeOnly, int asyncOkay); #endif WOLFSSL_LOCAL int AllocKey(WOLFSSL* ssl, int type, void** pKey); diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 7e573a398..59608670b 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1701,6 +1701,10 @@ WOLFSSL_API int wolfSSL_UseClientSuites(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_UseAsync(WOLFSSL*, int devId); WOLFSSL_API int wolfSSL_CTX_UseAsync(WOLFSSL_CTX*, int devId); +/* helpers to get device id and heap */ +WOLFSSL_API int wolfSSL_CTX_GetDevId(WOLFSSL_CTX* ctx, WOLFSSL* ssl); +WOLFSSL_API void* wolfSSL_CTX_GetHeap(WOLFSSL_CTX* ctx, WOLFSSL* ssl); + /* TLS Extensions */ /* Server Name Indication */ diff --git a/wolfssl/test.h b/wolfssl/test.h index 7535465af..a22a8af37 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -1803,6 +1803,11 @@ static INLINE int myEccSharedSecret(WOLFSSL* ssl, ecc_key* otherKey, ret = wc_InitRng(&rng); if (ret == 0) { ret = wc_ecc_make_key_ex(&rng, 0, privKey, otherKey->dp->id); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wc_AsyncWait(ret, &privKey->asyncDev, WC_ASYNC_FLAG_NONE); + } + #endif if (ret == 0) ret = wc_ecc_export_x963(privKey, pubKeyDer, pubKeySz); wc_FreeRng(&rng); @@ -1824,6 +1829,12 @@ static INLINE int myEccSharedSecret(WOLFSSL* ssl, ecc_key* otherKey, /* generate shared secret and return it */ if (ret == 0) { ret = wc_ecc_shared_secret(privKey, pubKey, out, outlen); + + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { + ret = wc_AsyncWait(ret, &privKey->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); + } + #endif } wc_ecc_free(&tmpKey); diff --git a/wolfssl/wolfcrypt/ed25519.h b/wolfssl/wolfcrypt/ed25519.h index f806785aa..049e4a61d 100644 --- a/wolfssl/wolfcrypt/ed25519.h +++ b/wolfssl/wolfcrypt/ed25519.h @@ -32,6 +32,10 @@ #include #include +#ifdef WOLFSSL_ASYNC_CRYPT + #include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -69,6 +73,9 @@ struct ed25519_key { byte pointX[ED25519_KEY_SIZE]; /* recovered X coordinate */ byte pointY[ED25519_KEY_SIZE]; /* Y coordinate is the public key with The most significant bit of the final octet always zero. */ #endif +#ifdef WOLFSSL_ASYNC_CRYPT + WC_ASYNC_DEV asyncDev; +#endif }; From af2cbcdbabe716a4addc87fa267085bfc9a37232 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 9 Jun 2017 08:57:50 -0700 Subject: [PATCH 2/2] Added new arg documentation for `asyncOkay` in doxygen style. --- src/tls13.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tls13.c b/src/tls13.c index 6bbd1d05f..c3ac01cf9 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -1594,6 +1594,7 @@ static int ChaCha20Poly1305_Encrypt(WOLFSSL* ssl, byte* output, * May be the same pointer as input. * input The data to encrypt. * sz The number of bytes to encrypt. + * asyncOkay If non-zero can return WC_PENDING_E, otherwise blocks on crypto * returns 0 on success, otherwise failure. */ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input, @@ -1963,6 +1964,7 @@ static void FreeBuildMsg13Args(WOLFSSL* ssl, void* pArgs) * type The recorder header content type. * hashOutput Whether to hash the unencrypted record data. * sizeOnly Only want the size of the record message. + * asyncOkay If non-zero can return WC_PENDING_E, otherwise blocks on crypto * returns the size of the encrypted record message or negative value on error. */ int BuildTls13Message(WOLFSSL* ssl, byte* output, int outSz, const byte* input,