diff --git a/src/sniffer.c b/src/sniffer.c index 5658de58c..dfaec0538 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -452,6 +452,11 @@ 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_MAX_FRAGMENT + byte* tlsFragBuf; + word32 tlsFragOffset; + word32 tlsFragSize; +#endif #ifdef HAVE_SNI const char* sni; /* server name indication */ #endif @@ -648,6 +653,12 @@ static void FreeSnifferSession(SnifferSession* session) #ifdef WOLFSSL_TLS13 if (session->cliKeyShare) XFREE(session->cliKeyShare, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif +#ifdef HAVE_MAX_FRAGMENT + if (session->tlsFragBuf) { + XFREE(session->tlsFragBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + session->tlsFragBuf = NULL; + } #endif } XFREE(session, NULL, DYNAMIC_TYPE_SNIFFER_SESSION); @@ -666,14 +677,7 @@ void ssl_FreeSniffer(void) wc_LockMutex(&ServerListMutex); wc_LockMutex(&SessionMutex); - srv = ServerList; - while (srv) { - removeServer = srv; - srv = srv->next; - FreeSnifferServer(removeServer); - } - ServerList = NULL; - + /* Free sessions (wolfSSL objects) first */ for (i = 0; i < HASH_SIZE; i++) { session = SessionTable[i]; while (session) { @@ -684,6 +688,15 @@ void ssl_FreeSniffer(void) } SessionCount = 0; + /* Then server (wolfSSL_CTX) */ + srv = ServerList; + while (srv) { + removeServer = srv; + srv = srv->next; + FreeSnifferServer(removeServer); + } + ServerList = NULL; + wc_UnLockMutex(&SessionMutex); wc_UnLockMutex(&ServerListMutex); @@ -1895,7 +1908,7 @@ static int CheckIp6Hdr(Ip6Hdr* iphdr, IpInfo* info, int length, char* error) /* returns 0 on success, -1 on error */ static int CheckIpHdr(IpHdr* iphdr, IpInfo* info, int length, char* error) { - int version = IP_V(iphdr); + int version = IP_V(iphdr); if (version == IPV6) return CheckIp6Hdr((Ip6Hdr*)iphdr, info, length, error); @@ -2055,6 +2068,11 @@ static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, { word32 idx = 0; int ret; +#ifdef HAVE_ECC + int useEccCurveId = ECC_CURVE_DEF; + if (ksInfo && ksInfo->curve_id != 0) + useEccCurveId = ksInfo->curve_id; +#endif #ifndef NO_RSA /* Static RSA */ @@ -2074,6 +2092,11 @@ static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, SetError(RSA_DECODE_STR, error, session, 0); #endif } + #ifdef HAVE_ECC + else { + useEccCurveId = -1; /* don't try loading ECC */ + } + #endif } if (ret == 0) { @@ -2124,7 +2147,7 @@ static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, #endif /* !NO_RSA */ #if !defined(NO_DH) && defined(WOLFSSL_DH_EXTRA) - /* Static Ephemeral DH Key */ + /* Static DH Key */ if (ksInfo && ksInfo->dh_key_bits != 0) { DhKey dhKey; const DhParams* params; @@ -2212,8 +2235,8 @@ static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, #endif /* !NO_DH && WOLFSSL_DH_EXTRA */ #ifdef HAVE_ECC - /* Static Ephemeral ECC Key */ - if (ksInfo && ksInfo->curve_id != 0) { + /* Static ECC Key */ + if (useEccCurveId >= ECC_CURVE_DEF) { ecc_key key; ecc_key pubKey; int length, keyInit = 0, pubKeyInit = 0; @@ -2224,6 +2247,15 @@ static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, keyInit = 1; ret = wc_ecc_init(&pubKey); } + + #if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \ + !defined(HAVE_SELFTEST) + if (ret == 0) { + ret = wc_ecc_set_rng(&key, session->sslServer->rng); + } + #endif + if (ret == 0) { pubKeyInit = 1; ret = wc_EccPrivateKeyDecode(keyBuf->buffer, &idx, &key, keyBuf->length); @@ -2247,7 +2279,7 @@ static int SetupKeys(const byte* input, int* sslBytes, SnifferSession* session, } if (ret == 0) { - ret = wc_ecc_import_x963_ex(input, length, &pubKey, ksInfo->curve_id); + ret = wc_ecc_import_x963_ex(input, length, &pubKey, useEccCurveId); if (ret != 0) { SetError(ECC_PUB_DECODE_STR, error, session, FATAL_ERROR_STATE); } @@ -2743,12 +2775,34 @@ static int ProcessServerHello(int msgSz, const byte* input, int* sslBytes, session->sslClient->session.ticketNonce.len = 1; session->sslClient->session.ticketNonce.data[0] = 0; break; + #endif + #ifdef HAVE_MAX_FRAGMENT + case EXT_MAX_FRAGMENT_LENGTH: + { + word16 max_fragment = MAX_RECORD_SIZE; + switch (input[0]) { + case WOLFSSL_MFL_2_8 : max_fragment = 256; break; + case WOLFSSL_MFL_2_9 : max_fragment = 512; break; + case WOLFSSL_MFL_2_10: max_fragment = 1024; break; + case WOLFSSL_MFL_2_11: max_fragment = 2048; break; + case WOLFSSL_MFL_2_12: max_fragment = 4096; break; + case WOLFSSL_MFL_2_13: max_fragment = 8192; break; + default: break; + } + session->sslServer->max_fragment = max_fragment; + session->sslClient->max_fragment = max_fragment; + break; + } #endif case EXT_SUPPORTED_VERSIONS: session->sslServer->version.major = input[0]; session->sslServer->version.minor = input[1]; session->sslClient->version.major = input[0]; session->sslClient->version.minor = input[1]; + if (IsAtLeastTLSv1_3(session->sslServer->version)) { + /* The server side handshake encryption is on for future packets */ + session->flags.serverCipherOn = 1; + } break; case EXT_MASTER_SECRET: #ifdef HAVE_EXTENDED_MASTER @@ -2971,6 +3025,10 @@ static int ProcessClientHello(const byte* input, int* sslBytes, } wc_UnLockMutex(&session->context->namedKeysMutex); } + if (ret > 0) { + /* make sure WOLFSSL_SUCCESS is converted to zero error code */ + ret = 0; + } } #endif @@ -3098,9 +3156,6 @@ static int ProcessClientHello(const byte* input, int* sslBytes, break; } XMEMCPY(session->cliKeyShare, &input[2], ksLen); - - /* The server side handshake encryption is on for future packets */ - session->flags.serverCipherOn = 1; break; } #ifdef HAVE_SESSION_TICKET @@ -3252,7 +3307,6 @@ static int KeyWatchCall(SnifferSession* session, const byte* data, int dataSz, static int ProcessCertificate(const byte* input, int* sslBytes, SnifferSession* session, char* error) { - int ret; const byte* certChain; word32 certChainSz; word32 certSz; @@ -3407,13 +3461,32 @@ static int ProcessFinished(const byte* input, int size, int* sslBytes, /* Process HandShake input */ static int DoHandShake(const byte* input, int* sslBytes, - SnifferSession* session, char* error) + SnifferSession* session, char* error, word16 rhSize) { byte type; int size; int ret = 0; - int startBytes; WOLFSSL* ssl; + int startBytes; + + (void)rhSize; + +#ifdef HAVE_MAX_FRAGMENT + if (session->tlsFragBuf) { + XMEMCPY(session->tlsFragBuf + session->tlsFragOffset, input, rhSize); + session->tlsFragOffset += rhSize; + *sslBytes -= rhSize; + + if (session->tlsFragOffset < session->tlsFragSize) { + return 0; + } + + /* reassembled complete fragment */ + input = session->tlsFragBuf; + *sslBytes = session->tlsFragSize; + rhSize = session->tlsFragSize; + } +#endif if (*sslBytes < HANDSHAKE_HEADER_SZ) { SetError(HANDSHAKE_INPUT_STR, error, session, FATAL_ERROR_STATE); @@ -3449,6 +3522,30 @@ static int DoHandShake(const byte* input, int* sslBytes, } #endif +#ifdef HAVE_MAX_FRAGMENT + if (rhSize < size) { + /* partial fragment, let's reassemble */ + if (session->tlsFragBuf == NULL) { + session->tlsFragOffset = 0; + session->tlsFragSize = size + HANDSHAKE_HEADER_SZ; + session->tlsFragBuf = (byte*)XMALLOC(session->tlsFragSize, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (session->tlsFragBuf == NULL) { + SetError(MEMORY_STR, error, NULL, 0); + return 0; + } + + /* include the handshake header */ + input -= HANDSHAKE_HEADER_SZ; + *sslBytes += HANDSHAKE_HEADER_SZ; + } + + XMEMCPY(session->tlsFragBuf + session->tlsFragOffset, input, rhSize); + session->tlsFragOffset += rhSize; + *sslBytes -= rhSize; + return 0; + } +#endif + #ifdef WOLFSSL_TLS13 if (type != client_hello) { /* For resumption the hash is before / after client_hello PSK binder */ @@ -3465,7 +3562,8 @@ static int DoHandShake(const byte* input, int* sslBytes, if (HashUpdate(session->hash, input, size) != 0) { SetError(EXTENDED_MASTER_HASH_STR, error, session, FATAL_ERROR_STATE); - return -1; + ret = -1; + goto exit; } } #endif @@ -3560,9 +3658,18 @@ static int DoHandShake(const byte* input, int* sslBytes, break; default: SetError(GOT_UNKNOWN_HANDSHAKE_STR, error, session, 0); - return -1; + ret = -1; + break; } +exit: +#ifdef HAVE_MAX_FRAGMENT + if (session->tlsFragBuf) { + XFREE(session->tlsFragBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + session->tlsFragBuf = NULL; + } +#endif + *sslBytes = startBytes - size; /* actual bytes of full process */ return ret; @@ -3982,6 +4089,9 @@ int TcpChecksum(IpInfo* ipInfo, TcpInfo* tcpInfo, int dataLen, static int CheckHeaders(IpInfo* ipInfo, TcpInfo* tcpInfo, const byte* packet, int length, const byte** sslFrame, int* sslBytes, char* error) { + IpHdr* iphdr = (IpHdr*)packet; + int version; + TraceHeader(); TracePacket(); @@ -3990,6 +4100,17 @@ static int CheckHeaders(IpInfo* ipInfo, TcpInfo* tcpInfo, const byte* packet, SetError(PACKET_HDR_SHORT_STR, error, NULL, 0); return -1; } + + version = IP_V(iphdr); + if (version != IPV6 && version != IPV4) { + /* Is this VLAN IEEE 802.1Q Frame? TPID = 0x8100 */ + if (packet[2] == 0x81 && packet[3] == 0x00) { + /* trim VLAN header and try again */ + packet += 8; + length -= 8; + } + } + if (CheckIpHdr((IpHdr*)packet, ipInfo, length, error) != 0) return -1; @@ -4822,8 +4943,8 @@ doPart: int used; Trace(GOT_HANDSHAKE_STR); - ret = DoHandShake(sslFrame, &sslBytes, session, error); - if (ret != 0) { + ret = DoHandShake(sslFrame, &sslBytes, session, error, rhSize); + if (ret != 0 || sslBytes > startIdx) { if (session->flags.fatalError == 0) SetError(BAD_HANDSHAKE_STR, error, session, FATAL_ERROR_STATE); diff --git a/sslSniffer/README.md b/sslSniffer/README.md index a9c48eecc..34d46c2ab 100644 --- a/sslSniffer/README.md +++ b/sslSniffer/README.md @@ -43,9 +43,9 @@ All options may be enabled with the following configure command line: ```sh ./configure --enable-sniffer \ - CPPFLAGS=”-DWOLFSSL_SNIFFER_STATS -DWOLFSSL_SNIFFER_WATCH \ + CPPFLAGS="-DWOLFSSL_SNIFFER_STATS -DWOLFSSL_SNIFFER_WATCH \ -DWOLFSSL_SNIFFER_STORE_DATA_CB -DWOLFSSL_SNIFFER_CHAIN_INPUT \ - -DSTARTTLS_ALLOWED” + -DSTARTTLS_ALLOWED" ``` To add some other cipher support to the sniffer, you can add options like: diff --git a/sslSniffer/sslSnifferTest/snifftest.c b/sslSniffer/sslSnifferTest/snifftest.c index 2330f693a..ec4fc31a2 100644 --- a/sslSniffer/sslSnifferTest/snifftest.c +++ b/sslSniffer/sslSnifferTest/snifftest.c @@ -267,8 +267,11 @@ static int myWatchCb(void* vSniffer, certName = DEFAULT_SERVER_KEY_ECC; } - if (certName == NULL) - return -1; + if (certName == NULL) { + /* don't return error if key is not loaded */ + printf("Warning: No matching key found for cert hash\n"); + return 0; + } return ssl_SetWatchKey_file(vSniffer, certName, FILETYPE_PEM, NULL, error); }