From 24e98dd05efc35d9d5ed19dec57b82eab1a13ce8 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Thu, 22 Aug 2019 09:33:38 +1000 Subject: [PATCH] Add support for Encrypt-Then-MAC to TLS 1.2 and below An extension is used to indicate that ETM is to be used. Only used when doing block ciphers - HMAC performed on encrypted data. --- configure.ac | 16 +- examples/client/client.c | 86 +++++--- examples/server/server.c | 72 ++++--- src/internal.c | 451 ++++++++++++++++++++++++++++++++++----- src/keys.c | 5 + src/ssl.c | 111 ++++++++++ src/tls.c | 178 +++++++++++++++ tests/test.conf | 57 +++++ wolfssl/internal.h | 19 ++ wolfssl/ssl.h | 23 +- wolfssl/test.h | 174 ++++++++++++++- 11 files changed, 1078 insertions(+), 114 deletions(-) diff --git a/configure.ac b/configure.ac index cf03e7f52..61fad39dd 100644 --- a/configure.ac +++ b/configure.ac @@ -2936,6 +2936,19 @@ then AM_CFLAGS="$AM_CFLAGS -DHAVE_EXTENDED_MASTER" fi +# Encrypt-Then-Mac +AC_ARG_ENABLE([enc-then-mac], + [AS_HELP_STRING([--enable-enc-then-mac],[Enable Encryptr-Then-Mac extension (default: enabled)])], + [ ENABLED_ENCRYPT_THEN_MAC=$enableval ], + [ ENABLED_ENCRYPT_THEN_MAC=yes ] + ) + +if test "x$ENABLED_ENCRYPT_THEN_MAC" = "xyes" +then + AM_CFLAGS="$AM_CFLAGS -DHAVE_ENCRYPT_THEN_MAC" +fi + + # TLS Extensions AC_ARG_ENABLE([tlsx], [AS_HELP_STRING([--enable-tlsx],[Enable all TLS Extensions (default: disabled)])], @@ -2955,7 +2968,8 @@ then ENABLED_TRUNCATED_HMAC=yes ENABLED_ALPN=yes ENABLED_TRUSTED_CA=yes - AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_SNI -DHAVE_MAX_FRAGMENT -DHAVE_TRUNCATED_HMAC -DHAVE_ALPN -DHAVE_TRUSTED_CA" + ENABLED_ENCRYPT_THEN_MAC=yes + AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_SNI -DHAVE_MAX_FRAGMENT -DHAVE_TRUNCATED_HMAC -DHAVE_ALPN -DHAVE_TRUSTED_CA -DHAVE_ENCRYPT_THEN_MAC" # Check the ECC supported curves prereq AS_IF([test "x$ENABLED_ECC" = "xyes" || test "x$ENABLED_CURVE25519" = "xyes"], [ENABLED_SUPPORTED_CURVES=yes diff --git a/examples/client/client.c b/examples/client/client.c index 8efa4ec49..56f551b95 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -940,7 +940,7 @@ static const char* client_usage_msg[][59] = { || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) "-W Use OCSP Stapling (1 v1, 2 v2, 3 v2 multi)\n", /* 41 */ #endif -#ifdef ATOMIC_USER +#if defined(ATOMIC_USER) && !defined(WOLFSSL_AEAD_ONLY) "-U Atomic User Record Layer Callbacks\n", /* 42 */ #endif #ifdef HAVE_PK_CALLBACKS @@ -959,41 +959,42 @@ static const char* client_usage_msg[][59] = { "-q Whitewood config file, defaults\n", /* 47 */ #endif "-H Internal tests" - " [defCipherList, exitWithRet, verifyFail]\n", /* 48 */ + " [defCipherList, exitWithRet, verifyFail, useSupCurve,\n", /* 48 */ + " loadSSL, disallowETM]\n", /* 49 */ #ifdef WOLFSSL_TLS13 - "-J Use HelloRetryRequest to choose group for KE\n", /* 49 */ - "-K Key Exchange for PSK not using (EC)DHE\n", /* 50 */ - "-I Update keys and IVs before sending data\n", /* 51 */ + "-J Use HelloRetryRequest to choose group for KE\n", /* 50 */ + "-K Key Exchange for PSK not using (EC)DHE\n", /* 51 */ + "-I Update keys and IVs before sending data\n", /* 52 */ #ifndef NO_DH - "-y Key Share with FFDHE named groups only\n", /* 52 */ + "-y Key Share with FFDHE named groups only\n", /* 53 */ #endif #ifdef HAVE_ECC - "-Y Key Share with ECC named groups only\n", /* 53 */ + "-Y Key Share with ECC named groups only\n", /* 54 */ #endif #endif /* WOLFSSL_TLS13 */ #ifdef HAVE_CURVE25519 - "-t Use X25519 for key exchange\n", /* 54 */ + "-t Use X25519 for key exchange\n", /* 55 */ #endif #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) - "-Q Support requesting certificate post-handshake\n", /* 55 */ + "-Q Support requesting certificate post-handshake\n", /* 56 */ #endif #ifdef WOLFSSL_EARLY_DATA - "-0 Early data sent to server (0-RTT handshake)\n", /* 56 */ + "-0 Early data sent to server (0-RTT handshake)\n", /* 57 */ #endif #ifdef WOLFSSL_MULTICAST - "-3 Multicast, grpid < 256\n", /* 57 */ + "-3 Multicast, grpid < 256\n", /* 58 */ #endif "-1 Display a result by specified language.\n" - " 0: English, 1: Japanese\n", /* 58 */ + " 0: English, 1: Japanese\n", /* 59 */ #if !defined(NO_DH) && !defined(HAVE_FIPS) && \ !defined(HAVE_SELFTEST) && !defined(WOLFSSL_OLD_PRIME_CHECK) - "-2 Disable DH Prime check\n", /* 59 */ + "-2 Disable DH Prime check\n", /* 60 */ #endif #ifdef HAVE_SECURE_RENEGOTIATION - "-4 Use resumption for renegotiation\n", /* 60 */ + "-4 Use resumption for renegotiation\n", /* 61 */ #endif #ifdef HAVE_TRUSTED_CA - "-5 Use Trusted CA Key Indication\n", /* 61 */ + "-5 Use Trusted CA Key Indication\n", /* 62 */ #endif NULL, }, @@ -1099,7 +1100,7 @@ static const char* client_usage_msg[][59] = { "-W OCSP Staplingを使用する" " (1 v1, 2 v2, 3 v2 multi)\n", /* 41 */ #endif -#ifdef ATOMIC_USER +#if defined(ATOMIC_USER) && !defined(WOLFSSL_AEAD_ONLY) "-U アトミック・ユーザー記録の" "コールバックを利用する\n", /* 42 */ #endif @@ -1119,42 +1120,43 @@ static const char* client_usage_msg[][59] = { "-q Whitewood コンフィグファイル, 既定値\n", /* 47 */ #endif "-H 内部テスト" - " [defCipherList, exitWithRet, verifyFail]\n", /* 48 */ + " [defCipherList, exitWithRet, verifyFail, useSupCurve,\n", /* 48 */ + " loadSSL, disallowETM]\n", /* 49 */ #ifdef WOLFSSL_TLS13 - "-J HelloRetryRequestをKEのグループ選択に使用する\n", /* 49 */ - "-K 鍵交換にPSKを使用、(EC)DHEは使用しない\n", /* 50 */ - "-I データ送信前に、鍵とIVを更新する\n", /* 51 */ + "-J HelloRetryRequestをKEのグループ選択に使用する\n", /* 50 */ + "-K 鍵交換にPSKを使用、(EC)DHEは使用しない\n", /* 51 */ + "-I データ送信前に、鍵とIVを更新する\n", /* 52 */ #ifndef NO_DH - "-y FFDHE名前付きグループとの鍵共有のみ\n", /* 52 */ + "-y FFDHE名前付きグループとの鍵共有のみ\n", /* 53 */ #endif #ifdef HAVE_ECC - "-Y ECC名前付きグループとの鍵共有のみ\n", /* 53 */ + "-Y ECC名前付きグループとの鍵共有のみ\n", /* 54 */ #endif #endif /* WOLFSSL_TLS13 */ #ifdef HAVE_CURVE25519 - "-t X25519を鍵交換に使用する\n", /* 54 */ + "-t X25519を鍵交換に使用する\n", /* 55 */ #endif #if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) - "-Q ポストハンドシェークの証明要求をサポートする\n", /* 55 */ + "-Q ポストハンドシェークの証明要求をサポートする\n", /* 56 */ #endif #ifdef WOLFSSL_EARLY_DATA "-0 Early data をサーバーへ送信する" - "(0-RTTハンドシェイク)\n", /* 56 */ + "(0-RTTハンドシェイク)\n", /* 57 */ #endif #ifdef WOLFSSL_MULTICAST - "-3 マルチキャスト, grpid < 256\n", /* 57 */ + "-3 マルチキャスト, grpid < 256\n", /* 58 */ #endif "-1 指定された言語で結果を表示します。\n" - " 0: 英語、 1: 日本語\n", /* 58 */ + " 0: 英語、 1: 日本語\n", /* 59 */ #if !defined(NO_DH) && !defined(HAVE_FIPS) && \ !defined(HAVE_SELFTEST) && !defined(WOLFSSL_OLD_PRIME_CHECK) - "-2 DHプライム番号チェックを無効にする\n", /* 59 */ + "-2 DHプライム番号チェックを無効にする\n", /* 60 */ #endif #ifdef HAVE_SECURE_RENEGOTIATION - "-4 再交渉に再開を使用\n", /* 60 */ + "-4 再交渉に再開を使用\n", /* 61 */ #endif #ifdef HAVE_TRUSTED_CA - "-5 信頼できる認証局の鍵表示を使用する\n", /* 61 */ + "-5 信頼できる認証局の鍵表示を使用する\n", /* 62 */ #endif NULL, }, @@ -1258,7 +1260,7 @@ static void Usage(void) || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) printf("%s", msg[++msgid]); /* -W */ #endif -#ifdef ATOMIC_USER +#if defined(ATOMIC_USER) && !defined(WOLFSSL_AEAD_ONLY) printf("%s", msg[++msgid]); /* -U */ #endif #ifdef HAVE_PK_CALLBACKS @@ -1277,6 +1279,7 @@ static void Usage(void) printf("%s %s\n", msg[++msgid], wnrConfig); /* -q */ #endif printf("%s", msg[++msgid]); /* -H */ + printf("%s", msg[++msgid]); /* more -H options */ #ifdef WOLFSSL_TLS13 printf("%s", msg[++msgid]); /* -J */ printf("%s", msg[++msgid]); /* -K */ @@ -1439,6 +1442,10 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) int exitWithRet = 0; int loadCertKeyIntoSSLObj = 0; +#ifdef HAVE_ENCRYPT_THEN_MAC + int disallowETM = 0; +#endif + #ifdef HAVE_WNR const char* wnrConfigFile = wnrConfig; #endif @@ -1580,7 +1587,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) break; case 'U' : - #ifdef ATOMIC_USER + #if defined(ATOMIC_USER) && !defined(WOLFSSL_AEAD_ONLY) atomicUser = 1; #endif break; @@ -1662,6 +1669,12 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) printf("Certs turned off with NO_CERTS!\n"); #endif } + else if (XSTRNCMP(myoptarg, "disallowETM", 7) == 0) { + printf("Disallow Enrypt-Then-MAC\n"); + #ifdef HAVE_ENCRYPT_THEN_MAC + disallowETM = 1; + #endif + } else { Usage(); XEXIT_T(MY_EX_USAGE); @@ -2699,6 +2712,11 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) wolfSSL_SetEnableDhKeyTest(ssl, 0); #endif +#ifdef HAVE_ENCRYPT_THEN_MAC + if (disallowETM) + wolfSSL_AllowEncryptThenMac(ssl, 0); +#endif + tcp_connect(&sockfd, host, port, dtlsUDP, dtlsSCTP, ssl); if (wolfSSL_set_fd(ssl, sockfd) != WOLFSSL_SUCCESS) { @@ -2749,7 +2767,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) } } #endif -#ifdef ATOMIC_USER +#if defined(ATOMIC_USER) && !defined(WOLFSSL_AEAD_ONLY) if (atomicUser) SetupAtomicUser(ctx, ssl); #endif @@ -2973,7 +2991,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) if (wc_shutdown && ret == WOLFSSL_SHUTDOWN_NOT_DONE) wolfSSL_shutdown(ssl); /* bidirectional shutdown */ } -#ifdef ATOMIC_USER +#if defined(ATOMIC_USER) && !defined(WOLFSSL_AEAD_ONLY) if (atomicUser) FreeAtomicUser(ssl); #endif diff --git a/examples/server/server.c b/examples/server/server.c index ea8f06743..a7e89ef2c 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -582,39 +582,40 @@ static const char* server_usage_msg[][49] = { "-g Return basic HTML web page\n", /* 35 */ "-C The number of connections to accept, default: 1\n",/* 36 */ "-H Internal tests" - " [defCipherList, exitWithRet, verifyFail]\n", /* 37 */ + " [defCipherList, exitWithRet, verifyFail, useSupCurve,\n", /* 37 */ + " loadSSL, disallowETM]\n", /* 38 */ #ifdef WOLFSSL_TLS13 - "-U Update keys and IVs before sending\n", /* 38 */ - "-K Key Exchange for PSK not using (EC)DHE\n", /* 39 */ + "-U Update keys and IVs before sending\n", /* 39 */ + "-K Key Exchange for PSK not using (EC)DHE\n", /* 40 */ #ifndef NO_DH - "-y Pre-generate Key Share using FFDHE_2048 only\n", /* 40 */ + "-y Pre-generate Key Share using FFDHE_2048 only\n", /* 41 */ #endif #ifdef HAVE_ECC - "-Y Pre-generate Key Share using P-256 only \n", /* 41 */ + "-Y Pre-generate Key Share using P-256 only \n", /* 42 */ #endif #ifdef HAVE_CURVE25519 - "-t Pre-generate Key share using Curve25519 only\n", /* 42 */ + "-t Pre-generate Key share using Curve25519 only\n", /* 43 */ #endif #ifdef HAVE_SESSION_TICKET - "-T Do not generate session ticket\n", /* 43 */ + "-T Do not generate session ticket\n", /* 44 */ #endif #ifdef WOLFSSL_POST_HANDSHAKE_AUTH - "-Q Request certificate from client post-handshake\n", /* 44 */ + "-Q Request certificate from client post-handshake\n", /* 45 */ #endif #ifdef WOLFSSL_SEND_HRR_COOKIE - "-J Server sends Cookie Extension containing state\n", /* 45 */ + "-J Server sends Cookie Extension containing state\n", /* 46 */ #endif #endif /* WOLFSSL_TLS13 */ #ifdef WOLFSSL_EARLY_DATA - "-0 Early data read from client (0-RTT handshake)\n", /* 46 */ + "-0 Early data read from client (0-RTT handshake)\n", /* 47 */ #endif #ifdef WOLFSSL_MULTICAST - "-3 Multicast, grpid < 256\n", /* 47 */ + "-3 Multicast, grpid < 256\n", /* 48 */ #endif "-1 Display a result by specified language." - "\n 0: English, 1: Japanese\n", /* 48 */ + "\n 0: English, 1: Japanese\n", /* 49 */ #ifdef HAVE_TRUSTED_CA - "-5 Use Trusted CA Key Indication\n", /* 51 */ + "-5 Use Trusted CA Key Indication\n", /* 52 */ #endif NULL, }, @@ -698,41 +699,42 @@ static const char* server_usage_msg[][49] = { "-g 基本的な Web ページを返す\n", /* 35 */ "-C アクセプト可能な接続数を指定する。既定値: 1\n", /* 36 */ "-H 内部テスト" - " [defCipherList, exitWithRet, verifyFail]\n", /* 37 */ + " [defCipherList, exitWithRet, verifyFail, useSupCurve,\n", /* 37 */ + " loadSSL, disallowETM]\n", /* 38 */ #ifdef WOLFSSL_TLS13 - "-U データ送信前に、鍵とIVを更新する\n", /* 38 */ - "-K 鍵交換にPSKを使用、(EC)DHEは使用しない\n", /* 39 */ + "-U データ送信前に、鍵とIVを更新する\n", /* 39 */ + "-K 鍵交換にPSKを使用、(EC)DHEは使用しない\n", /* 40 */ #ifndef NO_DH - "-y FFDHE_2048のみを使用して鍵共有を事前生成する\n", /* 40 */ + "-y FFDHE_2048のみを使用して鍵共有を事前生成する\n", /* 41 */ #endif #ifdef HAVE_ECC - "-Y P-256のみを使用したキー共有の事前生成\n", /* 41 */ + "-Y P-256のみを使用したキー共有の事前生成\n", /* 42 */ #endif #ifdef HAVE_CURVE25519 - "-t Curve25519のみを使用して鍵共有を事前生成する\n", /* 42 */ + "-t Curve25519のみを使用して鍵共有を事前生成する\n", /* 43 */ #endif #ifdef HAVE_SESSION_TICKET - "-T セッションチケットを生成しない\n", /* 43 */ + "-T セッションチケットを生成しない\n", /* 44 */ #endif #ifdef WOLFSSL_POST_HANDSHAKE_AUTH "-Q クライアントのポストハンドシェイクから" - "証明書を要求する\n", /* 44 */ + "証明書を要求する\n", /* 45 */ #endif #ifdef WOLFSSL_SEND_HRR_COOKIE - "-J サーバーの状態を含むTLS Cookie 拡張を送信する\n", /* 45 */ + "-J サーバーの状態を含むTLS Cookie 拡張を送信する\n", /* 46 */ #endif #endif /* WOLFSSL_TLS13 */ #ifdef WOLFSSL_EARLY_DATA "-0 クライアントからの Early Data 読み取り" - "(0-RTTハンドシェイク)\n", /* 46 */ + "(0-RTTハンドシェイク)\n", /* 47 */ #endif #ifdef WOLFSSL_MULTICAST - "-3 マルチキャスト, grpid < 256\n", /* 47 */ + "-3 マルチキャスト, grpid < 256\n", /* 48 */ #endif "-1 指定された言語で結果を表示します。" - "\n 0: 英語、 1: 日本語\n", /* 48 */ + "\n 0: 英語、 1: 日本語\n", /* 49 */ #ifdef HAVE_TRUSTED_CA - "-5 信頼できる認証局の鍵表示を使用する\n", /* 51 */ + "-5 信頼できる認証局の鍵表示を使用する\n", /* 52 */ #endif NULL, }, @@ -812,7 +814,8 @@ static void Usage(void) #endif printf("%s", msg[++msgId]); /* -g */ printf("%s", msg[++msgId]); /* -C */ - printf("%s", msg[++msgId]); /* -H */ + printf("%s", msg[++msgId]); /* -H */ + printf("%s", msg[++msgId]); /* more -H options */ #ifdef WOLFSSL_TLS13 printf("%s", msg[++msgId]); /* -U */ printf("%s", msg[++msgId]); /* -K */ @@ -997,6 +1000,10 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) int exitWithRet = 0; int loadCertKeyIntoSSLObj = 0; +#ifdef HAVE_ENCRYPT_THEN_MAC + int disallowETM = 0; +#endif + ((func_args*)args)->return_code = -1; /* error state */ #ifdef NO_RSA @@ -1173,6 +1180,12 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) loadCertKeyIntoSSLObj = 1; #endif } + else if (XSTRNCMP(myoptarg, "disallowETM", 11) == 0) { + printf("Disallow Encrypt-Then-MAC\n"); + #ifdef HAVE_ENCRYPT_THEN_MAC + disallowETM = 1; + #endif + } else { Usage(); XEXIT_T(MY_EX_USAGE); @@ -1979,6 +1992,11 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args) } #endif + #ifdef HAVE_ENCRYPT_THEN_MAC + if (disallowETM) + wolfSSL_AllowEncryptThenMac(ssl, 0); + #endif + /* do accept */ readySignal = ((func_args*)args)->signal; diff --git a/src/internal.c b/src/internal.c index 08f57bf8c..080f152e2 100644 --- a/src/internal.c +++ b/src/internal.c @@ -141,6 +141,7 @@ enum processReply { #endif getRecordLayerHeader, getData, + verifyEncryptedMessage, decryptMessage, verifyMessage, runProcessingOneMessage @@ -3373,6 +3374,20 @@ static void SetDigest(WOLFSSL* ssl, int hashAlgo) #endif /* !NO_WOLFSSL_SERVER || !NO_WOLFSSL_CLIENT */ #endif /* !NO_CERTS */ +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) +static word32 MacSize(WOLFSSL* ssl) +{ +#ifdef HAVE_TRUNCATED_HMAC + word32 digestSz = ssl->truncated_hmac ? (byte)TRUNCATED_HMAC_SZ + : ssl->specs.hash_size; +#else + word32 digestSz = ssl->specs.hash_size; +#endif + + return digestSz; +} +#endif /* HAVE_ENCRYPT_THEN_MAC && !WOLFSSL_AEAD_ONLY */ + #ifndef NO_RSA #ifndef WOLFSSL_NO_TLS12 #if !defined(NO_WOLFSSL_SERVER) || !defined(NO_WOLFSSL_CLIENT) @@ -5133,6 +5148,10 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) #endif #endif /* HAVE_TLS_EXTENSIONS */ +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + ssl->options.disallowEncThenMac = ctx->disallowEncThenMac; +#endif + /* default alert state (none) */ ssl->alert_history.last_rx.code = -1; ssl->alert_history.last_rx.level = -1; @@ -10481,6 +10500,10 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, if (IsEncryptionOn(ssl, 0)) { args->idx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) + args->idx += MacSize(ssl); + #endif } /* Advance state and proceed */ @@ -10704,9 +10727,20 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx, SendAlert(ssl, alert_fatal, bad_certificate_status_response); if (IsEncryptionOn(ssl, 0)) { - if (*inOutIdx + ssl->keys.padSz > size) - return BUFFER_E; - *inOutIdx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) { + word32 digestSz = MacSize(ssl); + if (*inOutIdx + ssl->keys.padSz + digestSz > size) + return BUFFER_E; + *inOutIdx += ssl->keys.padSz + digestSz; + } + else + #endif + { + if (*inOutIdx + ssl->keys.padSz > size) + return BUFFER_E; + *inOutIdx += ssl->keys.padSz; + } } WOLFSSL_LEAVE("DoCertificateStatus", ret); @@ -10735,11 +10769,22 @@ static int DoHelloRequest(WOLFSSL* ssl, const byte* input, word32* inOutIdx, return BUFFER_ERROR; if (IsEncryptionOn(ssl, 0)) { - /* access beyond input + size should be checked against totalSz */ - if (*inOutIdx + ssl->keys.padSz > totalSz) - return BUFFER_E; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) { + word32 digestSz = MacSize(ssl); + if (*inOutIdx + ssl->keys.padSz + digestSz > totalSz) + return BUFFER_E; + *inOutIdx += ssl->keys.padSz + digestSz; + } + else + #endif + { + /* access beyond input + size should be checked against totalSz */ + if (*inOutIdx + ssl->keys.padSz > totalSz) + return BUFFER_E; - *inOutIdx += ssl->keys.padSz; + *inOutIdx += ssl->keys.padSz; + } } if (ssl->options.side == WOLFSSL_SERVER_END) { @@ -10772,8 +10817,17 @@ int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size, return BUFFER_ERROR; /* check against totalSz */ - if (*inOutIdx + size + ssl->keys.padSz > totalSz) - return BUFFER_E; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) { + if (*inOutIdx + size + ssl->keys.padSz + MacSize(ssl) > totalSz) + return BUFFER_E; + } + else + #endif + { + if (*inOutIdx + size + ssl->keys.padSz > totalSz) + return BUFFER_E; + } #ifdef WOLFSSL_CALLBACKS if (ssl->hsInfoOn) AddPacketName(ssl, "Finished"); @@ -10805,6 +10859,10 @@ int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size, /* force input exhaustion at ProcessReply consuming padSz */ *inOutIdx += size + ssl->keys.padSz; +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) + *inOutIdx += MacSize(ssl); +#endif if (ssl->options.side == WOLFSSL_CLIENT_END) { ssl->options.serverState = SERVER_FINISHED_COMPLETE; @@ -11192,6 +11250,10 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, expectedIdx = *inOutIdx + size + (ssl->keys.encryptionOn ? ssl->keys.padSz : 0); +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac && ssl->keys.encryptionOn) + expectedIdx += MacSize(ssl); +#endif #if !defined(WOLFSSL_NO_SERVER) && \ defined(HAVE_SECURE_RENEGOTIATION) && \ @@ -11369,6 +11431,10 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, ssl->options.serverState = SERVER_HELLODONE_COMPLETE; if (IsEncryptionOn(ssl, 0)) { *inOutIdx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) + *inOutIdx += MacSize(ssl); + #endif } if (ssl->options.resuming) { WOLFSSL_MSG("Not resuming as thought"); @@ -11402,11 +11468,23 @@ static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx, } #endif if (IsEncryptionOn(ssl, 0)) { - /* access beyond input + size should be checked against totalSz */ - if (*inOutIdx + ssl->keys.padSz > totalSz) - return BUFFER_E; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) { + word32 digestSz = MacSize(ssl); + if (*inOutIdx + ssl->keys.padSz + digestSz > totalSz) + return BUFFER_E; + *inOutIdx += ssl->keys.padSz + digestSz; + } + else + #endif + { + /* access beyond input + size should be checked against totalSz + */ + if (*inOutIdx + ssl->keys.padSz > totalSz) + return BUFFER_E; - *inOutIdx += ssl->keys.padSz; + *inOutIdx += ssl->keys.padSz; + } } break; @@ -11917,11 +11995,22 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, /* Already saw this message and processed it. It can be ignored. */ *inOutIdx += fragSz; if(type == finished ) { - if (*inOutIdx + ssl->keys.padSz > totalSz) { - WOLFSSL_ERROR(BUFFER_E); - return BUFFER_E; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) { + word32 digestSz = MacSize(ssl); + if (*inOutIdx + ssl->keys.padSz + digestSz > totalSz) + return BUFFER_E; + *inOutIdx += ssl->keys.padSz + digestSz; + } + else + #endif + { + if (*inOutIdx + ssl->keys.padSz > totalSz) { + WOLFSSL_ERROR(BUFFER_E); + return BUFFER_E; + } + *inOutIdx += ssl->keys.padSz; } - *inOutIdx += ssl->keys.padSz; } if (IsDtlsNotSctpMode(ssl) && VerifyForDtlsMsgPoolSend(ssl, type, fragOffset)) { @@ -12921,6 +13010,15 @@ static int SanityCheckCipherText(WOLFSSL* ssl, word32 encryptSz) #ifndef WOLFSSL_AEAD_ONLY if (ssl->specs.cipher_type == block) { +#ifdef HAVE_ENCRYPT_THEN_MAC + if (ssl->options.encThenMac) { + if ((encryptSz - MacSize(ssl)) % ssl->specs.block_size) { + WOLFSSL_MSG("Block ciphertext not block size"); + return SANITY_CIPHER_E; + } + } + else +#endif if (encryptSz % ssl->specs.block_size) { WOLFSSL_MSG("Block ciphertext not block size"); return SANITY_CIPHER_E; @@ -13127,6 +13225,10 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx) } dataSz = msgSz - ivExtra - ssl->keys.padSz; +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) + dataSz -= MacSize(ssl); +#endif if (dataSz < 0) { WOLFSSL_MSG("App data buffer error, malicious input?"); SendAlert(ssl, alert_fatal, unexpected_message); @@ -13159,6 +13261,10 @@ int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx) } idx += ssl->keys.padSz; +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) + idx += MacSize(ssl); +#endif #ifdef HAVE_LIBZ /* decompress could be bigger, overwrite after verify */ @@ -13189,8 +13295,13 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type, READ_PROTO, ssl->heap); #endif - if (IsEncryptionOn(ssl, 0)) + if (IsEncryptionOn(ssl, 0)) { dataSz -= ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) + dataSz -= MacSize(ssl); + #endif + } /* make sure can read the message */ if (dataSz != ALERT_SIZE) { @@ -13232,8 +13343,13 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type, } #endif WOLFSSL_ERROR(*type); - if (IsEncryptionOn(ssl, 0)) + if (IsEncryptionOn(ssl, 0)) { *inOutIdx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) + *inOutIdx += MacSize(ssl); + #endif + } return level; } @@ -13311,6 +13427,30 @@ static int GetInputData(WOLFSSL *ssl, word32 size) return 0; } +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) +static WC_INLINE int VerifyMacEnc(WOLFSSL* ssl, const byte* input, word32 msgSz, + int content) +{ + int ret; +#ifdef HAVE_TRUNCATED_HMAC + word32 digestSz = ssl->truncated_hmac ? (byte)TRUNCATED_HMAC_SZ + : ssl->specs.hash_size; +#else + word32 digestSz = ssl->specs.hash_size; +#endif + byte verify[WC_MAX_DIGEST_SIZE]; + + WOLFSSL_MSG("Verify MAC of Encrypted Data"); + + ret = ssl->hmac(ssl, verify, input, msgSz - digestSz, -1, content, 1); + ret |= ConstantCompare(verify, input + msgSz - digestSz, digestSz); + if (ret != 0) { + return VERIFY_MAC_ERROR; + } + + return 0; +} +#endif static WC_INLINE int VerifyMac(WOLFSSL* ssl, const byte* input, word32 msgSz, int content, word32* padSz) @@ -13611,10 +13751,49 @@ int ProcessReply(WOLFSSL* ssl) } ssl->keys.padSz = 0; - ssl->options.processReply = decryptMessage; + ssl->options.processReply = verifyEncryptedMessage; startIdx = ssl->buffers.inputBuffer.idx; /* in case > 1 msg per */ FALL_THROUGH; + /* verify digest of encrypted message */ + case verifyEncryptedMessage: +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (IsEncryptionOn(ssl, 0) && ssl->keys.decryptedCur == 0 && + !atomicUser && ssl->options.encThenMac) { + ret = VerifyMacEnc(ssl, ssl->buffers.inputBuffer.buffer + + ssl->buffers.inputBuffer.idx, + ssl->curSize, ssl->curRL.type); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) + return ret; + #endif + if (ret < 0) { + WOLFSSL_MSG("VerifyMacEnc failed"); + WOLFSSL_ERROR(ret); + #ifdef WOLFSSL_DTLS + /* If in DTLS mode, if the decrypt fails for any + * reason, pretend the datagram never happened. */ + if (ssl->options.dtls) { + ssl->options.processReply = doProcessInit; + ssl->buffers.inputBuffer.idx = + ssl->buffers.inputBuffer.length; + #ifdef WOLFSSL_DTLS_DROP_STATS + ssl->macDropCount++; + #endif /* WOLFSSL_DTLS_DROP_STATS */ + } + #endif /* WOLFSSL_DTLS */ + #ifdef WOLFSSL_EXTRA_ALERTS + if (!ssl->options.dtls) + SendAlert(ssl, alert_fatal, bad_record_mac); + #endif + return DECRYPT_ERROR; + } + ssl->keys.encryptSz = ssl->curSize; + } +#endif + ssl->options.processReply = decryptMessage; + FALL_THROUGH; + /* decrypt message */ case decryptMessage: @@ -13637,24 +13816,52 @@ int ProcessReply(WOLFSSL* ssl) } if (atomicUser) { - #ifdef ATOMIC_USER - ret = ssl->ctx->DecryptVerifyCb(ssl, - in->buffer + in->idx, - in->buffer + in->idx, - ssl->curSize, ssl->curRL.type, 1, - &ssl->keys.padSz, ssl->DecryptVerifyCtx); - #endif /* ATOMIC_USER */ + #ifdef ATOMIC_USER + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) { + ret = ssl->ctx->VerifyDecryptCb(ssl, + in->buffer + in->idx, in->buffer + in->idx, + ssl->curSize - MacSize(ssl), + ssl->curRL.type, 1, &ssl->keys.padSz, + ssl->DecryptVerifyCtx); + } + else + #endif + { + ret = ssl->ctx->DecryptVerifyCb(ssl, + in->buffer + in->idx, + in->buffer + in->idx, + ssl->curSize, ssl->curRL.type, 1, + &ssl->keys.padSz, ssl->DecryptVerifyCtx); + } + #endif /* ATOMIC_USER */ } else { if (!ssl->options.tls1_3) { - #ifndef WOLFSSL_NO_TLS12 + #ifndef WOLFSSL_NO_TLS12 + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) { + word32 digestSz = MacSize(ssl); + ret = Decrypt(ssl, + in->buffer + in->idx, + in->buffer + in->idx, + ssl->curSize - digestSz); + ssl->keys.padSz = + in->buffer[in->idx + ssl->curSize - digestSz - 1]; + ssl->keys.padSz += 1; + ssl->keys.decryptedCur = 1; + } + else + #endif + { ret = Decrypt(ssl, in->buffer + in->idx, in->buffer + in->idx, ssl->curSize); - #else + } + #else ret = DECRYPT_ERROR; - #endif + #endif } else { @@ -13743,7 +13950,11 @@ int ProcessReply(WOLFSSL* ssl) ssl->curRL.type != change_cipher_spec)) #endif { - if (!atomicUser) { + if (!atomicUser +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + && !ssl->options.encThenMac +#endif + ) { ret = VerifyMac(ssl, ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx, ssl->curSize, ssl->curRL.type, @@ -13940,6 +14151,13 @@ int ProcessReply(WOLFSSL* ssl) if (IsEncryptionOn(ssl, 0) && ssl->options.handShakeDone) { ssl->buffers.inputBuffer.idx += ssl->keys.padSz; ssl->curSize -= (word16) ssl->buffers.inputBuffer.idx; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) { + word32 digestSz = MacSize(ssl); + ssl->buffers.inputBuffer.idx += digestSz; + ssl->curSize -= digestSz; + } + #endif } if (ssl->curSize != 1) { @@ -14054,12 +14272,29 @@ int ProcessReply(WOLFSSL* ssl) if (IsEncryptionOn(ssl, 0)) { WOLFSSL_MSG("Bundled encrypted messages, remove middle pad"); - if (ssl->buffers.inputBuffer.idx >= ssl->keys.padSz) { - ssl->buffers.inputBuffer.idx -= ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) { + word32 digestSz = MacSize(ssl); + if (ssl->buffers.inputBuffer.idx >= + ssl->keys.padSz + digestSz) { + ssl->buffers.inputBuffer.idx -= + ssl->keys.padSz + digestSz; + } + else { + WOLFSSL_MSG("\tmiddle padding error"); + return FATAL_ERROR; + } } - else { - WOLFSSL_MSG("\tmiddle padding error"); - return FATAL_ERROR; + else + #endif + { + if (ssl->buffers.inputBuffer.idx >= ssl->keys.padSz) { + ssl->buffers.inputBuffer.idx -= ssl->keys.padSz; + } + else { + WOLFSSL_MSG("\tmiddle padding error"); + return FATAL_ERROR; + } } } @@ -14563,7 +14798,14 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, ERROR_OUT(BUFFER_E, exit_buildmsg); } args->sz += 1; /* pad byte */ - args->pad = (args->sz - args->headerSz) % blockSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) { + args->pad = (args->sz - args->headerSz - + args->digestSz) % blockSz; + } + else + #endif + args->pad = (args->sz - args->headerSz) % blockSz; #ifdef OPENSSL_EXTRA if(args->pad != 0) #endif @@ -14634,9 +14876,16 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, } #ifndef WOLFSSL_AEAD_ONLY if (ssl->specs.cipher_type == block) { - word32 tmpIdx = args->idx + args->digestSz; + word32 tmpIdx; word32 i; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) + tmpIdx = args->idx; + else + #endif + tmpIdx = args->idx + args->digestSz; + for (i = 0; i <= args->pad; i++) output[tmpIdx++] = (byte)args->pad; /* pad byte gets pad value */ } @@ -14648,18 +14897,39 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, case BUILD_MSG_VERIFY_MAC: { /* User Record Layer Callback handling */ - #ifdef ATOMIC_USER - if (ssl->ctx->MacEncryptCb) { - ret = ssl->ctx->MacEncryptCb(ssl, output + args->idx, - output + args->headerSz + args->ivSz, inSz, type, 0, - output + args->headerSz, output + args->headerSz, args->size, - ssl->MacEncryptCtx); - goto exit_buildmsg; + #ifdef ATOMIC_USER + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) { + if (ssl->ctx->EncryptMacCb) { + ret = ssl->ctx->EncryptMacCb(ssl, output + args->idx + + args->pad + 1, type, 0, + output + args->headerSz, + output + args->headerSz, + args->size - args->digestSz, + ssl->MacEncryptCtx); + goto exit_buildmsg; + } } + else #endif + { + if (ssl->ctx->MacEncryptCb) { + ret = ssl->ctx->MacEncryptCb(ssl, output + args->idx, + output + args->headerSz + args->ivSz, inSz, + type, 0, output + args->headerSz, + output + args->headerSz, args->size, + ssl->MacEncryptCtx); + goto exit_buildmsg; + } + } + #endif #ifndef WOLFSSL_AEAD_ONLY - if (ssl->specs.cipher_type != aead) { + if (ssl->specs.cipher_type != aead + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + && !ssl->options.encThenMac + #endif + ) { #ifdef HAVE_TRUNCATED_HMAC if (ssl->truncated_hmac && ssl->specs.hash_size > args->digestSz) { @@ -14701,9 +14971,65 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, FALL_THROUGH; case BUILD_MSG_ENCRYPT: { - ret = Encrypt(ssl, output + args->headerSz, output + args->headerSz, args->size, - asyncOkay); - break; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) { + ret = Encrypt(ssl, output + args->headerSz, + output + args->headerSz, + args->size - args->digestSz, asyncOkay); + } + else + #endif + { + ret = Encrypt(ssl, output + args->headerSz, + output + args->headerSz, args->size, asyncOkay); + } + if (ret != 0) + goto exit_buildmsg; + ssl->options.buildMsgState = BUILD_MSG_ENCRYPTED_VERIFY_MAC; + } + FALL_THROUGH; + case BUILD_MSG_ENCRYPTED_VERIFY_MAC: + { + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) { + WOLFSSL_MSG("Calculate MAC of Encrypted Data"); + + #ifdef HAVE_TRUNCATED_HMAC + if (ssl->truncated_hmac && + ssl->specs.hash_size > args->digestSz) { + #ifdef WOLFSSL_SMALL_STACK + byte* hmac = NULL; + #else + byte hmac[WC_MAX_DIGEST_SIZE]; + #endif + + #ifdef WOLFSSL_SMALL_STACK + hmac = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, ssl->heap, + DYNAMIC_TYPE_DIGEST); + if (hmac == NULL) + ERROR_OUT(MEMORY_E, exit_buildmsg); + #endif + + ret = ssl->hmac(ssl, hmac, output + args->headerSz, + args->ivSz + inSz + args->pad + 1, -1, type, + 0); + XMEMCPY(output + args->idx + args->pad + 1, hmac, + args->digestSz); + + #ifdef WOLFSSL_SMALL_STACK + XFREE(hmac, ssl->heap, DYNAMIC_TYPE_DIGEST); + #endif + } + else + #endif + { + ret = ssl->hmac(ssl, output + args->idx + args->pad + 1, + output + args->headerSz, + args->ivSz + inSz + args->pad + 1, -1, type, + 0); + } + } + #endif /* HAVE_ENCRYPT_THEN_MAC && !WOLFSSL_AEAD_ONLY */ } } @@ -18396,6 +18722,10 @@ exit_dpk: if (IsEncryptionOn(ssl, 0)) { *inOutIdx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac && ssl->specs.cipher_type == block) + *inOutIdx += MacSize(ssl); + #endif } #ifdef HAVE_SECRET_CALLBACK @@ -18652,8 +18982,13 @@ exit_dpk: ssl->options.sendVerify = SEND_BLANK_CERT; } - if (IsEncryptionOn(ssl, 0)) + if (IsEncryptionOn(ssl, 0)) { *inOutIdx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) + *inOutIdx += MacSize(ssl); + #endif + } WOLFSSL_LEAVE("DoCertificateRequest", 0); WOLFSSL_END(WC_FUNC_CERTIFICATE_REQUEST_DO); @@ -19680,6 +20015,10 @@ static int DoServerKeyExchange(WOLFSSL* ssl, const byte* input, { if (IsEncryptionOn(ssl, 0)) { args->idx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) + args->idx += MacSize(ssl); + #endif } /* QSH extensions */ @@ -21824,6 +22163,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (IsEncryptionOn(ssl, 0)) { *inOutIdx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) + *inOutIdx += MacSize(ssl); + #endif } ssl->expect_session_ticket = 0; @@ -25019,6 +25362,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, { if (IsEncryptionOn(ssl, 0)) { args->idx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) + args->idx += MacSize(ssl); + #endif } ssl->options.havePeerVerify = 1; @@ -26625,6 +26972,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, { if (IsEncryptionOn(ssl, 0)) { args->idx += ssl->keys.padSz; + #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.encThenMac) + args->idx += MacSize(ssl); + #endif } #ifdef HAVE_QSH diff --git a/src/keys.c b/src/keys.c index 42e40c7cb..9282a2bc2 100644 --- a/src/keys.c +++ b/src/keys.c @@ -2208,6 +2208,11 @@ int SetCipherSpecs(WOLFSSL* ssl) #endif } +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (IsAtLeastTLSv1_3(ssl->version) || ssl->specs.cipher_type != block) + ssl->options.encThenMac = 0; +#endif + #if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_AEAD_ONLY) if (ssl->options.dtls) ssl->hmac = TLS_hmac; diff --git a/src/ssl.c b/src/ssl.c index 6d6a682a6..8dbbfb57a 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -3057,6 +3057,84 @@ void* wolfSSL_GetDecryptVerifyCtx(WOLFSSL* ssl) return NULL; } +/** + * Set the callback, against the context, that encrypts then MACs. + * + * ctx SSL/TLS context. + * cb Callback function to use with Encrypt-Then-MAC. + */ +void wolfSSL_CTX_SetEncryptMacCb(WOLFSSL_CTX* ctx, CallbackEncryptMac cb) +{ + if (ctx) + ctx->EncryptMacCb = cb; +} + +/** + * Set the context to use with callback that encrypts then MACs. + * + * ssl SSL/TLS object. + * ctx Callback function's context. + */ +void wolfSSL_SetEncryptMacCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->EncryptMacCtx = ctx; +} + +/** + * Get the context being used with callback that encrypts then MACs. + * + * ssl SSL/TLS object. + * returns callback function's context or NULL if SSL/TLS object is NULL. + */ +void* wolfSSL_GetEncryptMacCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->EncryptMacCtx; + + return NULL; +} + + +/** + * Set the callback, against the context, that MAC verifies then decrypts. + * + * ctx SSL/TLS context. + * cb Callback function to use with Encrypt-Then-MAC. + */ +void wolfSSL_CTX_SetVerifyDecryptCb(WOLFSSL_CTX* ctx, CallbackVerifyDecrypt cb) +{ + if (ctx) + ctx->VerifyDecryptCb = cb; +} + +/** + * Set the context to use with callback that MAC verifies then decrypts. + * + * ssl SSL/TLS object. + * ctx Callback function's context. + */ +void wolfSSL_SetVerifyDecryptCtx(WOLFSSL* ssl, void *ctx) +{ + if (ssl) + ssl->VerifyDecryptCtx = ctx; +} + +/** + * Get the context being used with callback that MAC verifies then decrypts. + * + * ssl SSL/TLS object. + * returns callback function's context or NULL if SSL/TLS object is NULL. + */ +void* wolfSSL_GetVerifyDecryptCtx(WOLFSSL* ssl) +{ + if (ssl) + return ssl->VerifyDecryptCtx; + + return NULL; +} + + const byte* wolfSSL_GetClientWriteKey(WOLFSSL* ssl) { @@ -3125,10 +3203,12 @@ int wolfSSL_GetCipherType(WOLFSSL* ssl) if (ssl == NULL) return BAD_FUNC_ARG; +#ifndef WOLFSSL_AEAD_ONLY if (ssl->specs.cipher_type == block) return WOLFSSL_BLOCK_TYPE; if (ssl->specs.cipher_type == stream) return WOLFSSL_STREAM_TYPE; +#endif if (ssl->specs.cipher_type == aead) return WOLFSSL_AEAD_TYPE; @@ -38027,3 +38107,34 @@ int wolfSSL_X509_REQ_set_pubkey(WOLFSSL_X509 *req, WOLFSSL_EVP_PKEY *pkey) return wolfSSL_X509_set_pubkey(req, pkey); } #endif + +#ifdef HAVE_ENCRYPT_THEN_MAC +/** + * Sets whether Encrypt-Then-MAC extension can be negotitated against context. + * The default value: enabled. + * + * ctx SSL/TLS context. + * set Whether to allow or not: 1 is allow and 0 is disallow. + * returns WOLFSSL_SUCCESS + */ +int wolfSSL_CTX_AllowEncryptThenMac(WOLFSSL_CTX *ctx, int set) +{ + ctx->disallowEncThenMac = !set; + return WOLFSSL_SUCCESS; +} + +/** + * Sets whether Encrypt-Then-MAC extension can be negotitated against context. + * The default value comes from context. + * + * ctx SSL/TLS context. + * set Whether to allow or not: 1 is allow and 0 is disallow. + * returns WOLFSSL_SUCCESS + */ +int wolfSSL_AllowEncryptThenMac(WOLFSSL *ssl, int set) +{ + ssl->options.disallowEncThenMac = !set; + return WOLFSSL_SUCCESS; +} +#endif + diff --git a/src/tls.c b/src/tls.c index ab54a9516..e362a5a8c 100644 --- a/src/tls.c +++ b/src/tls.c @@ -5568,6 +5568,148 @@ int TLSX_UseQSHScheme(TLSX** extensions, word16 name, byte* pKey, word16 pkeySz, #endif /* HAVE_QSH */ +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) +/******************************************************************************/ +/* Encrypt-then-MAC */ +/******************************************************************************/ + +#ifndef WOLFSSL_NO_TLS12 +static int TLSX_EncryptThenMac_Use(WOLFSSL* ssl); + +/** + * Get the size of the Encrypt-Then-MAC extension. + * + * msgType Type of message to put extension into. + * pSz Size of extension data. + * return SANITY_MSG_E when the message is not allowed to have extension and + * 0 otherwise. + */ +static int TLSX_EncryptThenMac_GetSize(byte msgType, word16* pSz) +{ + (void)pSz; + + if (msgType != client_hello && msgType != server_hello) { + return SANITY_MSG_E; + } + + /* Empty extension */ + + return 0; +} + +/** + * Write the Encrypt-Then-MAC extension. + * + * data Unused + * output Extension data buffer. Unused. + * msgType Type of message to put extension into. + * pSz Size of extension data. + * return SANITY_MSG_E when the message is not allowed to have extension and + * 0 otherwise. + */ +static int TLSX_EncryptThenMac_Write(void* data, byte* output, byte msgType, + word16* pSz) +{ + (void)data; + (void)output; + (void)pSz; + + if (msgType != client_hello && msgType != server_hello) { + return SANITY_MSG_E; + } + + /* Empty extension */ + + return 0; +} + +/** + * Parse the Encrypt-Then-MAC extension. + * + * ssl SSL object + * input Extension data buffer. + * length Length of this extension's data. + * msgType Type of message to extension appeared in. + * return SANITY_MSG_E when the message is not allowed to have extension, + * BUFFER_ERROR when the extension's data is invalid, + * MEMORY_E when unable to allocate memory and + * 0 otherwise. + */ +static int TLSX_EncryptThenMac_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte msgType) +{ + int ret; + + (void)input; + + if (msgType != client_hello && msgType != server_hello) { + return SANITY_MSG_E; + } + + /* Empty extension */ + if (length != 0) + return BUFFER_ERROR; + + if (msgType == client_hello) { + /* Check the user hasn't disallowed use of Encrypt-Then-Mac. */ + if (!ssl->options.disallowEncThenMac) { + ssl->options.encThenMac = 1; + /* Set the extension reply. */ + ret = TLSX_EncryptThenMac_Use(ssl); + if (ret != 0) + return ret; + TLSX_SetResponse(ssl, TLSX_ENCRYPT_THEN_MAC); + } + return 0; + } + + /* Server Hello */ + if (ssl->options.disallowEncThenMac) + return SANITY_MSG_E; + + ssl->options.encThenMac = 1; + return 0; + +} + +/** + * Add the Encrypt-Then-MAC extension to list. + * + * ssl SSL object + * return MEMORY_E when unable to allocate memory and 0 otherwise. + */ +static int TLSX_EncryptThenMac_Use(WOLFSSL* ssl) +{ + int ret = 0; + TLSX* extension; + + /* Find the Encrypt-Then-Mac extension if it exists. */ + extension = TLSX_Find(ssl->extensions, TLSX_ENCRYPT_THEN_MAC); + if (extension == NULL) { + /* Push new Encrypt-Then-Mac extension. */ + ret = TLSX_Push(&ssl->extensions, TLSX_ENCRYPT_THEN_MAC, NULL, + ssl->heap); + if (ret != 0) + return ret; + } + + return 0; +} + +#define ETM_GET_SIZE TLSX_EncryptThenMac_GetSize +#define ETM_WRITE TLSX_EncryptThenMac_Write +#define ETM_PARSE TLSX_EncryptThenMac_Parse + +#else + +#define ETM_GET_SIZE(a, b) 0 +#define ETM_WRITE(a, b, c, d) 0 +#define ETM_PARSE(a, b, c, d) 0 + +#endif /* !WOLFSSL_NO_TLS12 */ + +#endif /* HAVE_ENCRYPT_THEN_MAC && !WOLFSSL_AEAD_ONLY */ + /******************************************************************************/ /* Supported Versions */ /******************************************************************************/ @@ -8721,6 +8863,10 @@ void TLSX_FreeAll(TLSX* list, void* heap) case TLSX_SIGNATURE_ALGORITHMS: break; #endif +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + case TLSX_ENCRYPT_THEN_MAC: + break; +#endif #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: break; @@ -8858,6 +9004,11 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType, length += SA_GET_SIZE(extension->data); break; #endif +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + case TLSX_ENCRYPT_THEN_MAC: + ret = ETM_GET_SIZE(msgType, &length); + break; +#endif /* HAVE_ENCRYPT_THEN_MAC */ #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: ret = SV_GET_SIZE(extension->data, msgType, &length); @@ -9021,6 +9172,12 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore, offset += SA_WRITE(extension->data, output + offset); break; #endif +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + case TLSX_ENCRYPT_THEN_MAC: + WOLFSSL_MSG("Encrypt-Then-Mac extension to write"); + ret = ETM_WRITE(extension->data, output, msgType, &offset); + break; +#endif /* HAVE_ENCRYPT_THEN_MAC */ #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: WOLFSSL_MSG("Supported Versions extension to write"); @@ -9560,6 +9717,14 @@ int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer) } #endif +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (!ssl->options.disallowEncThenMac) { + ret = TLSX_EncryptThenMac_Use(ssl); + if (ret != 0) + return ret; + } +#endif + #if (defined(HAVE_ECC) || defined(HAVE_CURVE25519)) && \ defined(HAVE_SUPPORTED_CURVES) if (!ssl->options.userCurves && !ssl->ctx->userCurves) { @@ -10552,6 +10717,19 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType, ret = SA_PARSE(ssl, input + offset, size, isRequest, suites); break; #endif + +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + case TLSX_ENCRYPT_THEN_MAC: + WOLFSSL_MSG("Encrypt-Then-Mac extension received"); + + /* Ignore for TLS 1.3+ */ + if (IsAtLeastTLSv1_3(ssl->version)) + break; + + ret = ETM_PARSE(ssl, input + offset, size, msgType); + break; +#endif /* HAVE_ENCRYPT_THEN_MAC */ + #ifdef WOLFSSL_TLS13 case TLSX_SUPPORTED_VERSIONS: WOLFSSL_MSG("Skipping Supported Versions - already processed"); diff --git a/tests/test.conf b/tests/test.conf index 43092d16b..445e30b98 100644 --- a/tests/test.conf +++ b/tests/test.conf @@ -2470,3 +2470,60 @@ # client TLSv1.2 with Trusted CA Indication (pre-shared) -v 3 -5 + +# server TLSv1.2 with block cipher and no ETM +-v 3 +-l ECDHE-RSA-AES128-SHA256 +-H disallowETM + +# client TLSv1.2 with block cipher +-v 3 +-l ECDHE-RSA-AES128-SHA256 + +# server TLSv1.2 with block cipher +-v 3 +-l ECDHE-RSA-AES128-SHA256 + +# client TLSv1.2 with block cipher and no ETM +-v 3 +-l ECDHE-RSA-AES128-SHA256 +-H disallowETM + +# server TLSv1.2 with block cipher and no ETM +-v 3 +-l ECDHE-RSA-AES128-SHA256 +-H disallowETM + +# client TLSv1.2 with block cipher and no ETM +-v 3 +-l ECDHE-RSA-AES128-SHA256 +-H disallowETM + +# server TLSv1.2 with block cipher and SHA-1 and no ETM +-v 3 +-l ECDHE-RSA-AES128-SHA +-H disallowETM + +# client TLSv1.2 with block cipher and SHA-1 and no ETM +-v 3 +-l ECDHE-RSA-AES128-SHA +-H disallowETM + +# server TLSv1.2 with block cipher +-v 3 +-l ECDHE-RSA-AES128-SHA256 + +# client TLSv1.2 with block cipher - atomic user (use callback) +-v 3 +-l ECDHE-RSA-AES128-SHA256 +-U + +# server TLSv1.2 with block cipher and no ETM +-v 3 +-l ECDHE-RSA-AES128-SHA256 +-H disallowETM + +# client TLSv1.2 with block cipher - atomic user (use callback) +-v 3 +-l ECDHE-RSA-AES128-SHA256 +-U diff --git a/wolfssl/internal.h b/wolfssl/internal.h index a0dc42b57..9ad7bb7ce 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2099,6 +2099,9 @@ typedef enum { #endif TLSX_APPLICATION_LAYER_PROTOCOL = 0x0010, /* a.k.a. ALPN */ TLSX_STATUS_REQUEST_V2 = 0x0011, /* a.k.a. OCSP stapling v2 */ +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + TLSX_ENCRYPT_THEN_MAC = 0x0016, /* RFC 7366 */ +#endif TLSX_QUANTUM_SAFE_HYBRID = 0x0018, /* a.k.a. QSH */ TLSX_SESSION_TICKET = 0x0023, #ifdef WOLFSSL_TLS13 @@ -2621,6 +2624,9 @@ struct WOLFSSL_CTX { #ifdef HAVE_SECURE_RENEGOTIATION byte useSecureReneg:1; /* when set will set WOLFSSL objects generated to enable */ #endif +#ifdef HAVE_ENCRYPT_THEN_MAC + byte disallowEncThenMac:1; /* Don't do Encrypt-Then-MAC */ +#endif #ifdef WOLFSSL_MULTICAST byte haveMcast; /* multicast requested */ byte mcastID; /* multicast group ID */ @@ -2748,6 +2754,10 @@ struct WOLFSSL_CTX { #ifdef ATOMIC_USER CallbackMacEncrypt MacEncryptCb; /* Atomic User Mac/Encrypt Cb */ CallbackDecryptVerify DecryptVerifyCb; /* Atomic User Decrypt/Verify Cb */ + #ifdef HAVE_ENCRYPT_THEN_MAC + CallbackEncryptMac EncryptMacCb; /* Atomic User Mac/Enc Cb */ + CallbackVerifyDecrypt VerifyDecryptCb; /* Atomic User Dec/Verify Cb */ + #endif #endif #ifdef HAVE_PK_CALLBACKS #ifdef HAVE_ECC @@ -3228,6 +3238,7 @@ enum buildMsgState { BUILD_MSG_HASH, BUILD_MSG_VERIFY_MAC, BUILD_MSG_ENCRYPT, + BUILD_MSG_ENCRYPTED_VERIFY_MAC, }; /* sub-states for cipher operations */ @@ -3352,6 +3363,10 @@ typedef struct Options { #ifdef SINGLE_THREADED word16 ownSuites:1; /* if suites are malloced in ssl object */ #endif +#ifdef HAVE_ENCRYPT_THEN_MAC + word16 disallowEncThenMac:1; /* Don't do Encrypt-Then-MAC */ + word16 encThenMac:1; /* Doing Encrypt-Then-MAC */ +#endif /* need full byte values for this section */ byte processReply; /* nonblocking resume */ @@ -3985,6 +4000,10 @@ struct WOLFSSL { #ifdef ATOMIC_USER void* MacEncryptCtx; /* Atomic User Mac/Encrypt Callback Context */ void* DecryptVerifyCtx; /* Atomic User Decrypt/Verify Callback Context */ + #ifdef HAVE_ENCRYPT_THEN_MAC + void* EncryptMacCtx; /* Atomic User Encrypt/Mac Callback Ctx */ + void* VerifyDecryptCtx; /* Atomic User Verify/Decrypt Callback Ctx */ + #endif #endif #ifdef HAVE_PK_CALLBACKS #ifdef HAVE_ECC diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index a51652761..5e88c9e32 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1935,10 +1935,26 @@ typedef int (*CallbackDecryptVerify)(WOLFSSL* ssl, unsigned int decSz, int content, int verify, unsigned int* padSz, void* ctx); WOLFSSL_API void wolfSSL_CTX_SetDecryptVerifyCb(WOLFSSL_CTX*, - CallbackDecryptVerify); + CallbackDecryptVerify); WOLFSSL_API void wolfSSL_SetDecryptVerifyCtx(WOLFSSL* ssl, void *ctx); WOLFSSL_API void* wolfSSL_GetDecryptVerifyCtx(WOLFSSL* ssl); +typedef int (*CallbackEncryptMac)(WOLFSSL* ssl, unsigned char* macOut, + int content, int macVerify, unsigned char* encOut, + const unsigned char* encIn, unsigned int encSz, void* ctx); +WOLFSSL_API void wolfSSL_CTX_SetEncryptMacCb(WOLFSSL_CTX*, CallbackEncryptMac); +WOLFSSL_API void wolfSSL_SetEncryptMacCtx(WOLFSSL* ssl, void *ctx); +WOLFSSL_API void* wolfSSL_GetEncryptMacCtx(WOLFSSL* ssl); + +typedef int (*CallbackVerifyDecrypt)(WOLFSSL* ssl, + unsigned char* decOut, const unsigned char* decIn, + unsigned int decSz, int content, int verify, unsigned int* padSz, + void* ctx); +WOLFSSL_API void wolfSSL_CTX_SetVerifyDecryptCb(WOLFSSL_CTX*, + CallbackVerifyDecrypt); +WOLFSSL_API void wolfSSL_SetVerifyDecryptCtx(WOLFSSL* ssl, void *ctx); +WOLFSSL_API void* wolfSSL_GetVerifyDecryptCtx(WOLFSSL* ssl); + WOLFSSL_API const unsigned char* wolfSSL_GetMacSecret(WOLFSSL*, int); WOLFSSL_API const unsigned char* wolfSSL_GetClientWriteKey(WOLFSSL*); WOLFSSL_API const unsigned char* wolfSSL_GetClientWriteIV(WOLFSSL*); @@ -3186,6 +3202,11 @@ WOLFSSL_API unsigned long wolfSSL_X509_subject_name_hash(const WOLFSSL_X509* x5 WOLFSSL_API int wolfSSL_CTX_IsPrivatePkSet(WOLFSSL_CTX* ctx); #endif +#ifdef HAVE_ENCRYPT_THEN_MAC +WOLFSSL_API int wolfSSL_CTX_AllowEncryptThenMac(WOLFSSL_CTX *, int); +WOLFSSL_API int wolfSSL_AllowEncryptThenMac(WOLFSSL *s, int); +#endif + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/test.h b/wolfssl/test.h index 3cbdba849..69b7bddd8 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -1975,7 +1975,7 @@ static WC_INLINE void StackTrap(void) #endif /* STACK_TRAP */ -#ifdef ATOMIC_USER +#if defined(ATOMIC_USER) && !defined(WOLFSSL_AEAD_ONLY) /* Atomic Encrypt Context example */ typedef struct AtomicEncCtx { @@ -2016,6 +2016,9 @@ static WC_INLINE int myMacEncryptCb(WOLFSSL* ssl, unsigned char* macOut, /* hmac, not needed if aead mode */ wolfSSL_SetTlsHmacInner(ssl, myInner, macInSz, macContent, macVerify); + ret = wc_HmacInit(&hmac, NULL, INVALID_DEVID); + if (ret != 0) + return ret; ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl), wolfSSL_GetMacSecret(ssl, macVerify), wolfSSL_GetHmacSize(ssl)); if (ret != 0) @@ -2133,6 +2136,9 @@ static WC_INLINE int myDecryptVerifyCb(WOLFSSL* ssl, wolfSSL_SetTlsHmacInner(ssl, myInner, macInSz, macContent, macVerify); + ret = wc_HmacInit(&hmac, NULL, INVALID_DEVID); + if (ret != 0) + return ret; ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl), wolfSSL_GetMacSecret(ssl, macVerify), digestSz); if (ret != 0) @@ -2156,6 +2162,162 @@ static WC_INLINE int myDecryptVerifyCb(WOLFSSL* ssl, return ret; } +#if defined(HAVE_ENCRYPT_THEN_MAC) + +static WC_INLINE int myEncryptMacCb(WOLFSSL* ssl, unsigned char* macOut, + int content, int macVerify, unsigned char* encOut, + const unsigned char* encIn, unsigned int encSz, void* ctx) +{ + int ret; + Hmac hmac; + AtomicEncCtx* encCtx = (AtomicEncCtx*)ctx; + byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ]; + const char* tlsStr = "TLS"; + + /* example supports (d)tls aes */ + if (wolfSSL_GetBulkCipher(ssl) != wolfssl_aes) { + printf("myMacEncryptCb not using AES\n"); + return -1; + } + + if (strstr(wolfSSL_get_version(ssl), tlsStr) == NULL) { + printf("myMacEncryptCb not using (D)TLS\n"); + return -1; + } + + /* encrypt setup on first time */ + if (encCtx->keySetup == 0) { + int keyLen = wolfSSL_GetKeySize(ssl); + const byte* key; + const byte* iv; + + if (wolfSSL_GetSide(ssl) == WOLFSSL_CLIENT_END) { + key = wolfSSL_GetClientWriteKey(ssl); + iv = wolfSSL_GetClientWriteIV(ssl); + } + else { + key = wolfSSL_GetServerWriteKey(ssl); + iv = wolfSSL_GetServerWriteIV(ssl); + } + + ret = wc_AesSetKey(&encCtx->aes, key, keyLen, iv, AES_ENCRYPTION); + if (ret != 0) { + printf("AesSetKey failed in myMacEncryptCb\n"); + return ret; + } + encCtx->keySetup = 1; + } + + /* encrypt */ + ret = wc_AesCbcEncrypt(&encCtx->aes, encOut, encIn, encSz); + if (ret != 0) + return ret; + + /* Reconstruct record header. */ + wolfSSL_SetTlsHmacInner(ssl, myInner, encSz, content, macVerify); + + ret = wc_HmacInit(&hmac, NULL, INVALID_DEVID); + if (ret != 0) + return ret; + ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl), + wolfSSL_GetMacSecret(ssl, macVerify), wolfSSL_GetHmacSize(ssl)); + if (ret != 0) + return ret; + ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner)); + if (ret != 0) + return ret; + ret = wc_HmacUpdate(&hmac, encOut, encSz); + if (ret != 0) + return ret; + return wc_HmacFinal(&hmac, macOut); +} + + +static WC_INLINE int myVerifyDecryptCb(WOLFSSL* ssl, + unsigned char* decOut, const unsigned char* decIn, + unsigned int decSz, int content, int macVerify, + unsigned int* padSz, void* ctx) +{ + AtomicDecCtx* decCtx = (AtomicDecCtx*)ctx; + int ret = 0; + int digestSz = wolfSSL_GetHmacSize(ssl); + Hmac hmac; + byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ]; + byte verify[WC_MAX_DIGEST_SIZE]; + const char* tlsStr = "TLS"; + + /* example supports (d)tls aes */ + if (wolfSSL_GetBulkCipher(ssl) != wolfssl_aes) { + printf("myMacEncryptCb not using AES\n"); + return -1; + } + + if (strstr(wolfSSL_get_version(ssl), tlsStr) == NULL) { + printf("myMacEncryptCb not using (D)TLS\n"); + return -1; + } + + /* Reconstruct record header. */ + wolfSSL_SetTlsHmacInner(ssl, myInner, decSz, content, macVerify); + + ret = wc_HmacInit(&hmac, NULL, INVALID_DEVID); + if (ret != 0) + return ret; + ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl), + wolfSSL_GetMacSecret(ssl, macVerify), digestSz); + if (ret != 0) + return ret; + ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner)); + if (ret != 0) + return ret; + ret = wc_HmacUpdate(&hmac, decIn, decSz); + if (ret != 0) + return ret; + ret = wc_HmacFinal(&hmac, verify); + if (ret != 0) + return ret; + + if (XMEMCMP(verify, decOut + decSz, digestSz) != 0) { + printf("myDecryptVerify verify failed\n"); + return -1; + } + + /* decrypt */ + if (decCtx->keySetup == 0) { + int keyLen = wolfSSL_GetKeySize(ssl); + const byte* key; + const byte* iv; + + /* decrypt is from other side (peer) */ + if (wolfSSL_GetSide(ssl) == WOLFSSL_SERVER_END) { + key = wolfSSL_GetClientWriteKey(ssl); + iv = wolfSSL_GetClientWriteIV(ssl); + } + else { + key = wolfSSL_GetServerWriteKey(ssl); + iv = wolfSSL_GetServerWriteIV(ssl); + } + + ret = wc_AesSetKey(&decCtx->aes, key, keyLen, iv, AES_DECRYPTION); + if (ret != 0) { + printf("AesSetKey failed in myDecryptVerifyCb\n"); + return ret; + } + decCtx->keySetup = 1; + } + + /* decrypt */ + ret = wc_AesCbcDecrypt(&decCtx->aes, decOut, decIn, decSz); + if (ret != 0) + return ret; + + *padSz = *(decOut + decSz - 1) + 1; + + return 0; +} + +#endif + static WC_INLINE void SetupAtomicUser(WOLFSSL_CTX* ctx, WOLFSSL* ssl) { @@ -2179,6 +2341,14 @@ static WC_INLINE void SetupAtomicUser(WOLFSSL_CTX* ctx, WOLFSSL* ssl) wolfSSL_CTX_SetDecryptVerifyCb(ctx, myDecryptVerifyCb); wolfSSL_SetDecryptVerifyCtx(ssl, decCtx); + +#if defined(HAVE_ENCRYPT_THEN_MAC) + wolfSSL_CTX_SetEncryptMacCb(ctx, myEncryptMacCb); + wolfSSL_SetEncryptMacCtx(ssl, encCtx); + + wolfSSL_CTX_SetVerifyDecryptCb(ctx, myVerifyDecryptCb); + wolfSSL_SetVerifyDecryptCtx(ssl, decCtx); +#endif } @@ -2187,6 +2357,8 @@ static WC_INLINE void FreeAtomicUser(WOLFSSL* ssl) AtomicEncCtx* encCtx = (AtomicEncCtx*)wolfSSL_GetMacEncryptCtx(ssl); AtomicDecCtx* decCtx = (AtomicDecCtx*)wolfSSL_GetDecryptVerifyCtx(ssl); + /* Encrypt-Then-MAC callbacks use same contexts. */ + free(decCtx); free(encCtx); }