diff --git a/src/internal.c b/src/internal.c index 44640fbad..f22fbd0c3 100644 --- a/src/internal.c +++ b/src/internal.c @@ -23355,6 +23355,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case DTLS_TOO_MANY_FRAGMENTS_E: return "Received too many fragmented messages from peer error"; + case DUPLICATE_TLS_EXT_E: + return "Duplicate TLS extension in message."; + default : return "unknown error number"; } diff --git a/src/tls.c b/src/tls.c index 88d555e68..f37ec67b7 100644 --- a/src/tls.c +++ b/src/tls.c @@ -1246,6 +1246,8 @@ int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz, * When adding a new extension type that don't extrapolate the number of * available semaphores, check for a possible collision with with a * 'remapped' extension type. + * + * Update TLSX_Parse for duplicate detection if more added above 62. */ static WC_INLINE word16 TLSX_ToSemaphore(word16 type) { @@ -11918,10 +11920,14 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType, #if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)) int pskDone = 0; #endif + byte seenType[SEMAPHORE_SIZE]; /* Seen known extensions. */ if (!ssl || !input || (isRequest && !suites)) return BAD_FUNC_ARG; + /* No known extensions seen yet. */ + XMEMSET(seenType, 0, sizeof(seenType)); + while (ret == 0 && offset < length) { word16 type; word16 size; @@ -11942,6 +11948,22 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType, ato16(input + offset, &size); offset += OPAQUE16_LEN; + /* Check we have a bit for extension type. */ + if ((type <= 62) || (type == TLSX_RENEGOTIATION_INFO) + #ifdef WOLFSSL_QUIC + || (type == TLSX_KEY_QUIC_TP_PARAMS_DRAFT) + #endif + ) + { + /* Detect duplicate recognized extensions. */ + if (IS_OFF(seenType, TLSX_ToSemaphore(type))) { + TURN_ON(seenType, TLSX_ToSemaphore(type)); + } + else { + return DUPLICATE_TLS_EXT_E; + } + } + if (length - offset < size) return BUFFER_ERROR; diff --git a/tests/api.c b/tests/api.c index c3fa9d2b4..a9e20b923 100644 --- a/tests/api.c +++ b/tests/api.c @@ -9132,6 +9132,113 @@ static int test_wolfSSL_wolfSSL_UseSecureRenegotiation(void) return res; } +#if !defined(NO_WOLFSSL_SERVER) && (!defined(NO_RSA) || defined(HAVE_ECC)) +/* Called when writing. */ +static int DummySend(WOLFSSL* ssl, char* buf, int sz, void* ctx) +{ + (void)ssl; + (void)buf; + (void)sz; + (void)ctx; + + /* Force error return from wolfSSL_accept_TLSv13(). */ + return WANT_WRITE; +} +/* Called when reading. */ +static int BufferInfoRecv(WOLFSSL* ssl, char* buf, int sz, void* ctx) +{ + WOLFSSL_BUFFER_INFO* msg = (WOLFSSL_BUFFER_INFO*)ctx; + int len = (int)msg->length; + + (void)ssl; + (void)sz; + + /* Pass back as much of message as will fit in buffer. */ + if (len > sz) + len = sz; + XMEMCPY(buf, msg->buffer, len); + /* Move over returned data. */ + msg->buffer += len; + msg->length -= len; + + /* Amount actually copied. */ + return len; +} +#endif + +/* Test the detection of duplicate known TLS extensions. + * Specifically in a ClientHello. + */ +static int test_tls_ext_duplicate(void) +{ + int res = TEST_SKIPPED; +#if !defined(NO_WOLFSSL_SERVER) && (!defined(NO_RSA) || defined(HAVE_ECC)) + static unsigned char clientHelloDupTlsExt[] = { + 0x16, 0x03, 0x03, 0x00, 0x6a, 0x01, 0x00, 0x00, + 0x66, 0x03, 0x03, 0xf4, 0x65, 0xbd, 0x22, 0xfe, + 0x6e, 0xab, 0x66, 0xdd, 0xcf, 0xe9, 0x65, 0x55, + 0xe8, 0xdf, 0xc3, 0x8e, 0x4b, 0x00, 0xbc, 0xf8, + 0x23, 0x57, 0x1b, 0xa0, 0xc8, 0xa9, 0xe2, 0x8c, + 0x91, 0x6e, 0xf9, 0x20, 0xf7, 0x5c, 0xc5, 0x5b, + 0x75, 0x8c, 0x47, 0x0a, 0x0e, 0xc4, 0x1a, 0xda, + 0xef, 0x75, 0xe5, 0x21, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x13, 0x01, + 0x00, 0x9e, 0x01, 0x00, + /* Extensions - duplicate signature algorithms. */ + 0x00, 0x19, 0x00, 0x0d, + 0x00, 0x04, 0x00, 0x02, 0x04, 0x01, 0x00, 0x0d, + 0x00, 0x04, 0x00, 0x02, 0x04, 0x01, + /* Supported Versions extension for TLS 1.3. */ + 0x00, 0x2b, + 0x00, 0x05, 0x04, 0x03, 0x04, 0x03, 0x03 + + + }; + WOLFSSL_BUFFER_INFO msg; + const char* testCertFile; + const char* testKeyFile; + WOLFSSL_CTX *ctx; + WOLFSSL *ssl; + +#ifndef NO_RSA + testCertFile = svrCertFile; + testKeyFile = svrKeyFile; +#elif defined(HAVE_ECC) + testCertFile = eccCertFile; + testKeyFile = eccKeyFile; +#endif + + ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()); + AssertNotNull(ctx); + + AssertTrue(wolfSSL_CTX_use_certificate_file(ctx, testCertFile, + WOLFSSL_FILETYPE_PEM)); + AssertTrue(wolfSSL_CTX_use_PrivateKey_file(ctx, testKeyFile, + WOLFSSL_FILETYPE_PEM)); + + /* Read from 'msg'. */ + wolfSSL_SetIORecv(ctx, BufferInfoRecv); + /* No where to send to - dummy sender. */ + wolfSSL_SetIOSend(ctx, DummySend); + + ssl = wolfSSL_new(ctx); + AssertNotNull(ssl); + + msg.buffer = clientHelloDupTlsExt; + msg.length = (unsigned int)sizeof(clientHelloDupTlsExt); + wolfSSL_SetIOReadCtx(ssl, &msg); + + AssertIntNE(wolfSSL_accept(ssl), WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_get_error(ssl, 0), DUPLICATE_TLS_EXT_E); + + wolfSSL_free(ssl); + wolfSSL_CTX_free(ctx); + + res = TEST_RES_CHECK(1); +#endif + return res; +} /*----------------------------------------------------------------------------* | X509 Tests @@ -59358,6 +59465,7 @@ TEST_CASE testCases[] = { #endif TEST_DECL(test_wolfSSL_DisableExtendedMasterSecret), TEST_DECL(test_wolfSSL_wolfSSL_UseSecureRenegotiation), + TEST_DECL(test_tls_ext_duplicate), /* X509 tests */ TEST_DECL(test_wolfSSL_X509_NAME_get_entry), diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 8da041a24..94a5b97fa 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -181,6 +181,8 @@ enum wolfSSL_ErrorCodes { DTLS_CID_ERROR = -454, /* Wrong or missing CID */ DTLS_TOO_MANY_FRAGMENTS_E = -455, /* Received too many fragments */ QUIC_WRONG_ENC_LEVEL = -456, /* QUIC data received on wrong encryption level */ + + DUPLICATE_TLS_EXT_E = -457, /* Duplicate TLS extension in msg. */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ /* begin negotiation parameter errors */