From 5bf880665586a580d7adaec25780f85489f99a43 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Thu, 1 Sep 2016 15:05:27 -0600 Subject: [PATCH 01/10] add wc_Sha384/512GetHash() functions --- wolfcrypt/src/hash.c | 30 ++++++++++++++++++++++++++++++ wolfssl/wolfcrypt/hash.h | 2 ++ 2 files changed, 32 insertions(+) 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/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) */ From e4f527a3327cfebc9fa712a97da136a89624cc7e Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Thu, 1 Sep 2016 15:12:54 -0600 Subject: [PATCH 02/10] initial extended master secret support --- configure.ac | 16 ++++- src/internal.c | 14 +++++ src/ssl.c | 23 +++++++ src/tls.c | 144 +++++++++++++++++++++++++++++++++++++++++--- wolfssl/error-ssl.h | 1 + wolfssl/internal.h | 14 +++++ wolfssl/ssl.h | 16 +++++ 7 files changed, 217 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 2908f99e7..853e71a0b 100644 --- a/configure.ac +++ b/configure.ac @@ -1957,6 +1957,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: disabled)])], + [ ENABLED_EXTENDED_MASTER=$enableval ], + [ ENABLED_EXTENDED_MASTER=no ] + ) + +if test "x$ENABLED_EXTENDED_MASTER" = "xyes" +then + AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_EXTENDED_MASTER" +fi + # TLS Extensions AC_ARG_ENABLE([tlsx], [ --enable-tlsx Enable all TLS Extensions (default: disabled)], @@ -1971,7 +1983,8 @@ then ENABLED_TRUNCATED_HMAC=yes ENABLED_SUPPORTED_CURVES=yes ENABLED_ALPN=yes - AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_SNI -DHAVE_MAX_FRAGMENT -DHAVE_TRUNCATED_HMAC -DHAVE_SUPPORTED_CURVES -DHAVE_ALPN" + ENABLED_EXTENDED_MASTER=yes + AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_SNI -DHAVE_MAX_FRAGMENT -DHAVE_TRUNCATED_HMAC -DHAVE_SUPPORTED_CURVES -DHAVE_ALPN -DHAVE_EXTENDED_MASTER" fi # PKCS7 @@ -3199,6 +3212,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/src/internal.c b/src/internal.c index 7e619daf9..e9556a142 100755 --- a/src/internal.c +++ b/src/internal.c @@ -11432,6 +11432,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"; } @@ -18185,6 +18188,17 @@ 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) { + ssl->options.resuming = 0; + } + /* if old sess used EMS, but new doesn't, MUST abort */ + else if (session->haveEMS && !ssl->options.haveEMS) { + return EXT_MASTER_SECRET_NEEDED_E; + } + } else { if (MatchSuite(ssl, &clSuites) < 0) { WOLFSSL_MSG("Unsupported cipher suite, ClientHello"); diff --git a/src/ssl.c b/src/ssl.c index 61bd2d4f8..2e99b5b6e 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -1749,6 +1749,28 @@ WOLFSSL_API int wolfSSL_set_SessionTicket_cb(WOLFSSL* ssl, } #endif +#ifdef HAVE_EXTENDED_MASTER +#ifndef NO_WOLFSSL_CLIENT + +int wolfSSL_UseExtendedMasterSecret(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + return TLSX_UseExtendedMasterSecret(&ssl->extensions, ssl->heap); +} + +int wolfSSL_CTX_UseExtendedMasterSecret(WOLFSSL_CTX* ctx) +{ + if (ctx == NULL) + return BAD_FUNC_ARG; + + return TLSX_UseExtendedMasterSecret(&ctx->extensions, ctx->heap); +} + +#endif /* NO_WOLFSSL_CLIENT */ +#endif /* HAVE_EXTENDED_MASTER */ + #ifndef WOLFSSL_LEANPSK int wolfSSL_send(WOLFSSL* ssl, const void* data, int sz, int flags) @@ -7847,6 +7869,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..4e6511d38 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, @@ -3888,6 +3942,58 @@ int TLSX_UseQSHScheme(TLSX** extensions, word16 name, byte* pKey, word16 pkeySz, #endif /* HAVE_QSH */ +/******************************************************************************/ +/* TLS Extended Master Secret */ +/******************************************************************************/ + +#ifdef HAVE_EXTENDED_MASTER + +static int TLSX_EMS_Parse(WOLFSSL* ssl, byte* input, word16 length, + byte isRequest) +{ + (void)isRequest; + + if (length != 0 || input == NULL) + return BUFFER_ERROR; + +#ifndef NO_WOLFSSL_SERVER + if (isRequest) { + int r = TLSX_UseExtendedMasterSecret(&ssl->extensions, ssl->heap); + + if (r != SSL_SUCCESS) + return r; /* throw error */ + + TLSX_SetResponse(ssl, TLSX_EXTENDED_MASTER_SECRET); + } +#endif + + ssl->options.haveEMS = 1; + + return 0; +} + +int TLSX_UseExtendedMasterSecret(TLSX** extensions, void* heap) +{ + int ret = 0; + + if (extensions == NULL) + return BAD_FUNC_ARG; + + if ((ret = TLSX_Push(extensions, TLSX_EXTENDED_MASTER_SECRET, NULL, + heap)) != 0) + return ret; + + return SSL_SUCCESS; +} + +#define EMS_PARSE TLSX_EMS_Parse + +#else + +#define EMS_PARSE(a, b, c, d) 0 + +#endif /* HAVE_EXTENDED_MASTER */ + /******************************************************************************/ /* TLS Extensions Framework */ /******************************************************************************/ @@ -3937,6 +4043,10 @@ void TLSX_FreeAll(TLSX* list, void* heap) CSR2_FREE_ALL(extension->data, heap); break; + case TLSX_EXTENDED_MASTER_SECRET: + /* Nothing to do. */ + break; + case TLSX_RENEGOTIATION_INFO: SCR_FREE_ALL(extension->data, heap); break; @@ -4014,6 +4124,10 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest) length += CSR2_GET_SIZE(extension->data, isRequest); break; + case TLSX_EXTENDED_MASTER_SECRET: + /* always empty. */ + break; + case TLSX_RENEGOTIATION_INFO: length += SCR_GET_SIZE(extension->data, isRequest); break; @@ -4093,6 +4207,10 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, isRequest); break; + case TLSX_EXTENDED_MASTER_SECRET: + /* always empty. */ + break; + case TLSX_RENEGOTIATION_INFO: offset += SCR_WRITE(extension->data, output + offset, isRequest); @@ -4606,6 +4724,12 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, ret = CSR2_PARSE(ssl, input + offset, size, isRequest); break; + case TLSX_EXTENDED_MASTER_SECRET: + WOLFSSL_MSG("Extended Master Secret extension received"); + + ret = EMS_PARSE(ssl, input + offset, size, isRequest); + break; + case TLSX_RENEGOTIATION_INFO: WOLFSSL_MSG("Secure Renegotiation extension received"); diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index bdf8f5bab..f42afc263 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..49ca05821 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -963,6 +963,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 */ @@ -1644,6 +1645,7 @@ typedef enum { TLSX_SUPPORTED_GROUPS = 0x000a, /* a.k.a. Supported Curves */ TLSX_APPLICATION_LAYER_PROTOCOL = 0x0010, /* a.k.a. ALPN */ TLSX_STATUS_REQUEST_V2 = 0x0011, /* a.k.a. OCSP stapling v2 */ + TLSX_EXTENDED_MASTER_SECRET = 0x0017, TLSX_QUANTUM_SAFE_HYBRID = 0x0018, /* a.k.a. QSH */ TLSX_SESSION_TICKET = 0x0023, TLSX_RENEGOTIATION_INFO = 0xff01 @@ -1897,6 +1899,14 @@ WOLFSSL_LOCAL int TLSX_ValidateQSHScheme(TLSX** extensions, word16 name); #endif /* HAVE_QSH */ +/* TLS Extended Master Secret, RFC 7627 */ +#ifdef HAVE_EXTENDED_MASTER + +WOLFSSL_LOCAL int TLSX_UseExtendedMasterSecret(TLSX** extensions, void* heap); + +#endif + + /* wolfSSL context type */ struct WOLFSSL_CTX { WOLFSSL_METHOD* method; @@ -2225,6 +2235,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 +2420,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 +3040,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/ssl.h b/wolfssl/ssl.h index 4f234b058..be86237ea 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1704,6 +1704,16 @@ WOLFSSL_API int wolfSSL_UseSupportedQSH(WOLFSSL* ssl, unsigned short name); #endif #endif +/* TLS Extended Master Secret Extension */ +#ifdef HAVE_EXTENDED_MASTER +#ifndef NO_WOLFSSL_CLIENT + +WOLFSSL_API int wolfSSL_UseExtendedMasterSecret(WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_CTX_UseExtendedMasterSecret(WOLFSSL_CTX* ctx); + +#endif /* NO_WOLFSSL_CLIENT */ +#endif /* HAVE_EXTENDED_MASTER */ + #define WOLFSSL_CRL_MONITOR 0x01 /* monitor this dir flag */ #define WOLFSSL_CRL_START_MON 0x02 /* start monitoring flag */ @@ -1725,6 +1735,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, From 88fab67804bbe507d246e1cc46a161f59005e9ae Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Thu, 1 Sep 2016 15:15:17 -0600 Subject: [PATCH 03/10] add extended master unit tests --- tests/api.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/api.c b/tests/api.c index 11605d1ce..ef8f982f2 100644 --- a/tests/api.c +++ b/tests/api.c @@ -1927,6 +1927,28 @@ static void test_wolfSSL_UseALPN(void) #endif } +static void test_wolfSSL_UseExtendedMasterSecret(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_UseExtendedMasterSecret(NULL)); + AssertIntNE(SSL_SUCCESS, wolfSSL_UseExtendedMasterSecret(NULL)); + + /* success cases */ + AssertIntEQ(SSL_SUCCESS, wolfSSL_CTX_UseExtendedMasterSecret(ctx)); + AssertIntEQ(SSL_SUCCESS, wolfSSL_UseExtendedMasterSecret(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_UseExtendedMasterSecret(); /* X509 tests */ test_wolfSSL_X509_NAME_get_entry(); From 0f0e0ca9a5b2712a1e08b354a2d753695a387f8e Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Thu, 1 Sep 2016 15:17:46 -0600 Subject: [PATCH 04/10] add extended master to example client --- examples/client/client.c | 45 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/examples/client/client.c b/examples/client/client.c index ae61c1a5f..2129f0247 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 Use 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 extMasterSecret = 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 + extMasterSecret = 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 (extMasterSecret) + if (wolfSSL_CTX_UseExtendedMasterSecret(ctx) != SSL_SUCCESS) + err_sys("UseExtendedMasterSecret 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) { From 4fb1431727fa68963043e088a1da3349c8b8c893 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 8 Sep 2016 11:25:02 -0700 Subject: [PATCH 05/10] Added support for the extended master secret extension to the sniffer. --- src/sniffer.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 223 insertions(+), 3 deletions(-) diff --git a/src/sniffer.c b/src/sniffer.c index 577d59110..bcef1f9c5 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 */ }; @@ -329,6 +330,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 +345,27 @@ 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 +#ifdef WOLFSSL_SHA512 + Sha512 hashSha512; +#endif +} HsHashes; + + /* Sniffer Session holds info for each client/server SSL/TLS session */ typedef struct SnifferSession { SnifferServer* context; /* server context */ @@ -363,6 +388,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 +511,9 @@ static void FreeSnifferSession(SnifferSession* session) FreePacketList(session->srvReassemblyList); free(session->ticketID); +#ifdef HAVE_EXTENDED_MASTER + free(session->hash); +#endif } free(session); } @@ -533,6 +564,102 @@ 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 +#ifdef WOLFSSL_SHA512 + if (ret == 0) + ret = wc_InitSha512(&hash->hashSha512); +#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 +#ifdef WOLFSSL_SHA512 + if (ret == 0) + ret = wc_Sha512Update(&hash->hashSha512, 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 +#ifdef WOLFSSL_SHA512 + XMEMCPY(&d->hashSha512, &s->hashSha512, sizeof(Sha512)); +#endif + + return 0; +} + +#endif + + /* Initialize a SnifferServer */ static void InitSnifferServer(SnifferServer* sniffer) { @@ -563,6 +690,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 +730,9 @@ static void InitSession(SnifferSession* session) InitFlags(&session->flags); InitFinCapture(&session->finCaputre); +#ifdef HAVE_EXTENDED_MASTER + session->hash = 0; +#endif } @@ -1483,13 +1616,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 +1685,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 +1951,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 +2076,11 @@ static int DoHandShake(const byte* input, int* sslBytes, return -1; } +#ifdef HAVE_EXTENDED_MASTER + if (session->hash) + HashUpdate(session->hash, input, size); +#endif + switch (type) { case hello_verify_request: Trace(GOT_HELLO_VERIFY_STR); @@ -1896,7 +2094,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,6 +2121,16 @@ static int DoHandShake(const byte* input, int* sslBytes, break; case client_key_exchange: Trace(GOT_CLIENT_KEY_EX_STR); +#ifdef HAVE_EXTENDED_MASTER + if (session->flags.expectEms && session->hash != NULL) { + HashCopy(session->sslServer->hsHashes, session->hash); + HashCopy(session->sslClient->hsHashes, session->hash); + session->sslServer->options.haveEMS = 1; + session->sslClient->options.haveEMS = 1; + free(session->hash); + session->hash = NULL; + } +#endif ret = ProcessClientKeyExchange(input, sslBytes, session, error); break; case certificate_verify: @@ -2135,6 +2343,18 @@ 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; + } + HashInit(newHash); + session->hash = newHash; + } +#endif session->server = ipInfo->dst; session->client = ipInfo->src; session->srvPort = (word16)tcpInfo->dstPort; From b9942440110819bde928c11782cba1f7a069b80c Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 9 Sep 2016 23:16:52 -0700 Subject: [PATCH 06/10] Revising the Extended Master Secret support. Removing the dynamic TLSX support for the extention and treating it like the Signature and Hash algorithms extension. It is to be enabled by default and the user can turn it off at run time or build time. --- configure.ac | 9 +-- examples/client/client.c | 12 +-- src/internal.c | 165 +++++++++++++++++++++++++++++++++------ src/sniffer.c | 4 + src/ssl.c | 31 +++++--- src/tls.c | 121 ++++++++++++---------------- tests/api.c | 12 +-- tests/suites.c | 38 +++++++-- wolfssl/internal.h | 17 ++-- wolfssl/ssl.h | 9 +-- 10 files changed, 271 insertions(+), 147 deletions(-) diff --git a/configure.ac b/configure.ac index 853e71a0b..ba4d2f3ef 100644 --- a/configure.ac +++ b/configure.ac @@ -1959,14 +1959,14 @@ fi # Extended Master Secret Extension AC_ARG_ENABLE([extended-master], - [AS_HELP_STRING([--enable-extended-master],[Enable Extended Master Secret (default: disabled)])], + [AS_HELP_STRING([--enable-extended-master],[Enable Extended Master Secret (default: enabled)])], [ ENABLED_EXTENDED_MASTER=$enableval ], - [ ENABLED_EXTENDED_MASTER=no ] + [ ENABLED_EXTENDED_MASTER=yes ] ) if test "x$ENABLED_EXTENDED_MASTER" = "xyes" then - AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_EXTENDED_MASTER" + AM_CFLAGS="$AM_CFLAGS -DHAVE_EXTENDED_MASTER" fi # TLS Extensions @@ -1983,8 +1983,7 @@ then ENABLED_TRUNCATED_HMAC=yes ENABLED_SUPPORTED_CURVES=yes ENABLED_ALPN=yes - ENABLED_EXTENDED_MASTER=yes - AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_SNI -DHAVE_MAX_FRAGMENT -DHAVE_TRUNCATED_HMAC -DHAVE_SUPPORTED_CURVES -DHAVE_ALPN -DHAVE_EXTENDED_MASTER" + AM_CFLAGS="$AM_CFLAGS -DHAVE_TLS_EXTENSIONS -DHAVE_SNI -DHAVE_MAX_FRAGMENT -DHAVE_TRUNCATED_HMAC -DHAVE_SUPPORTED_CURVES -DHAVE_ALPN" fi # PKCS7 diff --git a/examples/client/client.c b/examples/client/client.c index 2129f0247..14ef26245 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -495,7 +495,7 @@ static void Usage(void) printf("-T Use Truncated HMAC\n"); #endif #ifdef HAVE_EXTENDED_MASTER - printf("-n Use Extended Master Secret\n"); + printf("-n Disable Extended Master Secret\n"); #endif #ifdef HAVE_OCSP printf("-o Perform OCSP lookup on peer certificate\n"); @@ -613,7 +613,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) byte statusRequest = 0; #endif #ifdef HAVE_EXTENDED_MASTER - byte extMasterSecret = 0; + byte disableExtMasterSecret = 0; #endif @@ -865,7 +865,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) case 'n' : #ifdef HAVE_EXTENDED_MASTER - extMasterSecret = 1; + disableExtMasterSecret = 1; #endif break; @@ -1246,9 +1246,9 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args) err_sys("UseSessionTicket failed"); #endif #ifdef HAVE_EXTENDED_MASTER - if (extMasterSecret) - if (wolfSSL_CTX_UseExtendedMasterSecret(ctx) != SSL_SUCCESS) - err_sys("UseExtendedMasterSecret failed"); + if (disableExtMasterSecret) + if (wolfSSL_CTX_DisableExtendedMasterSecret(ctx) != SSL_SUCCESS) + err_sys("DisableExtendedMasterSecret failed"); #endif if (benchmark) { diff --git a/src/internal.c b/src/internal.c index e9556a142..2c3895f16 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; @@ -12681,6 +12699,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 +12733,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 +12830,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 @@ -13058,9 +13097,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; @@ -13082,9 +13120,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; @@ -15979,6 +16078,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 */ @@ -16052,6 +16155,18 @@ 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; + } +#endif #endif ssl->buffers.outputBuffer.length += sendSz; @@ -18155,6 +18270,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; diff --git a/src/sniffer.c b/src/sniffer.c index bcef1f9c5..d2d94e1a9 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -2130,6 +2130,10 @@ static int DoHandShake(const byte* input, int* sslBytes, free(session->hash); session->hash = NULL; } + else { + session->sslServer->options.haveEMS = 0; + session->sslClient->options.haveEMS = 0; + } #endif ret = ProcessClientKeyExchange(input, sslBytes, session, error); break; diff --git a/src/ssl.c b/src/ssl.c index 2e99b5b6e..c6cc0d696 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -1749,27 +1749,34 @@ WOLFSSL_API int wolfSSL_set_SessionTicket_cb(WOLFSSL* ssl, } #endif + #ifdef HAVE_EXTENDED_MASTER #ifndef NO_WOLFSSL_CLIENT -int wolfSSL_UseExtendedMasterSecret(WOLFSSL* ssl) -{ - if (ssl == NULL) - return BAD_FUNC_ARG; - - return TLSX_UseExtendedMasterSecret(&ssl->extensions, ssl->heap); -} - -int wolfSSL_CTX_UseExtendedMasterSecret(WOLFSSL_CTX* ctx) +int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx) { if (ctx == NULL) return BAD_FUNC_ARG; - return TLSX_UseExtendedMasterSecret(&ctx->extensions, ctx->heap); + ctx->haveEMS = 0; + + return SSL_SUCCESS; } -#endif /* NO_WOLFSSL_CLIENT */ -#endif /* HAVE_EXTENDED_MASTER */ + +int wolfSSL_DisableExtendedMasterSecret(WOLFSSL* ssl) +{ + if (ssl == NULL) + return BAD_FUNC_ARG; + + ssl->options.haveEMS = 0; + + return SSL_SUCCESS; +} + +#endif +#endif + #ifndef WOLFSSL_LEANPSK diff --git a/src/tls.c b/src/tls.c index 4e6511d38..648147c2a 100644 --- a/src/tls.c +++ b/src/tls.c @@ -3942,58 +3942,6 @@ int TLSX_UseQSHScheme(TLSX** extensions, word16 name, byte* pKey, word16 pkeySz, #endif /* HAVE_QSH */ -/******************************************************************************/ -/* TLS Extended Master Secret */ -/******************************************************************************/ - -#ifdef HAVE_EXTENDED_MASTER - -static int TLSX_EMS_Parse(WOLFSSL* ssl, byte* input, word16 length, - byte isRequest) -{ - (void)isRequest; - - if (length != 0 || input == NULL) - return BUFFER_ERROR; - -#ifndef NO_WOLFSSL_SERVER - if (isRequest) { - int r = TLSX_UseExtendedMasterSecret(&ssl->extensions, ssl->heap); - - if (r != SSL_SUCCESS) - return r; /* throw error */ - - TLSX_SetResponse(ssl, TLSX_EXTENDED_MASTER_SECRET); - } -#endif - - ssl->options.haveEMS = 1; - - return 0; -} - -int TLSX_UseExtendedMasterSecret(TLSX** extensions, void* heap) -{ - int ret = 0; - - if (extensions == NULL) - return BAD_FUNC_ARG; - - if ((ret = TLSX_Push(extensions, TLSX_EXTENDED_MASTER_SECRET, NULL, - heap)) != 0) - return ret; - - return SSL_SUCCESS; -} - -#define EMS_PARSE TLSX_EMS_Parse - -#else - -#define EMS_PARSE(a, b, c, d) 0 - -#endif /* HAVE_EXTENDED_MASTER */ - /******************************************************************************/ /* TLS Extensions Framework */ /******************************************************************************/ @@ -4043,10 +3991,6 @@ void TLSX_FreeAll(TLSX* list, void* heap) CSR2_FREE_ALL(extension->data, heap); break; - case TLSX_EXTENDED_MASTER_SECRET: - /* Nothing to do. */ - break; - case TLSX_RENEGOTIATION_INFO: SCR_FREE_ALL(extension->data, heap); break; @@ -4124,10 +4068,6 @@ static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest) length += CSR2_GET_SIZE(extension->data, isRequest); break; - case TLSX_EXTENDED_MASTER_SECRET: - /* always empty. */ - break; - case TLSX_RENEGOTIATION_INFO: length += SCR_GET_SIZE(extension->data, isRequest); break; @@ -4207,10 +4147,6 @@ static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore, isRequest); break; - case TLSX_EXTENDED_MASTER_SECRET: - /* always empty. */ - break; - case TLSX_RENEGOTIATION_INFO: offset += SCR_WRITE(extension->data, output + offset, isRequest); @@ -4552,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) @@ -4583,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 */ @@ -4603,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 */ } @@ -4629,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; } @@ -4652,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 */ } @@ -4667,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; @@ -4724,11 +4692,17 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest, ret = CSR2_PARSE(ssl, input + offset, size, isRequest); break; - case TLSX_EXTENDED_MASTER_SECRET: +#ifdef HAVE_EXTENDED_MASTER + case HELLO_EXT_EXTMS: WOLFSSL_MSG("Extended Master Secret extension received"); - ret = EMS_PARSE(ssl, input + offset, size, isRequest); +#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"); @@ -4779,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 ef8f982f2..b5d348ca0 100644 --- a/tests/api.c +++ b/tests/api.c @@ -1927,7 +1927,7 @@ static void test_wolfSSL_UseALPN(void) #endif } -static void test_wolfSSL_UseExtendedMasterSecret(void) +static void test_wolfSSL_DisableExtendedMasterSecret(void) { #ifdef HAVE_EXTENDED_MASTER WOLFSSL_CTX *ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()); @@ -1937,12 +1937,12 @@ static void test_wolfSSL_UseExtendedMasterSecret(void) AssertNotNull(ssl); /* error cases */ - AssertIntNE(SSL_SUCCESS, wolfSSL_CTX_UseExtendedMasterSecret(NULL)); - AssertIntNE(SSL_SUCCESS, wolfSSL_UseExtendedMasterSecret(NULL)); + AssertIntNE(SSL_SUCCESS, wolfSSL_CTX_DisableExtendedMasterSecret(NULL)); + AssertIntNE(SSL_SUCCESS, wolfSSL_DisableExtendedMasterSecret(NULL)); /* success cases */ - AssertIntEQ(SSL_SUCCESS, wolfSSL_CTX_UseExtendedMasterSecret(ctx)); - AssertIntEQ(SSL_SUCCESS, wolfSSL_UseExtendedMasterSecret(ssl)); + AssertIntEQ(SSL_SUCCESS, wolfSSL_CTX_DisableExtendedMasterSecret(ctx)); + AssertIntEQ(SSL_SUCCESS, wolfSSL_DisableExtendedMasterSecret(ssl)); wolfSSL_free(ssl); wolfSSL_CTX_free(ctx); @@ -2151,7 +2151,7 @@ void ApiTest(void) test_wolfSSL_UseTruncatedHMAC(); test_wolfSSL_UseSupportedCurve(); test_wolfSSL_UseALPN(); - test_wolfSSL_UseExtendedMasterSecret(); + 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/wolfssl/internal.h b/wolfssl/internal.h index 49ca05821..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) */ @@ -1645,7 +1646,6 @@ typedef enum { TLSX_SUPPORTED_GROUPS = 0x000a, /* a.k.a. Supported Curves */ TLSX_APPLICATION_LAYER_PROTOCOL = 0x0010, /* a.k.a. ALPN */ TLSX_STATUS_REQUEST_V2 = 0x0011, /* a.k.a. OCSP stapling v2 */ - TLSX_EXTENDED_MASTER_SECRET = 0x0017, TLSX_QUANTUM_SAFE_HYBRID = 0x0018, /* a.k.a. QSH */ TLSX_SESSION_TICKET = 0x0023, TLSX_RENEGOTIATION_INFO = 0xff01 @@ -1899,14 +1899,6 @@ WOLFSSL_LOCAL int TLSX_ValidateQSHScheme(TLSX** extensions, word16 name); #endif /* HAVE_QSH */ -/* TLS Extended Master Secret, RFC 7627 */ -#ifdef HAVE_EXTENDED_MASTER - -WOLFSSL_LOCAL int TLSX_UseExtendedMasterSecret(TLSX** extensions, void* heap); - -#endif - - /* wolfSSL context type */ struct WOLFSSL_CTX { WOLFSSL_METHOD* method; @@ -1946,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 */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index be86237ea..e83749cd2 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1705,14 +1705,9 @@ WOLFSSL_API int wolfSSL_UseSupportedQSH(WOLFSSL* ssl, unsigned short name); #endif /* TLS Extended Master Secret Extension */ -#ifdef HAVE_EXTENDED_MASTER -#ifndef NO_WOLFSSL_CLIENT +WOLFSSL_API int wolfSSL_DisableExtendedMasterSecret(WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx); -WOLFSSL_API int wolfSSL_UseExtendedMasterSecret(WOLFSSL* ssl); -WOLFSSL_API int wolfSSL_CTX_UseExtendedMasterSecret(WOLFSSL_CTX* ctx); - -#endif /* NO_WOLFSSL_CLIENT */ -#endif /* HAVE_EXTENDED_MASTER */ #define WOLFSSL_CRL_MONITOR 0x01 /* monitor this dir flag */ #define WOLFSSL_CRL_START_MON 0x02 /* start monitoring flag */ From c1136a30e9b70bebf681bf755d467d348ddd4e26 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 12 Sep 2016 09:42:42 -0700 Subject: [PATCH 07/10] 1. Enabled the extended master secret in the Windows IDE user_settings.h file by default. 2. Fixed scan-build warning about an assignment to a variable that isn't used again in the function. Commented out the line. --- IDE/WIN/user_settings.h | 1 + src/internal.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) 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/src/internal.c b/src/internal.c index 2c3895f16..e9b6850cc 100755 --- a/src/internal.c +++ b/src/internal.c @@ -16164,7 +16164,9 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, c16toa(HELLO_EXT_EXTMS, output + idx); idx += HELLO_EXT_TYPE_SZ; c16toa(0, output + idx); - idx += HELLO_EXT_SZ_SZ; + /*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 From 77cf7006571dbca1dac9a9ecbabcd050b649a920 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 12 Sep 2016 14:24:56 -0700 Subject: [PATCH 08/10] Update to allow resumption with session tickets and extended master secret. --- src/internal.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/internal.c b/src/internal.c index e9b6850cc..618c4f6eb 100755 --- a/src/internal.c +++ b/src/internal.c @@ -18732,6 +18732,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 */ @@ -18753,6 +18754,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; @@ -18762,6 +18765,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)); @@ -18853,8 +18857,10 @@ 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); + ssl->session.haveEMS = it->haveEMS; + } return ret; } From 8b713adcfd7f0b03bf713498d29d2de9967b9b29 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 14 Sep 2016 13:43:02 -0700 Subject: [PATCH 09/10] Extended Master Secret Peer Review Changes 1. Checked the returns on the hash functions in the sniffer, return new error if any fail. 2. Removed the SHA-512 hash from the sniffer's collection of hashes. Never used in a cipher suite. 3. Added some logging messages in the EMS support in wolfSSL. --- src/internal.c | 7 ++++++ src/sniffer.c | 53 +++++++++++++++++++++++----------------- wolfssl/sniffer_error.h | 1 + wolfssl/sniffer_error.rc | 1 + 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/internal.c b/src/internal.c index 618c4f6eb..c94b5c7fc 100755 --- a/src/internal.c +++ b/src/internal.c @@ -18313,10 +18313,15 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* 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; } } @@ -18859,6 +18864,8 @@ int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx, /* get master secret */ 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; } diff --git a/src/sniffer.c b/src/sniffer.c index d2d94e1a9..49627960b 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -254,7 +254,8 @@ static const char* const msgTable[] = "Clear ACK Fault", /* 81 */ - "Bad Decrypt Size" + "Bad Decrypt Size", + "Extended Master Secret Hash Error" }; @@ -360,9 +361,6 @@ typedef struct HsHashes { #ifdef WOLFSSL_SHA384 Sha384 hashSha384; #endif -#ifdef WOLFSSL_SHA512 - Sha512 hashSha512; -#endif } HsHashes; @@ -590,10 +588,6 @@ static int HashInit(HsHashes* hash) if (ret == 0) ret = wc_InitSha384(&hash->hashSha384); #endif -#ifdef WOLFSSL_SHA512 - if (ret == 0) - ret = wc_InitSha512(&hash->hashSha512); -#endif return ret; } @@ -624,10 +618,6 @@ static int HashUpdate(HsHashes* hash, const byte* input, int sz) if (ret == 0) ret = wc_Sha384Update(&hash->hashSha384, input, sz); #endif -#ifdef WOLFSSL_SHA512 - if (ret == 0) - ret = wc_Sha512Update(&hash->hashSha512, input, sz); -#endif return ret; } @@ -650,9 +640,6 @@ static int HashCopy(HS_Hashes* d, HsHashes* s) #ifdef WOLFSSL_SHA384 XMEMCPY(&d->hashSha384, &s->hashSha384, sizeof(Sha384)); #endif -#ifdef WOLFSSL_SHA512 - XMEMCPY(&d->hashSha512, &s->hashSha512, sizeof(Sha512)); -#endif return 0; } @@ -2077,8 +2064,13 @@ static int DoHandShake(const byte* input, int* sslBytes, } #ifdef HAVE_EXTENDED_MASTER - if (session->hash) - HashUpdate(session->hash, input, size); + 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) { @@ -2123,10 +2115,20 @@ static int DoHandShake(const byte* input, int* sslBytes, Trace(GOT_CLIENT_KEY_EX_STR); #ifdef HAVE_EXTENDED_MASTER if (session->flags.expectEms && session->hash != NULL) { - HashCopy(session->sslServer->hsHashes, session->hash); - HashCopy(session->sslClient->hsHashes, session->hash); - session->sslServer->options.haveEMS = 1; - session->sslClient->options.haveEMS = 1; + 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; } @@ -2135,7 +2137,8 @@ static int DoHandShake(const byte* input, int* sslBytes, session->sslClient->options.haveEMS = 0; } #endif - ret = ProcessClientKeyExchange(input, sslBytes, session, error); + if (ret == 0) + ret = ProcessClientKeyExchange(input, sslBytes, session, error); break; case certificate_verify: Trace(GOT_CERT_VER_STR); @@ -2355,7 +2358,11 @@ static SnifferSession* CreateSession(IpInfo* ipInfo, TcpInfo* tcpInfo, free(session); return 0; } - HashInit(newHash); + if (HashInit(newHash) != 0) { + SetError(EXTENDED_MASTER_HASH_STR, error, NULL, 0); + free(session); + return 0; + } session->hash = newHash; } #endif 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" } From 19434e285a11bc6d77810645a8701e5ca22239c8 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 15 Sep 2016 10:13:31 -0700 Subject: [PATCH 10/10] Update the resume test to rerun itself with the "-n" option to disable extended master secret if the option is enabled. --- scripts/resume.test | 110 +++++++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 47 deletions(-) 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