xref: /src/crypto/openssl/test/tls13ccstest.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*
2  * Copyright 2017-2024 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include <openssl/ssl.h>
11 #include <string.h>
12 #include "helpers/ssltestlib.h"
13 #include "testutil.h"
14 #include "internal/packet.h"
15 
16 static char *cert = NULL;
17 static char *privkey = NULL;
18 
19 static BIO *s_to_c_fbio = NULL, *c_to_s_fbio = NULL;
20 static int chseen = 0, shseen = 0, sccsseen = 0, ccsaftersh = 0;
21 static int ccsbeforesh = 0, sappdataseen = 0, cappdataseen = 0, badccs = 0;
22 static int badvers = 0, badsessid = 0;
23 
24 static unsigned char chsessid[SSL_MAX_SSL_SESSION_ID_LENGTH];
25 static size_t chsessidlen = 0;
26 
27 static int watchccs_new(BIO *bi);
28 static int watchccs_free(BIO *a);
29 static int watchccs_read(BIO *b, char *out, int outl);
30 static int watchccs_write(BIO *b, const char *in, int inl);
31 static long watchccs_ctrl(BIO *b, int cmd, long num, void *ptr);
32 static int watchccs_gets(BIO *bp, char *buf, int size);
33 static int watchccs_puts(BIO *bp, const char *str);
34 
35 /* Choose a sufficiently large type likely to be unused for this custom BIO */
36 #define BIO_TYPE_WATCHCCS_FILTER (0x80 | BIO_TYPE_FILTER)
37 
38 static BIO_METHOD *method_watchccs = NULL;
39 
bio_f_watchccs_filter(void)40 static const BIO_METHOD *bio_f_watchccs_filter(void)
41 {
42     if (method_watchccs == NULL) {
43         method_watchccs = BIO_meth_new(BIO_TYPE_WATCHCCS_FILTER,
44             "Watch CCS filter");
45         if (method_watchccs == NULL
46             || !BIO_meth_set_write(method_watchccs, watchccs_write)
47             || !BIO_meth_set_read(method_watchccs, watchccs_read)
48             || !BIO_meth_set_puts(method_watchccs, watchccs_puts)
49             || !BIO_meth_set_gets(method_watchccs, watchccs_gets)
50             || !BIO_meth_set_ctrl(method_watchccs, watchccs_ctrl)
51             || !BIO_meth_set_create(method_watchccs, watchccs_new)
52             || !BIO_meth_set_destroy(method_watchccs, watchccs_free))
53             return NULL;
54     }
55     return method_watchccs;
56 }
57 
watchccs_new(BIO * bio)58 static int watchccs_new(BIO *bio)
59 {
60     BIO_set_init(bio, 1);
61     return 1;
62 }
63 
watchccs_free(BIO * bio)64 static int watchccs_free(BIO *bio)
65 {
66     BIO_set_init(bio, 0);
67     return 1;
68 }
69 
watchccs_read(BIO * bio,char * out,int outl)70 static int watchccs_read(BIO *bio, char *out, int outl)
71 {
72     int ret = 0;
73     BIO *next = BIO_next(bio);
74 
75     if (outl <= 0)
76         return 0;
77     if (next == NULL)
78         return 0;
79 
80     BIO_clear_retry_flags(bio);
81 
82     ret = BIO_read(next, out, outl);
83     if (ret <= 0 && BIO_should_read(next))
84         BIO_set_retry_read(bio);
85 
86     return ret;
87 }
88 
watchccs_write(BIO * bio,const char * in,int inl)89 static int watchccs_write(BIO *bio, const char *in, int inl)
90 {
91     int ret = 0;
92     BIO *next = BIO_next(bio);
93     PACKET pkt, msg, msgbody, sessionid;
94     unsigned int rectype, recvers, msgtype, expectedrecvers;
95 
96     if (inl <= 0)
97         return 0;
98     if (next == NULL)
99         return 0;
100 
101     BIO_clear_retry_flags(bio);
102 
103     if (!PACKET_buf_init(&pkt, (const unsigned char *)in, inl))
104         return 0;
105 
106     /* We assume that we always write complete records each time */
107     while (PACKET_remaining(&pkt)) {
108         if (!PACKET_get_1(&pkt, &rectype)
109             || !PACKET_get_net_2(&pkt, &recvers)
110             || !PACKET_get_length_prefixed_2(&pkt, &msg))
111             return 0;
112 
113         expectedrecvers = TLS1_2_VERSION;
114 
115         if (rectype == SSL3_RT_HANDSHAKE) {
116             if (!PACKET_get_1(&msg, &msgtype)
117                 || !PACKET_get_length_prefixed_3(&msg, &msgbody))
118                 return 0;
119             if (msgtype == SSL3_MT_CLIENT_HELLO) {
120                 chseen++;
121 
122                 /*
123                  * Skip legacy_version (2 bytes) and Random (32 bytes) to read
124                  * session_id.
125                  */
126                 if (!PACKET_forward(&msgbody, 34)
127                     || !PACKET_get_length_prefixed_1(&msgbody, &sessionid))
128                     return 0;
129 
130                 if (chseen == 1) {
131                     expectedrecvers = TLS1_VERSION;
132 
133                     /* Save the session id for later */
134                     chsessidlen = PACKET_remaining(&sessionid);
135                     if (!PACKET_copy_bytes(&sessionid, chsessid, chsessidlen))
136                         return 0;
137                 } else {
138                     /*
139                      * Check the session id for the second ClientHello is the
140                      * same as the first one.
141                      */
142                     if (PACKET_remaining(&sessionid) != chsessidlen
143                         || (chsessidlen > 0
144                             && memcmp(chsessid, PACKET_data(&sessionid),
145                                    chsessidlen)
146                                 != 0))
147                         badsessid = 1;
148                 }
149             } else if (msgtype == SSL3_MT_SERVER_HELLO) {
150                 shseen++;
151                 /*
152                  * Skip legacy_version (2 bytes) and Random (32 bytes) to read
153                  * session_id.
154                  */
155                 if (!PACKET_forward(&msgbody, 34)
156                     || !PACKET_get_length_prefixed_1(&msgbody, &sessionid))
157                     return 0;
158 
159                 /*
160                  * Check the session id is the same as the one in the
161                  * ClientHello
162                  */
163                 if (PACKET_remaining(&sessionid) != chsessidlen
164                     || (chsessidlen > 0
165                         && memcmp(chsessid, PACKET_data(&sessionid),
166                                chsessidlen)
167                             != 0))
168                     badsessid = 1;
169             }
170         } else if (rectype == SSL3_RT_CHANGE_CIPHER_SPEC) {
171             if (bio == s_to_c_fbio) {
172                 /*
173                  * Server writing. We shouldn't have written any app data
174                  * yet, and we should have seen both the ClientHello and the
175                  * ServerHello
176                  */
177                 if (!sappdataseen
178                     && chseen == 1
179                     && shseen == 1
180                     && !sccsseen)
181                     sccsseen = 1;
182                 else
183                     badccs = 1;
184             } else if (!cappdataseen) {
185                 /*
186                  * Client writing. We shouldn't have written any app data
187                  * yet, and we should have seen the ClientHello
188                  */
189                 if (shseen == 1 && !ccsaftersh)
190                     ccsaftersh = 1;
191                 else if (shseen == 0 && !ccsbeforesh)
192                     ccsbeforesh = 1;
193                 else
194                     badccs = 1;
195             } else {
196                 badccs = 1;
197             }
198         } else if (rectype == SSL3_RT_APPLICATION_DATA) {
199             if (bio == s_to_c_fbio)
200                 sappdataseen = 1;
201             else
202                 cappdataseen = 1;
203         }
204         if (recvers != expectedrecvers)
205             badvers = 1;
206     }
207 
208     ret = BIO_write(next, in, inl);
209     if (ret <= 0 && BIO_should_write(next))
210         BIO_set_retry_write(bio);
211 
212     return ret;
213 }
214 
watchccs_ctrl(BIO * bio,int cmd,long num,void * ptr)215 static long watchccs_ctrl(BIO *bio, int cmd, long num, void *ptr)
216 {
217     long ret;
218     BIO *next = BIO_next(bio);
219 
220     if (next == NULL)
221         return 0;
222 
223     switch (cmd) {
224     case BIO_CTRL_DUP:
225         ret = 0;
226         break;
227     default:
228         ret = BIO_ctrl(next, cmd, num, ptr);
229         break;
230     }
231     return ret;
232 }
233 
watchccs_gets(BIO * bio,char * buf,int size)234 static int watchccs_gets(BIO *bio, char *buf, int size)
235 {
236     /* We don't support this - not needed anyway */
237     return -1;
238 }
239 
watchccs_puts(BIO * bio,const char * str)240 static int watchccs_puts(BIO *bio, const char *str)
241 {
242     return watchccs_write(bio, str, strlen(str));
243 }
244 
test_tls13ccs(int tst)245 static int test_tls13ccs(int tst)
246 {
247     SSL_CTX *sctx = NULL, *cctx = NULL;
248     SSL *sssl = NULL, *cssl = NULL;
249     int ret = 0;
250     const char msg[] = "Dummy data";
251     char buf[80];
252     size_t written, readbytes;
253     SSL_SESSION *sess = NULL;
254 
255     chseen = shseen = sccsseen = ccsaftersh = ccsbeforesh = 0;
256     sappdataseen = cappdataseen = badccs = badvers = badsessid = 0;
257     chsessidlen = 0;
258 
259     if (!TEST_true(create_ssl_ctx_pair(NULL, TLS_server_method(),
260             TLS_client_method(), TLS1_VERSION, 0,
261             &sctx, &cctx, cert, privkey))
262         || !TEST_true(SSL_CTX_set_max_early_data(sctx,
263             SSL3_RT_MAX_PLAIN_LENGTH)))
264         goto err;
265 
266     /*
267      * Test 0: Simple Handshake
268      * Test 1: Simple Handshake, client middlebox compat mode disabled
269      * Test 2: Simple Handshake, server middlebox compat mode disabled
270      * Test 3: HRR Handshake
271      * Test 4: HRR Handshake, client middlebox compat mode disabled
272      * Test 5: HRR Handshake, server middlebox compat mode disabled
273      * Test 6: Early data handshake
274      * Test 7: Early data handshake, client middlebox compat mode disabled
275      * Test 8: Early data handshake, server middlebox compat mode disabled
276      * Test 9: Early data then HRR
277      * Test 10: Early data then HRR, client middlebox compat mode disabled
278      * Test 11: Early data then HRR, server middlebox compat mode disabled
279      */
280     switch (tst) {
281     case 0:
282     case 3:
283     case 6:
284     case 9:
285         break;
286     case 1:
287     case 4:
288     case 7:
289     case 10:
290         SSL_CTX_clear_options(cctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
291         break;
292     case 2:
293     case 5:
294     case 8:
295     case 11:
296         SSL_CTX_clear_options(sctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT);
297         break;
298     default:
299         TEST_error("Invalid test value");
300         goto err;
301     }
302 
303     if (tst >= 6) {
304         /* Get a session suitable for early_data */
305         if (!TEST_true(create_ssl_objects(sctx, cctx, &sssl, &cssl, NULL, NULL))
306             || !TEST_true(create_ssl_connection(sssl, cssl, SSL_ERROR_NONE)))
307             goto err;
308         sess = SSL_get1_session(cssl);
309         if (!TEST_ptr(sess))
310             goto err;
311         SSL_shutdown(cssl);
312         SSL_shutdown(sssl);
313         SSL_free(sssl);
314         SSL_free(cssl);
315         sssl = cssl = NULL;
316     }
317 
318     if ((tst >= 3 && tst <= 5) || tst >= 9) {
319         /* HRR handshake */
320 #if defined(OPENSSL_NO_EC)
321 #if !defined(OPENSSL_NO_DH)
322         if (!TEST_true(SSL_CTX_set1_groups_list(sctx, "ffdhe3072")))
323             goto err;
324 #endif
325 #else
326         if (!TEST_true(SSL_CTX_set1_groups_list(sctx, "P-384")))
327             goto err;
328 #endif
329     }
330 
331     s_to_c_fbio = BIO_new(bio_f_watchccs_filter());
332     c_to_s_fbio = BIO_new(bio_f_watchccs_filter());
333     if (!TEST_ptr(s_to_c_fbio)
334         || !TEST_ptr(c_to_s_fbio)) {
335         BIO_free(s_to_c_fbio);
336         BIO_free(c_to_s_fbio);
337         goto err;
338     }
339 
340     /* BIOs get freed on error */
341     if (!TEST_true(create_ssl_objects(sctx, cctx, &sssl, &cssl, s_to_c_fbio,
342             c_to_s_fbio)))
343         goto err;
344 
345     if (tst >= 6) {
346         /* Early data */
347         if (!TEST_true(SSL_set_session(cssl, sess))
348             || !TEST_true(SSL_write_early_data(cssl, msg, strlen(msg),
349                 &written))
350             || (tst <= 8
351                 && !TEST_int_eq(SSL_read_early_data(sssl, buf, sizeof(buf),
352                                     &readbytes),
353                     SSL_READ_EARLY_DATA_SUCCESS)))
354             goto err;
355         if (tst <= 8) {
356             if (!TEST_int_gt(SSL_connect(cssl), 0))
357                 goto err;
358         } else {
359             if (!TEST_int_le(SSL_connect(cssl), 0))
360                 goto err;
361         }
362         if (!TEST_int_eq(SSL_read_early_data(sssl, buf, sizeof(buf),
363                              &readbytes),
364                 SSL_READ_EARLY_DATA_FINISH))
365             goto err;
366     }
367 
368     /* Perform handshake (or complete it if doing early data ) */
369     if (!TEST_true(create_ssl_connection(sssl, cssl, SSL_ERROR_NONE)))
370         goto err;
371 
372     /*
373      * Check there were no unexpected CCS messages, all record versions
374      * were as expected, and that the session ids were reflected by the server
375      * correctly.
376      */
377     if (!TEST_false(badccs) || !TEST_false(badvers) || !TEST_false(badsessid))
378         goto err;
379 
380     switch (tst) {
381     case 0:
382         if (!TEST_true(sccsseen)
383             || !TEST_true(ccsaftersh)
384             || !TEST_false(ccsbeforesh)
385             || !TEST_size_t_gt(chsessidlen, 0))
386             goto err;
387         break;
388 
389     case 1:
390         if (!TEST_true(sccsseen)
391             || !TEST_false(ccsaftersh)
392             || !TEST_false(ccsbeforesh)
393             || !TEST_size_t_eq(chsessidlen, 0))
394             goto err;
395         break;
396 
397     case 2:
398         if (!TEST_false(sccsseen)
399             || !TEST_true(ccsaftersh)
400             || !TEST_false(ccsbeforesh)
401             || !TEST_size_t_gt(chsessidlen, 0))
402             goto err;
403         break;
404 
405     case 3:
406         if (!TEST_true(sccsseen)
407             || !TEST_true(ccsaftersh)
408             || !TEST_false(ccsbeforesh)
409             || !TEST_size_t_gt(chsessidlen, 0))
410             goto err;
411         break;
412 
413     case 4:
414         if (!TEST_true(sccsseen)
415             || !TEST_false(ccsaftersh)
416             || !TEST_false(ccsbeforesh)
417             || !TEST_size_t_eq(chsessidlen, 0))
418             goto err;
419         break;
420 
421     case 5:
422         if (!TEST_false(sccsseen)
423             || !TEST_true(ccsaftersh)
424             || !TEST_false(ccsbeforesh)
425             || !TEST_size_t_gt(chsessidlen, 0))
426             goto err;
427         break;
428 
429     case 6:
430         if (!TEST_true(sccsseen)
431             || !TEST_false(ccsaftersh)
432             || !TEST_true(ccsbeforesh)
433             || !TEST_size_t_gt(chsessidlen, 0))
434             goto err;
435         break;
436 
437     case 7:
438         if (!TEST_true(sccsseen)
439             || !TEST_false(ccsaftersh)
440             || !TEST_false(ccsbeforesh)
441             || !TEST_size_t_eq(chsessidlen, 0))
442             goto err;
443         break;
444 
445     case 8:
446         if (!TEST_false(sccsseen)
447             || !TEST_false(ccsaftersh)
448             || !TEST_true(ccsbeforesh)
449             || !TEST_size_t_gt(chsessidlen, 0))
450             goto err;
451         break;
452 
453     case 9:
454         if (!TEST_true(sccsseen)
455             || !TEST_false(ccsaftersh)
456             || !TEST_true(ccsbeforesh)
457             || !TEST_size_t_gt(chsessidlen, 0))
458             goto err;
459         break;
460 
461     case 10:
462         if (!TEST_true(sccsseen)
463             || !TEST_false(ccsaftersh)
464             || !TEST_false(ccsbeforesh)
465             || !TEST_size_t_eq(chsessidlen, 0))
466             goto err;
467         break;
468 
469     case 11:
470         if (!TEST_false(sccsseen)
471             || !TEST_false(ccsaftersh)
472             || !TEST_true(ccsbeforesh)
473             || !TEST_size_t_gt(chsessidlen, 0))
474             goto err;
475         break;
476     }
477 
478     ret = 1;
479 err:
480     SSL_SESSION_free(sess);
481     SSL_free(sssl);
482     SSL_free(cssl);
483     SSL_CTX_free(sctx);
484     SSL_CTX_free(cctx);
485 
486     return ret;
487 }
488 
489 OPT_TEST_DECLARE_USAGE("certfile privkeyfile\n")
490 
setup_tests(void)491 int setup_tests(void)
492 {
493     if (!test_skip_common_options()) {
494         TEST_error("Error parsing test options\n");
495         return 0;
496     }
497 
498     if (!TEST_ptr(cert = test_get_argument(0))
499         || !TEST_ptr(privkey = test_get_argument(1)))
500         return 0;
501 
502     ADD_ALL_TESTS(test_tls13ccs, 12);
503 
504     return 1;
505 }
506 
cleanup_tests(void)507 void cleanup_tests(void)
508 {
509     BIO_meth_free(method_watchccs);
510 }
511