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 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 58 static int watchccs_new(BIO *bio) 59 { 60 BIO_set_init(bio, 1); 61 return 1; 62 } 63 64 static int watchccs_free(BIO *bio) 65 { 66 BIO_set_init(bio, 0); 67 return 1; 68 } 69 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 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 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 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 240 static int watchccs_puts(BIO *bio, const char *str) 241 { 242 return watchccs_write(bio, str, strlen(str)); 243 } 244 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 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 507 void cleanup_tests(void) 508 { 509 BIO_meth_free(method_watchccs); 510 } 511