diff --git a/IDE/WIN/user_settings.h b/IDE/WIN/user_settings.h index 30ec8f000..a3146861f 100755 --- a/IDE/WIN/user_settings.h +++ b/IDE/WIN/user_settings.h @@ -28,6 +28,7 @@ #define WOLFSSL_RIPEMD #define WOLFSSL_SHA512 #define NO_PSK + #define HAVE_EXTENDED_MASTER #define WOLFSSL_SNIFFER #else /* The servers and clients */ diff --git a/configure.ac b/configure.ac index bc1be8374..e74edd327 100644 --- a/configure.ac +++ b/configure.ac @@ -1975,6 +1975,18 @@ then AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_SESSION_TICKET" fi +# Extended Master Secret Extension +AC_ARG_ENABLE([extended-master], + [AS_HELP_STRING([--enable-extended-master],[Enable Extended Master Secret (default: enabled)])], + [ ENABLED_EXTENDED_MASTER=$enableval ], + [ ENABLED_EXTENDED_MASTER=yes ] + ) + +if test "x$ENABLED_EXTENDED_MASTER" = "xyes" +then + AM_CFLAGS="$AM_CFLAGS -DHAVE_EXTENDED_MASTER" +fi + # TLS Extensions AC_ARG_ENABLE([tlsx], [ --enable-tlsx Enable all TLS Extensions (default: disabled)], @@ -3217,6 +3229,7 @@ echo " * Maximum Fragment Length: $ENABLED_MAX_FRAGMENT" echo " * Truncated HMAC: $ENABLED_TRUNCATED_HMAC" echo " * Supported Elliptic Curves: $ENABLED_SUPPORTED_CURVES" echo " * Session Ticket: $ENABLED_SESSION_TICKET" +echo " * Extended Master Secret: $ENABLED_EXTENDED_MASTER" echo " * Renegotiation Indication: $ENABLED_RENEGOTIATION_INDICATION" echo " * Secure Renegotiation: $ENABLED_SECURE_RENEGOTIATION" echo " * All TLS Extensions: $ENABLED_TLSX" diff --git a/examples/client/client.c b/examples/client/client.c index ae61c1a5f..14ef26245 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -494,6 +494,9 @@ static void Usage(void) #ifdef HAVE_TRUNCATED_HMAC printf("-T Use Truncated HMAC\n"); #endif +#ifdef HAVE_EXTENDED_MASTER + printf("-n Disable Extended Master Secret\n"); +#endif #ifdef HAVE_OCSP printf("-o Perform OCSP lookup on peer certificate\n"); printf("-O Perform OCSP lookup using as responder\n"); @@ -609,6 +612,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) byte statusRequest = 0; #endif +#ifdef HAVE_EXTENDED_MASTER + byte disableExtMasterSecret = 0; +#endif #ifdef HAVE_OCSP @@ -651,7 +657,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #ifndef WOLFSSL_VXWORKS while ((ch = mygetopt(argc, argv, - "?gdeDuGsmNrwRitfxXUPCVh:p:v:l:A:c:k:Z:b:zS:F:L:ToO:aB:W:E:M:q:")) + "?gdeDuGsmNrwRitfxXUPCVh:p:v:l:A:c:k:Z:b:zS:F:L:TnoO:aB:W:E:M:q:")) != -1) { switch (ch) { case '?' : @@ -857,6 +863,12 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) #endif break; + case 'n' : + #ifdef HAVE_EXTENDED_MASTER + disableExtMasterSecret = 1; + #endif + break; + case 'W' : #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) @@ -1233,6 +1245,11 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) if (wolfSSL_CTX_UseSessionTicket(ctx) != SSL_SUCCESS) err_sys("UseSessionTicket failed"); #endif +#ifdef HAVE_EXTENDED_MASTER + if (disableExtMasterSecret) + if (wolfSSL_CTX_DisableExtendedMasterSecret(ctx) != SSL_SUCCESS) + err_sys("DisableExtendedMasterSecret failed"); +#endif if (benchmark) { ((func_args*)args)->return_code = @@ -1555,6 +1572,32 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) wolfSSL_set_SessionTicket_cb(sslResume, sessionTicketCB, (void*)"resumed session"); #endif + #ifdef HAVE_SUPPORTED_CURVES /* add curves to supported curves extension */ + if (wolfSSL_UseSupportedCurve(sslResume, WOLFSSL_ECC_SECP256R1) + != SSL_SUCCESS) { + err_sys("unable to set curve secp256r1"); + } + if (wolfSSL_UseSupportedCurve(sslResume, WOLFSSL_ECC_SECP384R1) + != SSL_SUCCESS) { + err_sys("unable to set curve secp384r1"); + } + if (wolfSSL_UseSupportedCurve(sslResume, WOLFSSL_ECC_SECP521R1) + != SSL_SUCCESS) { + err_sys("unable to set curve secp521r1"); + } + if (wolfSSL_UseSupportedCurve(sslResume, WOLFSSL_ECC_SECP224R1) + != SSL_SUCCESS) { + err_sys("unable to set curve secp224r1"); + } + if (wolfSSL_UseSupportedCurve(sslResume, WOLFSSL_ECC_SECP192R1) + != SSL_SUCCESS) { + err_sys("unable to set curve secp192r1"); + } + if (wolfSSL_UseSupportedCurve(sslResume, WOLFSSL_ECC_SECP160R1) + != SSL_SUCCESS) { + err_sys("unable to set curve secp160r1"); + } + #endif #ifndef WOLFSSL_CALLBACKS if (nonBlocking) { diff --git a/scripts/resume.test b/scripts/resume.test index 337c30a76..6b6ad488e 100755 --- a/scripts/resume.test +++ b/scripts/resume.test @@ -5,6 +5,7 @@ # need a unique resume port since may run the same time as testsuite # use server port zero hack to get one resume_string="reused" +ems_string="Extended\ Master\ Secret" resume_port=0 no_pid=-1 server_pid=$no_pid @@ -41,57 +42,72 @@ do_trap() { exit -1 } +do_test() { + echo -e "\nStarting example server for resume test...\n" + + remove_ready_file + ./examples/server/server -r -R $ready_file -p $resume_port & + server_pid=$! + + while [ ! -s $ready_file -a "$counter" -lt 20 ]; do + echo -e "waiting for ready file..." + sleep 0.1 + counter=$((counter+ 1)) + done + + if test -e $ready_file; then + echo -e "found ready file, starting client..." + else + echo -e "NO ready file ending test..." + do_cleanup + exit 1 + fi + + # get created port 0 ephemeral port + resume_port=`cat $ready_file` + + capture_out=$(./examples/client/client $1 -r -p $resume_port 2>&1) + client_result=$? + + if [ $client_result != 0 ] + then + echo -e "client failed!" + do_cleanup + exit 1 + fi + + wait $server_pid + server_result=$? + remove_ready_file + + if [ $server_result != 0 ] + then + echo -e "client failed!" + exit 1 + fi + + case "$capture_out" in + *$resume_string*) + echo "resumed session" ;; + *) + echo "did NOT resume session as expected" + exit 1 + ;; + esac +} + trap do_trap INT TERM -echo -e "\nStarting example server for resume test...\n" +do_test -remove_ready_file -./examples/server/server -r -R $ready_file -p $resume_port & -server_pid=$! - -while [ ! -s $ready_file -a "$counter" -lt 20 ]; do - echo -e "waiting for ready file..." - sleep 0.1 - counter=$((counter+ 1)) -done - -if test -e $ready_file; then - echo -e "found ready file, starting client..." -else - echo -e "NO ready file ending test..." - do_cleanup - exit 1 -fi - -# get created port 0 ephemeral port -resume_port=`cat $ready_file` - -capture_out=$(./examples/client/client -r -p $resume_port 2>&1) -client_result=$? - -if [ $client_result != 0 ] -then - echo -e "client failed!" - do_cleanup - exit 1 -fi - -wait $server_pid -server_result=$? -remove_ready_file - -if [ $server_result != 0 ] -then - echo -e "client failed!" - exit 1 -fi - -case "$capture_out" in -*$resume_string*) - echo "resumed session" ;; +# Check the client for the extended master secret disable option. If +# present we need to run the test twice. +options_check=`./examples/client/client -?` +case "$options_check" in +*$ems_string*) + echo -e "\nRepeating resume test without extended master secret..." + do_test -n ;; *) - echo "did NOT resume session as expected" - exit 1 ;; esac diff --git a/src/internal.c b/src/internal.c index d134b9aaf..de6a8e6f9 100755 --- a/src/internal.c +++ b/src/internal.c @@ -1401,6 +1401,20 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method, void* heap) } #endif +#if defined(HAVE_EXTENDED_MASTER) && !defined(NO_WOLFSSL_CLIENT) + if (method->side == WOLFSSL_CLIENT_END) { + if ((method->version.major == SSLv3_MAJOR) && + (method->version.minor >= TLSv1_MINOR)) { + + ctx->haveEMS = 1; + } +#ifdef WOLFSSL_DTLS + if (method->version.major == DTLS_MAJOR) + ctx->haveEMS = 1; +#endif /* WOLFSSL_DTLS */ + } +#endif /* HAVE_EXTENDED_MASTER && !NO_WOLFSSL_CLIENT */ + #if defined(HAVE_SESSION_TICKET) && !defined(NO_WOLFSSL_SERVER) ctx->ticketHint = SESSION_TICKET_HINT_DEFAULT; #endif @@ -3375,6 +3389,10 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx) ssl->cipher.ssl = ssl; +#ifdef HAVE_EXTENDED_MASTER + ssl->options.haveEMS = ctx->haveEMS; +#endif + #ifdef HAVE_TLS_EXTENSIONS #ifdef HAVE_MAX_FRAGMENT ssl->max_fragment = MAX_RECORD_SIZE; @@ -11435,6 +11453,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case CTX_INIT_MUTEX_E: return "Initialize ctx mutex error"; + case EXT_MASTER_SECRET_NEEDED_E: + return "Extended Master Secret must be enabled to resume EMS session"; + default : return "unknown error number"; } @@ -12681,6 +12702,7 @@ static void PickHashSigAlgo(WOLFSSL* ssl, ? ssl->session.sessionIDSz : 0; int ret; + word16 extSz = 0; if (ssl->suites == NULL) { WOLFSSL_MSG("Bad suites pointer in SendClientHello"); @@ -12714,11 +12736,19 @@ static void PickHashSigAlgo(WOLFSSL* ssl, if (QSH_Init(ssl) != 0) return MEMORY_E; #endif - length += TLSX_GetRequestSize(ssl); + extSz = TLSX_GetRequestSize(ssl); + if (extSz != 0) + length += extSz; #else - if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) { - length += ssl->suites->hashSigAlgoSz + HELLO_EXT_SZ; - } + if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) + extSz += HELLO_EXT_SZ + HELLO_EXT_SIGALGO_SZ + + ssl->suites->hashSigAlgoSz; +#ifdef HAVE_EXTENDED_MASTER + if (ssl->options.haveEMS) + extSz += HELLO_EXT_SZ; +#endif + if (extSz != 0) + length += extSz + HELLO_EXT_SZ_SZ; #endif sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ; @@ -12803,24 +12833,36 @@ static void PickHashSigAlgo(WOLFSSL* ssl, (void)idx; /* suppress analyzer warning, keep idx current */ #else - if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) - { - int i; - /* add in the extensions length */ - c16toa((word16)(HELLO_EXT_LEN + ssl->suites->hashSigAlgoSz), - output + idx); - idx += 2; + if (extSz != 0) { + c16toa(extSz, output + idx); + idx += HELLO_EXT_SZ_SZ; - c16toa(HELLO_EXT_SIG_ALGO, output + idx); - idx += 2; - c16toa((word16)(HELLO_EXT_SIGALGO_SZ + ssl->suites->hashSigAlgoSz), - output+idx); - idx += 2; - c16toa(ssl->suites->hashSigAlgoSz, output + idx); - idx += 2; - for (i = 0; i < ssl->suites->hashSigAlgoSz; i++, idx++) { - output[idx] = ssl->suites->hashSigAlgo[i]; + if (IsAtLeastTLSv1_2(ssl)) { + if (ssl->suites->hashSigAlgoSz) { + int i; + /* extension type */ + c16toa(HELLO_EXT_SIG_ALGO, output + idx); + idx += HELLO_EXT_TYPE_SZ; + /* extension data length */ + c16toa(HELLO_EXT_SIGALGO_SZ + ssl->suites->hashSigAlgoSz, + output + idx); + idx += HELLO_EXT_SZ_SZ; + /* sig algos length */ + c16toa(ssl->suites->hashSigAlgoSz, output + idx); + idx += HELLO_EXT_SIGALGO_SZ; + for (i = 0; i < ssl->suites->hashSigAlgoSz; i++, idx++) { + output[idx] = ssl->suites->hashSigAlgo[i]; + } + } } +#ifdef HAVE_EXTENDED_MASTER + if (ssl->options.haveEMS) { + c16toa(HELLO_EXT_EXTMS, output + idx); + idx += HELLO_EXT_TYPE_SZ; + c16toa(0, output + idx); + idx += HELLO_EXT_SZ_SZ; + } +#endif } #endif @@ -13063,9 +13105,8 @@ static void PickHashSigAlgo(WOLFSSL* ssl, *inOutIdx = i; - - if ( (i - begin) < helloSz) { #ifdef HAVE_TLS_EXTENSIONS + if ( (i - begin) < helloSz) { if (TLSX_SupportExtensions(ssl)) { int ret = 0; word16 totalExtSz; @@ -13087,9 +13128,70 @@ static void PickHashSigAlgo(WOLFSSL* ssl, *inOutIdx = i; } else -#endif *inOutIdx = begin + helloSz; /* skip extensions */ } + else + ssl->options.haveEMS = 0; /* If no extensions, no EMS */ +#else + { + int allowExt = 0; + byte pendingEMS = 0; + + if ( (i - begin) < helloSz) { + if (ssl->version.major == SSLv3_MAJOR && + ssl->version.minor >= TLSv1_MINOR) { + + allowExt = 1; + } +#ifdef WOLFSSL_DTLS + if (ssl->version.major == DTLS_MAJOR) + allowExt = 1; +#endif + + if (allowExt) { + word16 totalExtSz; + + if ((i - begin) + OPAQUE16_LEN > helloSz) + return BUFFER_ERROR; + + ato16(&input[i], &totalExtSz); + i += OPAQUE16_LEN; + + if ((i - begin) + totalExtSz > helloSz) + return BUFFER_ERROR; + + while (totalExtSz) { + word16 extId, extSz; + + if (OPAQUE16_LEN + OPAQUE16_LEN > totalExtSz) + return BUFFER_ERROR; + + ato16(&input[i], &extId); + i += OPAQUE16_LEN; + ato16(&input[i], &extSz); + i += OPAQUE16_LEN; + + if (OPAQUE16_LEN + OPAQUE16_LEN + extSz > totalExtSz) + return BUFFER_ERROR; + + if (extId == HELLO_EXT_EXTMS) + pendingEMS = 1; + else + i += extSz; + + totalExtSz -= OPAQUE16_LEN + OPAQUE16_LEN + extSz; + } + + *inOutIdx = i; + } + else + *inOutIdx = begin + helloSz; /* skip extensions */ + } + + if (!pendingEMS && ssl->options.haveEMS) + ssl->options.haveEMS = 0; + } +#endif ssl->options.serverState = SERVER_HELLO_COMPLETE; @@ -15984,6 +16086,10 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, length -= (ID_LEN - sessIdSz); /* adjust ID_LEN assumption */ } #endif /* HAVE_SESSION_TICKET */ +#else + if (ssl->options.haveEMS) { + length += HELLO_EXT_SZ_SZ + HELLO_EXT_SZ; + } #endif /* check for avalaible size */ @@ -16057,6 +16163,20 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* last, extensions */ #ifdef HAVE_TLS_EXTENSIONS TLSX_WriteResponse(ssl, output + idx); +#else +#ifdef HAVE_EXTENDED_MASTER + if (ssl->options.haveEMS) { + c16toa(HELLO_EXT_SZ, output + idx); + idx += HELLO_EXT_SZ_SZ; + + c16toa(HELLO_EXT_EXTMS, output + idx); + idx += HELLO_EXT_TYPE_SZ; + c16toa(0, output + idx); + /*idx += HELLO_EXT_SZ_SZ;*/ + /* idx is not used after this point. uncomment the line above + * if adding any more extentions in the future. */ + } +#endif #endif ssl->buffers.outputBuffer.length += sendSz; @@ -18176,6 +18296,10 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, if (clSuites.hashSigAlgoSz > HELLO_EXT_SIGALGO_MAX) clSuites.hashSigAlgoSz = HELLO_EXT_SIGALGO_MAX; } +#ifdef HAVE_EXTENDED_MASTER + else if (extId == HELLO_EXT_EXTMS) + ssl->options.haveEMS = 1; +#endif else i += extSz; @@ -18209,6 +18333,22 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, WOLFSSL_MSG("Session lookup for resume failed"); ssl->options.resuming = 0; } + else if (session->haveEMS != ssl->options.haveEMS) { + /* RFC 7627, 5.3, server-side */ + /* if old sess didn't have EMS, but new does, full handshake */ + if (!session->haveEMS && ssl->options.haveEMS) { + WOLFSSL_MSG("Attempting to resume a session that didn't " + "use EMS with a new session with EMS. Do full " + "handshake."); + ssl->options.resuming = 0; + } + /* if old sess used EMS, but new doesn't, MUST abort */ + else if (session->haveEMS && !ssl->options.haveEMS) { + WOLFSSL_MSG("Trying to resume a session with EMS without " + "using EMS"); + return EXT_MASTER_SECRET_NEEDED_E; + } + } else { if (MatchSuite(ssl, &clSuites) < 0) { WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); @@ -18621,6 +18761,7 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, byte suite[SUITE_LEN]; /* cipher suite when created */ byte msecret[SECRET_LEN]; /* master secret */ word32 timestamp; /* born on */ + word16 haveEMS; /* have extended master secret */ } InternalTicket; /* fit within SESSION_TICKET_LEN */ @@ -18642,6 +18783,8 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, int ret; byte zeros[WOLFSSL_TICKET_MAC_SZ]; /* biggest cmp size */ + XMEMSET(&it, 0, sizeof(it)); + /* build internal */ it.pv.major = ssl->version.major; it.pv.minor = ssl->version.minor; @@ -18651,6 +18794,7 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, XMEMCPY(it.msecret, ssl->arrays->masterSecret, SECRET_LEN); c32toa(LowResTimer(), (byte*)&it.timestamp); + it.haveEMS = ssl->options.haveEMS; /* build external */ XMEMCPY(et->enc_ticket, &it, sizeof(InternalTicket)); @@ -18742,8 +18886,12 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, } /* get master secret */ - if (ret == WOLFSSL_TICKET_RET_OK || ret == WOLFSSL_TICKET_RET_CREATE) + if (ret == WOLFSSL_TICKET_RET_OK || ret == WOLFSSL_TICKET_RET_CREATE) { XMEMCPY(ssl->arrays->masterSecret, it->msecret, SECRET_LEN); + /* Copy the haveExtendedMasterSecret property from the ticket to + * the saved session, so the property may be checked later. */ + ssl->session.haveEMS = it->haveEMS; + } return ret; } diff --git a/src/sniffer.c b/src/sniffer.c index 577d59110..49627960b 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -90,6 +90,7 @@ enum { EXT_TYPE_SZ = 2, /* Extension length */ MAX_INPUT_SZ = MAX_RECORD_SIZE + COMP_EXTRA + MAX_MSG_EXTRA + MTU_EXTRA, /* Max input sz of reassembly */ + EXT_MASTER_SECRET = 0x17, /* Extended Master Secret Extension ID */ TICKET_EXT_ID = 0x23 /* Session Ticket Extension ID */ }; @@ -253,7 +254,8 @@ static const char* const msgTable[] = "Clear ACK Fault", /* 81 */ - "Bad Decrypt Size" + "Bad Decrypt Size", + "Extended Master Secret Hash Error" }; @@ -329,6 +331,9 @@ typedef struct Flags { byte srvAckFault; /* server acked unseen data from client */ byte cliSkipPartial; /* client skips partial data to catch up */ byte srvSkipPartial; /* server skips partial data to catch up */ +#ifdef HAVE_EXTENDED_MASTER + byte expectEms; /* expect extended master secret */ +#endif } Flags; @@ -341,6 +346,24 @@ typedef struct FinCaputre { } FinCaputre; +typedef struct HsHashes { +#ifndef NO_OLD_TLS +#ifndef NO_SHA + Sha hashSha; +#endif +#ifndef NO_MD5 + Md5 hashMd5; +#endif +#endif +#ifndef NO_SHA256 + Sha256 hashSha256; +#endif +#ifdef WOLFSSL_SHA384 + Sha384 hashSha384; +#endif +} HsHashes; + + /* Sniffer Session holds info for each client/server SSL/TLS session */ typedef struct SnifferSession { SnifferServer* context; /* server context */ @@ -363,6 +386,9 @@ typedef struct SnifferSession { word32 srvReassemblyMemory; /* server packet memory used */ struct SnifferSession* next; /* for hash table list */ byte* ticketID; /* mac ID of session ticket */ +#ifdef HAVE_EXTENDED_MASTER + HsHashes* hash; +#endif } SnifferSession; @@ -483,6 +509,9 @@ static void FreeSnifferSession(SnifferSession* session) FreePacketList(session->srvReassemblyList); free(session->ticketID); +#ifdef HAVE_EXTENDED_MASTER + free(session->hash); +#endif } free(session); } @@ -533,6 +562,91 @@ void ssl_FreeSniffer(void) } +#ifdef HAVE_EXTENDED_MASTER + +static int HashInit(HsHashes* hash) +{ + int ret = 0; + + XMEMSET(hash, 0, sizeof(HsHashes)); + +#ifndef NO_OLD_TLS +#ifndef NO_SHA + if (ret == 0) + ret = wc_InitSha(&hash->hashSha); +#endif +#ifndef NO_MD5 + if (ret == 0) + wc_InitMd5(&hash->hashMd5); +#endif +#endif +#ifndef NO_SHA256 + if (ret == 0) + ret = wc_InitSha256(&hash->hashSha256); +#endif +#ifdef WOLFSSL_SHA384 + if (ret == 0) + ret = wc_InitSha384(&hash->hashSha384); +#endif + + return ret; +} + + +static int HashUpdate(HsHashes* hash, const byte* input, int sz) +{ + int ret = 0; + + input -= HANDSHAKE_HEADER_SZ; + sz += HANDSHAKE_HEADER_SZ; + +#ifndef NO_OLD_TLS +#ifndef NO_SHA + if (ret == 0) + ret = wc_ShaUpdate(&hash->hashSha, input, sz); +#endif +#ifndef NO_MD5 + if (ret == 0) + wc_Md5Update(&hash->hashMd5, input, sz); +#endif +#endif +#ifndef NO_SHA256 + if (ret == 0) + ret = wc_Sha256Update(&hash->hashSha256, input, sz); +#endif +#ifdef WOLFSSL_SHA384 + if (ret == 0) + ret = wc_Sha384Update(&hash->hashSha384, input, sz); +#endif + + return ret; +} + + +static int HashCopy(HS_Hashes* d, HsHashes* s) +{ +#ifndef NO_OLD_TLS +#ifndef NO_SHA + XMEMCPY(&d->hashSha, &s->hashSha, sizeof(Sha)); +#endif +#ifndef NO_MD5 + XMEMCPY(&d->hashMd5, &s->hashMd5, sizeof(Md5)); +#endif +#endif + +#ifndef NO_SHA256 + XMEMCPY(&d->hashSha256, &s->hashSha256, sizeof(Sha256)); +#endif +#ifdef WOLFSSL_SHA384 + XMEMCPY(&d->hashSha384, &s->hashSha384, sizeof(Sha384)); +#endif + + return 0; +} + +#endif + + /* Initialize a SnifferServer */ static void InitSnifferServer(SnifferServer* sniffer) { @@ -563,6 +677,9 @@ static void InitFlags(Flags* flags) flags->srvAckFault = 0; flags->cliSkipPartial = 0; flags->srvSkipPartial = 0; +#ifdef HAVE_EXTENDED_MASTER + flags->expectEms = 0; +#endif } @@ -600,6 +717,9 @@ static void InitSession(SnifferSession* session) InitFlags(&session->flags); InitFinCapture(&session->finCaputre); +#ifdef HAVE_EXTENDED_MASTER + session->hash = 0; +#endif } @@ -1483,13 +1603,17 @@ static int ProcessSessionTicket(const byte* input, int* sslBytes, /* Process Server Hello */ -static int ProcessServerHello(const byte* input, int* sslBytes, +static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, SnifferSession* session, char* error) { ProtocolVersion pv; byte b; int toRead = VERSION_SZ + RAN_LEN + ENUM_LEN; int doResume = 0; + int initialBytes = *sslBytes; + + (void)msgSz; + (void)initialBytes; /* make sure we didn't miss ClientHello */ if (session->flags.clientHello == 0) { @@ -1548,6 +1672,62 @@ static int ProcessServerHello(const byte* input, int* sslBytes, return -1; } +#ifdef HAVE_EXTENDED_MASTER + /* extensions */ + if ((initialBytes - *sslBytes) < msgSz) { + word16 len; + + /* skip extensions until extended master secret */ + /* make sure can read len */ + if (SUITE_LEN > *sslBytes) { + SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + len = (word16)((input[0] << 8) | input[1]); + input += SUITE_LEN; + *sslBytes -= SUITE_LEN; + /* make sure can read through all extensions */ + if (len > *sslBytes) { + SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE); + return -1; + } + + while (len >= EXT_TYPE_SZ + LENGTH_SZ) { + byte extType[EXT_TYPE_SZ]; + word16 extLen; + + extType[0] = input[0]; + extType[1] = input[1]; + input += EXT_TYPE_SZ; + *sslBytes -= EXT_TYPE_SZ; + + extLen = (word16)((input[0] << 8) | input[1]); + input += LENGTH_SZ; + *sslBytes -= LENGTH_SZ; + + /* make sure can read through individual extension */ + if (extLen > *sslBytes) { + SetError(SERVER_HELLO_INPUT_STR, error, session, + FATAL_ERROR_STATE); + return -1; + } + + if (extType[0] == 0x00 && extType[1] == EXT_MASTER_SECRET) { + session->flags.expectEms = 1; + } + + input += extLen; + *sslBytes -= extLen; + len -= extLen + EXT_TYPE_SZ + LENGTH_SZ; + } + } + + if (!session->flags.expectEms) { + free(session->hash); + session->hash = NULL; + } +#endif + if (session->sslServer->options.haveSessionId && XMEMCMP(session->sslServer->arrays->sessionID, session->sslClient->arrays->sessionID, ID_LEN) == 0) @@ -1758,7 +1938,7 @@ static int ProcessClientHello(const byte* input, int* sslBytes, return -1; } - while (len > EXT_TYPE_SZ + LENGTH_SZ) { + while (len >= EXT_TYPE_SZ + LENGTH_SZ) { byte extType[EXT_TYPE_SZ]; word16 extLen; @@ -1883,6 +2063,16 @@ static int DoHandShake(const byte* input, int* sslBytes, return -1; } +#ifdef HAVE_EXTENDED_MASTER + if (session->hash) { + if (HashUpdate(session->hash, input, size) != 0) { + SetError(EXTENDED_MASTER_HASH_STR, error, + session, FATAL_ERROR_STATE); + return -1; + } + } +#endif + switch (type) { case hello_verify_request: Trace(GOT_HELLO_VERIFY_STR); @@ -1896,7 +2086,7 @@ static int DoHandShake(const byte* input, int* sslBytes, break; case server_hello: Trace(GOT_SERVER_HELLO_STR); - ret = ProcessServerHello(input, sslBytes, session, error); + ret = ProcessServerHello(size, input, sslBytes, session, error); break; case certificate_request: Trace(GOT_CERT_REQ_STR); @@ -1923,7 +2113,32 @@ static int DoHandShake(const byte* input, int* sslBytes, break; case client_key_exchange: Trace(GOT_CLIENT_KEY_EX_STR); - ret = ProcessClientKeyExchange(input, sslBytes, session, error); +#ifdef HAVE_EXTENDED_MASTER + if (session->flags.expectEms && session->hash != NULL) { + if (HashCopy(session->sslServer->hsHashes, + session->hash) == 0 && + HashCopy(session->sslClient->hsHashes, + session->hash) == 0) { + + session->sslServer->options.haveEMS = 1; + session->sslClient->options.haveEMS = 1; + } + else { + SetError(EXTENDED_MASTER_HASH_STR, error, + session, FATAL_ERROR_STATE); + ret = -1; + } + XMEMSET(session->hash, 0, sizeof(HsHashes)); + free(session->hash); + session->hash = NULL; + } + else { + session->sslServer->options.haveEMS = 0; + session->sslClient->options.haveEMS = 0; + } +#endif + if (ret == 0) + ret = ProcessClientKeyExchange(input, sslBytes, session, error); break; case certificate_verify: Trace(GOT_CERT_VER_STR); @@ -2135,6 +2350,22 @@ static SnifferSession* CreateSession(IpInfo* ipInfo, TcpInfo* tcpInfo, return 0; } InitSession(session); +#ifdef HAVE_EXTENDED_MASTER + { + HsHashes* newHash = (HsHashes*)malloc(sizeof(HsHashes)); + if (newHash == NULL) { + SetError(MEMORY_STR, error, NULL, 0); + free(session); + return 0; + } + if (HashInit(newHash) != 0) { + SetError(EXTENDED_MASTER_HASH_STR, error, NULL, 0); + free(session); + return 0; + } + session->hash = newHash; + } +#endif session->server = ipInfo->dst; session->client = ipInfo->src; session->srvPort = (word16)tcpInfo->dstPort; diff --git a/src/ssl.c b/src/ssl.c index 391488162..f04ec1287 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -1749,6 +1749,35 @@ WOLFSSL_API int wolfSSL_set_SessionTicket_cb(WOLFSSL* ssl, } #endif + +#ifdef HAVE_EXTENDED_MASTER +#ifndef NO_WOLFSSL_CLIENT + +int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + ctx->haveEMS = 0; + + return SSL_SUCCESS; +} + + +int wolfSSL_DisableExtendedMasterSecret(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->options.haveEMS = 0; + + return SSL_SUCCESS; +} + +#endif +#endif + + #ifndef WOLFSSL_LEANPSK int wolfSSL_send(WOLFSSL* ssl, const void* data, int sz, int flags) @@ -7847,6 +7876,7 @@ int AddSession(WOLFSSL* ssl) XMEMCPY(SessionCache[row].Sessions[idx].masterSecret, ssl->arrays->masterSecret, SECRET_LEN); + SessionCache[row].Sessions[idx].haveEMS = ssl->options.haveEMS; XMEMCPY(SessionCache[row].Sessions[idx].sessionID, ssl->arrays->sessionID, ID_LEN); SessionCache[row].Sessions[idx].sessionIDSz = ssl->arrays->sessionIDSz; diff --git a/src/tls.c b/src/tls.c index e13ae88a1..648147c2a 100644 --- a/src/tls.c +++ b/src/tls.c @@ -341,21 +341,23 @@ static int PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen, #endif -int BuildTlsFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) +int BuildTlsHandshakeHash(WOLFSSL* ssl, byte* hash, word32* hashLen) { - const byte* side; - byte handshake_hash[HSHASH_SZ]; - word32 hashSz = FINISHED_SZ; + word32 hashSz = FINISHED_SZ; + + if (ssl == NULL || hash == NULL || hashLen == NULL || *hashLen < HSHASH_SZ) + return BAD_FUNC_ARG; #ifndef NO_OLD_TLS - wc_Md5GetHash(&ssl->hsHashes->hashMd5, handshake_hash); - wc_ShaGetHash(&ssl->hsHashes->hashSha, &handshake_hash[MD5_DIGEST_SIZE]); + wc_Md5GetHash(&ssl->hsHashes->hashMd5, hash); + wc_ShaGetHash(&ssl->hsHashes->hashSha, &hash[MD5_DIGEST_SIZE]); #endif if (IsAtLeastTLSv1_2(ssl)) { #ifndef NO_SHA256 - if (ssl->specs.mac_algorithm <= sha256_mac || ssl->specs.mac_algorithm == blake2b_mac) { - int ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256,handshake_hash); + if (ssl->specs.mac_algorithm <= sha256_mac || + ssl->specs.mac_algorithm == blake2b_mac) { + int ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash); if (ret != 0) return ret; @@ -365,7 +367,7 @@ int BuildTlsFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) #endif #ifdef WOLFSSL_SHA384 if (ssl->specs.mac_algorithm == sha384_mac) { - int ret = wc_Sha384Final(&ssl->hsHashes->hashSha384,handshake_hash); + int ret = wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash); if (ret != 0) return ret; @@ -375,6 +377,23 @@ int BuildTlsFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) #endif } + *hashLen = hashSz; + + return 0; +} + + +int BuildTlsFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) +{ + int ret; + const byte* side; + byte handshake_hash[HSHASH_SZ]; + word32 hashSz = HSHASH_SZ; + + ret = BuildTlsHandshakeHash(ssl, handshake_hash, &hashSz); + if (ret < 0) + return ret; + if ( XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0) side = tls_client; else @@ -420,6 +439,10 @@ ProtocolVersion MakeTLSv1_2(void) } +#ifdef HAVE_EXTENDED_MASTER +static const byte ext_master_label[EXT_MASTER_LABEL_SZ + 1] = + "extended master secret"; +#endif static const byte master_label[MASTER_LABEL_SZ + 1] = "master secret"; static const byte key_label [KEY_LABEL_SZ + 1] = "key expansion"; @@ -490,10 +513,41 @@ int wolfSSL_MakeTlsMasterSecret(byte* ms, word32 msLen, } +#ifdef HAVE_EXTENDED_MASTER + +/* External facing wrapper so user can call as well, 0 on success */ +int wolfSSL_MakeTlsExtendedMasterSecret(byte* ms, word32 msLen, + const byte* pms, word32 pmsLen, + const byte* sHash, word32 sHashLen, + int tls1_2, int hash_type) +{ + return PRF(ms, msLen, pms, pmsLen, ext_master_label, EXT_MASTER_LABEL_SZ, + sHash, sHashLen, tls1_2, hash_type); +} + +#endif /* HAVE_EXTENDED_MASTER */ + + int MakeTlsMasterSecret(WOLFSSL* ssl) { - int ret; + int ret; +#ifdef HAVE_EXTENDED_MASTER + byte handshake_hash[HSHASH_SZ]; + word32 hashSz = HSHASH_SZ; + if (ssl->options.haveEMS) { + + ret = BuildTlsHandshakeHash(ssl, handshake_hash, &hashSz); + if (ret < 0) + return ret; + + ret = wolfSSL_MakeTlsExtendedMasterSecret( + ssl->arrays->masterSecret, SECRET_LEN, + ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz, + handshake_hash, hashSz, + IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm); + } else +#endif ret = wolfSSL_MakeTlsMasterSecret(ssl->arrays->masterSecret, SECRET_LEN, ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz, ssl->arrays->clientRandom, ssl->arrays->serverRandom, @@ -4434,7 +4488,13 @@ word16 TLSX_GetRequestSize(WOLFSSL* ssl) length += TLSX_GetSize(ssl->ctx->extensions, semaphore, 1); if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) - length += ssl->suites->hashSigAlgoSz + HELLO_EXT_LEN; + length += HELLO_EXT_SZ + HELLO_EXT_SIGALGO_SZ + + ssl->suites->hashSigAlgoSz; + +#ifdef HAVE_EXTENDED_MASTER + if (ssl->options.haveEMS) + length += HELLO_EXT_SZ; +#endif } if (length) @@ -4465,15 +4525,15 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output) offset += TLSX_Write(ssl->ctx->extensions, output + offset, semaphore, 1); - if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) - { + if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz) { int i; /* extension type */ c16toa(HELLO_EXT_SIG_ALGO, output + offset); offset += HELLO_EXT_TYPE_SZ; /* extension data length */ - c16toa(OPAQUE16_LEN + ssl->suites->hashSigAlgoSz, output + offset); + c16toa(OPAQUE16_LEN + ssl->suites->hashSigAlgoSz, + output + offset); offset += OPAQUE16_LEN; /* sig algos length */ @@ -4485,6 +4545,15 @@ word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output) output[offset] = ssl->suites->hashSigAlgo[i]; } +#ifdef HAVE_EXTENDED_MASTER + if (ssl->options.haveEMS) { + c16toa(HELLO_EXT_EXTMS, output + offset); + offset += HELLO_EXT_TYPE_SZ; + c16toa(0, output + offset); + offset += HELLO_EXT_SZ_SZ; + } +#endif + if (offset > OPAQUE16_LEN) c16toa(offset - OPAQUE16_LEN, output); /* extensions length */ } @@ -4511,13 +4580,18 @@ word16 TLSX_GetResponseSize(WOLFSSL* ssl) } #endif +#ifdef HAVE_EXTENDED_MASTER + if (ssl->options.haveEMS) + length += HELLO_EXT_SZ; +#endif + if (TLSX_SupportExtensions(ssl)) length += TLSX_GetSize(ssl->extensions, semaphore, 0); /* All the response data is set at the ssl object only, so no ctx here. */ if (length) - length += OPAQUE16_LEN; /* for total length storage */ + length += OPAQUE16_LEN; /* for total length storage. */ return length; } @@ -4534,6 +4608,15 @@ word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output) offset += TLSX_Write(ssl->extensions, output + offset, semaphore, 0); +#ifdef HAVE_EXTENDED_MASTER + if (ssl->options.haveEMS) { + c16toa(HELLO_EXT_EXTMS, output + offset); + offset += HELLO_EXT_TYPE_SZ; + c16toa(0, output + offset); + offset += HELLO_EXT_SZ_SZ; + } +#endif + if (offset > OPAQUE16_LEN) c16toa(offset - OPAQUE16_LEN, output); /* extensions length */ } @@ -4549,6 +4632,9 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, { int ret = 0; word16 offset = 0; +#ifdef HAVE_EXTENDED_MASTER + byte pendingEMS = 0; +#endif if (!ssl || !input || (isRequest && !suites)) return BAD_FUNC_ARG; @@ -4606,6 +4692,18 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, ret = CSR2_PARSE(ssl, input + offset, size, isRequest); break; +#ifdef HAVE_EXTENDED_MASTER + case HELLO_EXT_EXTMS: + WOLFSSL_MSG("Extended Master Secret extension received"); + +#ifndef NO_WOLFSSL_SERVER + if (isRequest) + ssl->options.haveEMS = 1; +#endif + pendingEMS = 1; + break; +#endif + case TLSX_RENEGOTIATION_INFO: WOLFSSL_MSG("Secure Renegotiation extension received"); @@ -4655,6 +4753,11 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, offset += size; } +#ifdef HAVE_EXTENDED_MASTER + if (!isRequest && ssl->options.haveEMS && !pendingEMS) + ssl->options.haveEMS = 0; +#endif + if (ret == 0) ret = SNI_VERIFY_PARSE(ssl, isRequest); diff --git a/tests/api.c b/tests/api.c index 11605d1ce..b5d348ca0 100644 --- a/tests/api.c +++ b/tests/api.c @@ -1927,6 +1927,28 @@ static void test_wolfSSL_UseALPN(void) #endif } +static void test_wolfSSL_DisableExtendedMasterSecret(void) +{ +#ifdef HAVE_EXTENDED_MASTER + WOLFSSL_CTX *ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); + WOLFSSL *ssl = wolfSSL_new(ctx); + + AssertNotNull(ctx); + AssertNotNull(ssl); + + /* error cases */ + AssertIntNE(SSL_SUCCESS, wolfSSL_CTX_DisableExtendedMasterSecret(NULL)); + AssertIntNE(SSL_SUCCESS, wolfSSL_DisableExtendedMasterSecret(NULL)); + + /* success cases */ + AssertIntEQ(SSL_SUCCESS, wolfSSL_CTX_DisableExtendedMasterSecret(ctx)); + AssertIntEQ(SSL_SUCCESS, wolfSSL_DisableExtendedMasterSecret(ssl)); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); +#endif +} + /*----------------------------------------------------------------------------* | X509 Tests *----------------------------------------------------------------------------*/ @@ -2129,6 +2151,7 @@ void ApiTest(void) test_wolfSSL_UseTruncatedHMAC(); test_wolfSSL_UseSupportedCurve(); test_wolfSSL_UseALPN(); + test_wolfSSL_DisableExtendedMasterSecret(); /* X509 tests */ test_wolfSSL_X509_NAME_get_entry(); diff --git a/tests/suites.c b/tests/suites.c index bc700d00e..f23c116cc 100644 --- a/tests/suites.c +++ b/tests/suites.c @@ -48,6 +48,7 @@ static WOLFSSL_CTX* cipherSuiteCtx = NULL; static char nonblockFlag[] = "-N"; static char noVerifyFlag[] = "-d"; +static char disableEMSFlag[] = "-n"; static char flagSep[] = " "; #if !defined(USE_WINDOWS_API) && !defined(WOLFSSL_TIRTOS) static char portFlag[] = "-p"; @@ -153,7 +154,8 @@ static int IsValidCipherSuite(const char* line, char* suite) static int execute_test_case(int svr_argc, char** svr_argv, int cli_argc, char** cli_argv, - int addNoVerify, int addNonBlocking) + int addNoVerify, int addNonBlocking, + int addDisableEMS) { #ifdef WOLFSSL_TIRTOS func_args cliArgs = {0}; @@ -270,6 +272,18 @@ static int execute_test_case(int svr_argc, char** svr_argv, cliArgs.argc = cli_argc; } } + if (addDisableEMS) { + printf("repeating test without extended master secret\n"); + added += 4; /* -n plus terminator */ + if (added >= MAX_COMMAND_SZ) + printf("client command line too long\n"); + else { + cli_argv[cli_argc++] = disableEMSFlag; + strcat(commandLine, disableEMSFlag); + strcat(commandLine, flagSep); + cliArgs.argc = cli_argc; + } + } printf("trying client command line[%d]: %s\n", tests++, commandLine); InitTcpReady(&ready); @@ -437,12 +451,26 @@ static void test_harness(void* vargs) } if (do_it) { - ret = execute_test_case(svrArgsSz, svrArgs, cliArgsSz, cliArgs,0,0); + ret = execute_test_case(svrArgsSz, svrArgs, + cliArgsSz, cliArgs, 0, 0, 0); /* don't repeat if not supported in build */ if (ret == 0) { - execute_test_case(svrArgsSz, svrArgs, cliArgsSz, cliArgs, 0, 1); - execute_test_case(svrArgsSz, svrArgs, cliArgsSz, cliArgs, 1, 0); - execute_test_case(svrArgsSz, svrArgs, cliArgsSz, cliArgs, 1, 1); + execute_test_case(svrArgsSz, svrArgs, + cliArgsSz, cliArgs, 0, 1, 0); + execute_test_case(svrArgsSz, svrArgs, + cliArgsSz, cliArgs, 1, 0, 0); + execute_test_case(svrArgsSz, svrArgs, + cliArgsSz, cliArgs, 1, 1, 0); +#ifdef HAVE_EXTENDED_MASTER + execute_test_case(svrArgsSz, svrArgs, + cliArgsSz, cliArgs, 0, 0, 1); + execute_test_case(svrArgsSz, svrArgs, + cliArgsSz, cliArgs, 0, 1, 1); + execute_test_case(svrArgsSz, svrArgs, + cliArgsSz, cliArgs, 1, 0, 1); + execute_test_case(svrArgsSz, svrArgs, + cliArgsSz, cliArgs, 1, 1, 1); +#endif } svrArgsSz = 1; cliArgsSz = 1; diff --git a/wolfcrypt/src/hash.c b/wolfcrypt/src/hash.c index 28d04e76b..7cda03024 100644 --- a/wolfcrypt/src/hash.c +++ b/wolfcrypt/src/hash.c @@ -324,6 +324,21 @@ int wc_Sha256Hash(const byte* data, word32 len, byte* hash) #endif /* !defined(WOLFSSL_TI_HASH) */ #if defined(WOLFSSL_SHA512) +int wc_Sha512GetHash(Sha512* sha512, byte* hash) +{ + int ret; + Sha512 save; + + if (sha512 == NULL || hash == NULL) + return BAD_FUNC_ARG; + + save= *sha512; + ret = wc_Sha512Final(sha512, hash); + *sha512 = save; + + return ret; +} + int wc_Sha512Hash(const byte* data, word32 len, byte* hash) { int ret = 0; @@ -357,6 +372,21 @@ int wc_Sha512Hash(const byte* data, word32 len, byte* hash) } #if defined(WOLFSSL_SHA384) +int wc_Sha384GetHash(Sha384* sha384, byte* hash) +{ + int ret; + Sha384 save; + + if (sha384 == NULL || hash == NULL) + return BAD_FUNC_ARG; + + save= *sha384; + ret = wc_Sha384Final(sha384, hash); + *sha384 = save; + + return ret; +} + int wc_Sha384Hash(const byte* data, word32 len, byte* hash) { int ret = 0; diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 6b55170d2..bf9861946 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -149,6 +149,7 @@ enum wolfSSL_ErrorCodes { DTLS_EXPORT_VER_E = -411, /* export version error */ INPUT_SIZE_E = -412, /* input size too big error */ CTX_INIT_MUTEX_E = -413, /* initialize ctx mutex error */ + EXT_MASTER_SECRET_NEEDED_E = -414, /* need EMS enabled to resume */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ /* begin negotiation parameter errors */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index c79dcdf0f..5f67dc33e 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -878,6 +878,7 @@ enum Misc { NO_COMPRESSION = 0, ZLIB_COMPRESSION = 221, /* wolfSSL zlib compression */ HELLO_EXT_SIG_ALGO = 13, /* ID for the sig_algo hello extension */ + HELLO_EXT_EXTMS = 0x0017, /* ID for the extended master secret ext */ SECRET_LEN = 48, /* pre RSA and all master */ #if defined(WOLFSSL_MYSQL_COMPATIBLE) ENCRYPT_LEN = 1024, /* allow larger static buffer with mysql */ @@ -939,10 +940,10 @@ enum Misc { REQ_HEADER_SZ = 2, /* cert request header sz */ HINT_LEN_SZ = 2, /* length of hint size field */ TRUNCATED_HMAC_SZ = 10, /* length of hmac w/ truncated hmac extension */ + HELLO_EXT_SZ = 4, /* base length of a hello extension */ HELLO_EXT_TYPE_SZ = 2, /* length of a hello extension type */ - HELLO_EXT_SZ = 8, /* total length of the lazy hello extensions */ - HELLO_EXT_LEN = 6, /* length of the lazy hello extensions */ - HELLO_EXT_SIGALGO_SZ = 2, /* length of signature algo extension */ + HELLO_EXT_SZ_SZ = 2, /* length of a hello extension size */ + HELLO_EXT_SIGALGO_SZ = 2, /* length of number of items in sigalgo list */ HELLO_EXT_SIGALGO_MAX = 32, /* number of items in the signature algo list */ DTLS_HANDSHAKE_HEADER_SZ = 12, /* normal + seq(2) + offset(3) + length(3) */ @@ -963,6 +964,7 @@ enum Misc { MAX_EXPORT_BUFFER = 500, /* max size of buffer for exporting */ FINISHED_LABEL_SZ = 15, /* TLS finished label size */ TLS_FINISHED_SZ = 12, /* TLS has a shorter size */ + EXT_MASTER_LABEL_SZ = 22, /* TLS extended master secret label sz */ MASTER_LABEL_SZ = 13, /* TLS master secret label sz */ KEY_LABEL_SZ = 13, /* TLS key block expansion sz */ MAX_PRF_HALF = 256, /* Maximum half secret len */ @@ -1936,6 +1938,7 @@ struct WOLFSSL_CTX { byte quietShutdown; /* don't send close notify */ byte groupMessages; /* group handshake messages before sending */ byte minDowngrade; /* minimum downgrade version */ + byte haveEMS; /* have extended master secret extension */ #if defined(WOLFSSL_SCTP) && defined(WOLFSSL_DTLS) byte dtlsSctp; /* DTLS-over-SCTP mode */ word16 dtlsMtuSz; /* DTLS MTU size */ @@ -2225,6 +2228,7 @@ struct WOLFSSL_SESSION { byte sessionID[ID_LEN]; /* id for protocol */ byte sessionIDSz; byte masterSecret[SECRET_LEN]; /* stored secret */ + word16 haveEMS; /* ext master secret flag */ #ifdef SESSION_CERTS WOLFSSL_X509_CHAIN chain; /* peer cert chain, static */ ProtocolVersion version; /* which version was used */ @@ -2409,6 +2413,7 @@ typedef struct Options { word16 dtlsSctp:1; /* DTLS-over-SCTP mode */ #endif #endif + word16 haveEMS:1; /* using extended master secret */ /* need full byte values for this section */ byte processReply; /* nonblocking resume */ @@ -3028,6 +3033,8 @@ WOLFSSL_LOCAL int VerifyClientSuite(WOLFSSL* ssl); WOLFSSL_LOCAL Signer* GetCAByName(void* cm, byte* hash); #endif #endif /* !NO_CERTS */ +WOLFSSL_LOCAL int BuildTlsHandshakeHash(WOLFSSL* ssl, byte* hash, + word32* hashLen); WOLFSSL_LOCAL int BuildTlsFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender); WOLFSSL_LOCAL void FreeArrays(WOLFSSL* ssl, int keep); diff --git a/wolfssl/sniffer_error.h b/wolfssl/sniffer_error.h index 327455ec2..0c04ba878 100644 --- a/wolfssl/sniffer_error.h +++ b/wolfssl/sniffer_error.h @@ -117,6 +117,7 @@ #define CLEAR_ACK_FAULT 80 #define BAD_DECRYPT_SIZE 81 +#define EXTENDED_MASTER_HASH_STR 82 /* !!!! also add to msgTable in sniffer.c and .rc file !!!! */ diff --git a/wolfssl/sniffer_error.rc b/wolfssl/sniffer_error.rc index e7d998059..947be6119 100644 --- a/wolfssl/sniffer_error.rc +++ b/wolfssl/sniffer_error.rc @@ -98,5 +98,6 @@ STRINGTABLE 80, "Clear ACK Fault" 81, "Bad Decrypt Size" + 82, "Extended Master Secret Hash Error" } diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 4f234b058..e83749cd2 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1704,6 +1704,11 @@ WOLFSSL_API int wolfSSL_UseSupportedQSH(WOLFSSL* ssl, unsigned short name); #endif #endif +/* TLS Extended Master Secret Extension */ +WOLFSSL_API int wolfSSL_DisableExtendedMasterSecret(WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx); + + #define WOLFSSL_CRL_MONITOR 0x01 /* monitor this dir flag */ #define WOLFSSL_CRL_START_MON 0x02 /* start monitoring flag */ @@ -1725,6 +1730,12 @@ int wolfSSL_MakeTlsMasterSecret(unsigned char* ms, unsigned int msLen, const unsigned char* cr, const unsigned char* sr, int tls1_2, int hash_type); +WOLFSSL_API +int wolfSSL_MakeTlsExtendedMasterSecret(unsigned char* ms, unsigned int msLen, + const unsigned char* pms, unsigned int pmsLen, + const unsigned char* sHash, unsigned int sHashLen, + int tls1_2, int hash_type); + WOLFSSL_API int wolfSSL_DeriveTlsKeys(unsigned char* key_data, unsigned int keyLen, const unsigned char* ms, unsigned int msLen, diff --git a/wolfssl/wolfcrypt/hash.h b/wolfssl/wolfcrypt/hash.h index a2d2eca92..1296c56f5 100644 --- a/wolfssl/wolfcrypt/hash.h +++ b/wolfssl/wolfcrypt/hash.h @@ -105,10 +105,12 @@ WOLFSSL_API int wc_Sha256Hash(const byte*, word32, byte*); #ifdef WOLFSSL_SHA512 #include +WOLFSSL_API int wc_Sha512GetHash(Sha512*, byte*); WOLFSSL_API int wc_Sha512Hash(const byte*, word32, byte*); #define wc_Sha512Free(d) #if defined(WOLFSSL_SHA384) + WOLFSSL_API int wc_Sha384GetHash(Sha384*, byte*); WOLFSSL_API int wc_Sha384Hash(const byte*, word32, byte*); #define wc_Sha384Free(d) #endif /* defined(WOLFSSL_SHA384) */