TLS: detect duplicate known extensions

TLS specification requires that there not be more than one extension of
the same type in a given extension block. E.g. ClientHello
pull/5872/head
Sean Parkinson 2022-12-09 10:49:23 +10:00
parent c959d22b98
commit 9ab8867b42
4 changed files with 135 additions and 0 deletions

View File

@ -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";
}

View File

@ -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;

View File

@ -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),

View File

@ -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 */