Skip to content

Commit 8ea0105

Browse files
authored
Merge pull request #8788 from julek-wolfssl/gh/8765
tls13: handle malformed CCS and CCS before CH
2 parents 3032e97 + 2ec6b92 commit 8ea0105

6 files changed

Lines changed: 195 additions & 2 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2633,6 +2633,7 @@ if(WOLFSSL_EXAMPLES)
26332633
tests/api/test_ocsp.c
26342634
tests/api/test_evp.c
26352635
tests/api/test_tls_ext.c
2636+
tests/api/test_tls.c
26362637
tests/srp.c
26372638
tests/suites.c
26382639
tests/w64wrapper.c

src/internal.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22126,7 +22126,11 @@ static int DoProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
2212622126
if ( ssl->options.side == WOLFSSL_SERVER_END &&
2212722127
ssl->options.clientState == NULL_STATE &&
2212822128
ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx]
22129-
!= handshake) {
22129+
!= handshake &&
22130+
/* change_cipher_spec here is an error but we want to handle
22131+
* it correctly later */
22132+
ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx]
22133+
!= change_cipher_spec) {
2213022134
byte b0, b1;
2213122135

2213222136
ssl->options.processReply = runProcessOldClientHello;
@@ -22742,11 +22746,18 @@ static int DoProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
2274222746
}
2274322747
if (ssl->curSize != 1 ||
2274422748
ssl->buffers.inputBuffer.buffer[i] != 1) {
22745-
SendAlert(ssl, alert_fatal, illegal_parameter);
22749+
SendAlert(ssl, alert_fatal, unexpected_message);
2274622750
WOLFSSL_ERROR_VERBOSE(UNKNOWN_RECORD_TYPE);
2274722751
return UNKNOWN_RECORD_TYPE;
2274822752
}
2274922753
ssl->buffers.inputBuffer.idx++;
22754+
if (ssl->options.side == WOLFSSL_SERVER_END &&
22755+
!ssl->msgsReceived.got_client_hello) {
22756+
/* Can't appear before CH */
22757+
SendAlert(ssl, alert_fatal, unexpected_message);
22758+
WOLFSSL_ERROR_VERBOSE(UNKNOWN_RECORD_TYPE);
22759+
return UNKNOWN_RECORD_TYPE;
22760+
}
2275022761
if (!ssl->msgsReceived.got_change_cipher) {
2275122762
ssl->msgsReceived.got_change_cipher = 1;
2275222763
}
@@ -22755,6 +22766,11 @@ static int DoProcessReplyEx(WOLFSSL* ssl, int allowSocketErr)
2275522766
WOLFSSL_ERROR_VERBOSE(UNKNOWN_RECORD_TYPE);
2275622767
return UNKNOWN_RECORD_TYPE;
2275722768
}
22769+
if (ssl->keys.decryptedCur == 1) {
22770+
SendAlert(ssl, alert_fatal, unexpected_message);
22771+
WOLFSSL_ERROR_VERBOSE(UNKNOWN_RECORD_TYPE);
22772+
return UNKNOWN_RECORD_TYPE;
22773+
}
2275822774
break;
2275922775
}
2276022776
#endif

tests/api.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@
324324
#include <tests/api/test_ocsp.h>
325325
#include <tests/api/test_evp.h>
326326
#include <tests/api/test_tls_ext.h>
327+
#include <tests/api/test_tls.h>
327328

328329
#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && !defined(NO_TLS) && \
329330
!defined(NO_RSA) && !defined(SINGLE_THREADED) && \
@@ -68182,6 +68183,8 @@ TEST_CASE testCases[] = {
6818268183
TEST_DECL(test_ocsp_basic_verify),
6818368184
TEST_DECL(test_ocsp_response_parsing),
6818468185
TEST_DECL(test_ocsp_certid_enc_dec),
68186+
TEST_DECL(test_tls12_unexpected_ccs),
68187+
TEST_DECL(test_tls13_unexpected_ccs),
6818568188
/* This test needs to stay at the end to clean up any caches allocated. */
6818668189
TEST_DECL(test_wolfSSL_Cleanup)
6818768190
};

tests/api/include.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ tests_unit_test_SOURCES += tests/api/test_dtls.c
5353
tests_unit_test_SOURCES += tests/api/test_ocsp.c
5454
tests_unit_test_SOURCES += tests/api/test_evp.c
5555
tests_unit_test_SOURCES += tests/api/test_tls_ext.c
56+
tests_unit_test_SOURCES += tests/api/test_tls.c
5657
endif
5758

5859
EXTRA_DIST += tests/api/api.h
@@ -103,4 +104,5 @@ EXTRA_DIST += tests/api/test_ocsp_test_blobs.h
103104
EXTRA_DIST += tests/api/create_ocsp_test_blobs.py
104105
EXTRA_DIST += tests/api/test_evp.h
105106
EXTRA_DIST += tests/api/test_tls_ext.h
107+
EXTRA_DIST += tests/api/test_tls.h
106108

tests/api/test_tls.c

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/* test_tls.c
2+
*
3+
* Copyright (C) 2006-2025 wolfSSL Inc.
4+
*
5+
* This file is part of wolfSSL.
6+
*
7+
* wolfSSL is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 2 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfSSL is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*/
21+
22+
#include <tests/unit.h>
23+
24+
#ifdef NO_INLINE
25+
#include <wolfssl/wolfcrypt/misc.h>
26+
#else
27+
#define WOLFSSL_MISC_INCLUDED
28+
#include <wolfcrypt/src/misc.c>
29+
#endif
30+
31+
#include <tests/utils.h>
32+
#include <tests/api/test_tls.h>
33+
34+
35+
int test_tls12_unexpected_ccs(void)
36+
{
37+
EXPECT_DECLS;
38+
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12)
39+
const byte ccs[] = {
40+
0x14, /* ccs type */
41+
0x03, 0x03, /* version */
42+
0x00, 0x01, /* length */
43+
0x01, /* ccs value */
44+
};
45+
const byte badccs[] = {
46+
0x14, /* ccs type */
47+
0x03, 0x03, /* version */
48+
0x00, 0x01, /* length */
49+
0x99, /* wrong ccs value */
50+
};
51+
WOLFSSL_CTX *ctx_s = NULL;
52+
WOLFSSL *ssl_s = NULL;
53+
struct test_memio_ctx test_ctx;
54+
55+
/* ccs in the wrong place */
56+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
57+
/* inject SH */
58+
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0,
59+
(const char*)ccs, sizeof(ccs)), 0);
60+
ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s,
61+
NULL, wolfTLSv1_2_server_method), 0);
62+
ExpectIntEQ(wolfSSL_accept(ssl_s), WOLFSSL_FATAL_ERROR);
63+
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
64+
OUT_OF_ORDER_E);
65+
wolfSSL_free(ssl_s);
66+
wolfSSL_CTX_free(ctx_s);
67+
ctx_s = NULL;
68+
ssl_s = NULL;
69+
70+
/* malformed ccs */
71+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
72+
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0,
73+
(const char*)badccs, sizeof(badccs)), 0);
74+
ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s,
75+
NULL, wolfTLSv1_2_server_method), 0);
76+
ExpectIntEQ(wolfSSL_accept(ssl_s), WOLFSSL_FATAL_ERROR);
77+
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
78+
LENGTH_ERROR);
79+
wolfSSL_free(ssl_s);
80+
wolfSSL_CTX_free(ctx_s);
81+
#endif
82+
return EXPECT_RESULT();
83+
}
84+
85+
int test_tls13_unexpected_ccs(void)
86+
{
87+
EXPECT_DECLS;
88+
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13)
89+
const byte ccs[] = {
90+
0x14, /* ccs type */
91+
0x03, 0x03, /* version */
92+
0x00, 0x01, /* length */
93+
0x01, /* ccs value */
94+
};
95+
const byte badccs[] = {
96+
0x14, /* ccs type */
97+
0x03, 0x03, /* version */
98+
0x00, 0x01, /* length */
99+
0x99, /* wrong ccs value */
100+
};
101+
const byte unexpectedAlert[] = {
102+
0x15, /* alert type */
103+
0x03, 0x03, /* version */
104+
0x00, 0x02, /* length */
105+
0x02, /* level: fatal */
106+
0x0a /* protocol version */
107+
};
108+
WOLFSSL_CTX *ctx_s = NULL;
109+
WOLFSSL *ssl_s = NULL;
110+
struct test_memio_ctx test_ctx;
111+
112+
/* ccs can't appear before a CH */
113+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
114+
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0,
115+
(const char*)ccs, sizeof(ccs)), 0);
116+
ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s,
117+
NULL, wolfTLSv1_3_server_method), 0);
118+
ExpectIntEQ(wolfSSL_accept(ssl_s), WOLFSSL_FATAL_ERROR);
119+
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
120+
UNKNOWN_RECORD_TYPE);
121+
ExpectIntEQ(test_ctx.c_len, sizeof(unexpectedAlert));
122+
ExpectBufEQ(test_ctx.c_buff, unexpectedAlert, sizeof(unexpectedAlert));
123+
wolfSSL_free(ssl_s);
124+
wolfSSL_CTX_free(ctx_s);
125+
ctx_s = NULL;
126+
ssl_s = NULL;
127+
128+
/* malformed ccs */
129+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
130+
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0,
131+
(const char*)badccs, sizeof(badccs)), 0);
132+
ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s,
133+
NULL, wolfTLSv1_3_server_method), 0);
134+
ExpectIntEQ(wolfSSL_accept(ssl_s), WOLFSSL_FATAL_ERROR);
135+
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
136+
UNKNOWN_RECORD_TYPE);
137+
ExpectIntEQ(test_ctx.c_len, sizeof(unexpectedAlert));
138+
ExpectBufEQ(test_ctx.c_buff, unexpectedAlert, sizeof(unexpectedAlert));
139+
wolfSSL_free(ssl_s);
140+
wolfSSL_CTX_free(ctx_s);
141+
#endif
142+
return EXPECT_RESULT();
143+
}

tests/api/test_tls.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* test_tls.h
2+
*
3+
* Copyright (C) 2006-2025 wolfSSL Inc.
4+
*
5+
* This file is part of wolfSSL.
6+
*
7+
* wolfSSL is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 2 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfSSL is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*/
21+
22+
#ifndef TESTS_API_TEST_TLS_H
23+
#define TESTS_API_TEST_TLS_H
24+
25+
int test_tls12_unexpected_ccs(void);
26+
int test_tls13_unexpected_ccs(void);
27+
28+
#endif /* TESTS_API_TEST_TLS_EMS_H */

0 commit comments

Comments
 (0)