static int test_client_hello(int currtest) { SSL_CTX *ctx; SSL *con = NULL; BIO *rbio; BIO *wbio; long len; unsigned char *data; PACKET pkt = {0}, pkt2 = {0}, pkt3 = {0}; char *dummytick = "Hello World!"; unsigned int type = 0; int testresult = 0; size_t msglen; BIO *sessbio = NULL; SSL_SESSION *sess = NULL; #ifdef OPENSSL_NO_TLS1_3 if (currtest == TEST_ADD_PADDING_AND_PSK) return 1; #endif /* * For each test set up an SSL_CTX and SSL and see what ClientHello gets * produced when we try to connect */ ctx = SSL_CTX_new(TLS_method()); if (!TEST_ptr(ctx)) goto end; switch(currtest) { case TEST_SET_SESSION_TICK_DATA_VER_NEG: /* Testing for session tickets <= TLS1.2; not relevant for 1.3 */ if (!TEST_true(SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION))) goto end; break; case TEST_ADD_PADDING_AND_PSK: case TEST_ADD_PADDING: case TEST_PADDING_NOT_NEEDED: SSL_CTX_set_options(ctx, SSL_OP_TLSEXT_PADDING); /* * Add lots of ciphersuites so that the ClientHello is at least * F5_WORKAROUND_MIN_MSG_LEN bytes long - meaning padding will be * needed. Also add some dummy ALPN protocols in case we still don't * have enough. */ if (currtest == TEST_ADD_PADDING && (!TEST_true(SSL_CTX_set_cipher_list(ctx, "ALL")) || !TEST_false(SSL_CTX_set_alpn_protos(ctx, (unsigned char *)alpn_prots, sizeof(alpn_prots) - 1)))) goto end; break; default: goto end; } con = SSL_new(ctx); if (!TEST_ptr(con)) goto end; if (currtest == TEST_ADD_PADDING_AND_PSK) { sessbio = BIO_new_file(sessionfile, "r"); if (!TEST_ptr(sessbio)) { TEST_info("Unable to open session.pem"); goto end; } sess = PEM_read_bio_SSL_SESSION(sessbio, NULL, NULL, NULL); if (!TEST_ptr(sess)) { TEST_info("Unable to load SSL_SESSION"); goto end; } /* * We reset the creation time so that we don't discard the session as * too old. */ if (!TEST_true(SSL_SESSION_set_time(sess, time(NULL))) || !TEST_true(SSL_set_session(con, sess))) goto end; } rbio = BIO_new(BIO_s_mem()); wbio = BIO_new(BIO_s_mem()); if (!TEST_ptr(rbio)|| !TEST_ptr(wbio)) { BIO_free(rbio); BIO_free(wbio); goto end; } SSL_set_bio(con, rbio, wbio); SSL_set_connect_state(con); if (currtest == TEST_SET_SESSION_TICK_DATA_VER_NEG) { if (!TEST_true(SSL_set_session_ticket_ext(con, dummytick, strlen(dummytick)))) goto end; } if (!TEST_int_le(SSL_connect(con), 0)) { /* This shouldn't succeed because we don't have a server! */ goto end; } len = BIO_get_mem_data(wbio, (char **)&data); if (!TEST_true(PACKET_buf_init(&pkt, data, len)) /* Skip the record header */ || !PACKET_forward(&pkt, SSL3_RT_HEADER_LENGTH)) goto end; msglen = PACKET_remaining(&pkt); /* Skip the handshake message header */ if (!TEST_true(PACKET_forward(&pkt, SSL3_HM_HEADER_LENGTH)) /* Skip client version and random */ || !TEST_true(PACKET_forward(&pkt, CLIENT_VERSION_LEN + SSL3_RANDOM_SIZE)) /* Skip session id */ || !TEST_true(PACKET_get_length_prefixed_1(&pkt, &pkt2)) /* Skip ciphers */ || !TEST_true(PACKET_get_length_prefixed_2(&pkt, &pkt2)) /* Skip compression */ || !TEST_true(PACKET_get_length_prefixed_1(&pkt, &pkt2)) /* Extensions len */ || !TEST_true(PACKET_as_length_prefixed_2(&pkt, &pkt2))) goto end; /* Loop through all extensions */ while (PACKET_remaining(&pkt2)) { if (!TEST_true(PACKET_get_net_2(&pkt2, &type)) || !TEST_true(PACKET_get_length_prefixed_2(&pkt2, &pkt3))) goto end; if (type == TLSEXT_TYPE_session_ticket) { if (currtest == TEST_SET_SESSION_TICK_DATA_VER_NEG) { if (TEST_true(PACKET_equal(&pkt3, dummytick, strlen(dummytick)))) { /* Ticket data is as we expected */ testresult = 1; } goto end; } } if (type == TLSEXT_TYPE_padding) { if (!TEST_false(currtest == TEST_PADDING_NOT_NEEDED)) goto end; else if (TEST_true(currtest == TEST_ADD_PADDING || currtest == TEST_ADD_PADDING_AND_PSK)) testresult = TEST_true(msglen == F5_WORKAROUND_MAX_MSG_LEN); } } if (currtest == TEST_PADDING_NOT_NEEDED) testresult = 1; end: SSL_free(con); SSL_CTX_free(ctx); SSL_SESSION_free(sess); BIO_free(sessbio); return testresult; }
int main(int argc, char *argv[]) { SSL_CTX *ctx; SSL *con; BIO *rbio; BIO *wbio; BIO *err; long len; unsigned char *data; unsigned char *dataend; char *dummytick = "Hello World!"; unsigned int tmplen; unsigned int type; unsigned int size; int testresult = 0; int currtest = 0; SSL_library_init(); SSL_load_error_strings(); err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT); CRYPTO_malloc_debug_init(); CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL); CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); /* * For each test set up an SSL_CTX and SSL and see what ClientHello gets * produced when we try to connect */ for (; currtest < TOTAL_NUM_TESTS; currtest++) { testresult = 0; if (currtest == TEST_SET_SESSION_TICK_DATA_TLS_1_2) { ctx = SSL_CTX_new(TLSv1_2_method()); } else { ctx = SSL_CTX_new(SSLv23_method()); } con = SSL_new(ctx); rbio = BIO_new(BIO_s_mem()); wbio = BIO_new(BIO_s_mem()); SSL_set_bio(con, rbio, wbio); SSL_set_connect_state(con); if (currtest == TEST_SET_SESSION_TICK_DATA_TLS_1_2 || currtest == TEST_SET_SESSION_TICK_DATA_VER_NEG) { if (!SSL_set_session_ticket_ext(con, dummytick, strlen(dummytick))) goto end; } if (SSL_connect(con) > 0) { /* This shouldn't succeed because we don't have a server! */ goto end; } len = BIO_get_mem_data(wbio, (char **)&data); dataend = data + len; /* Skip the record header */ data += SSL3_RT_HEADER_LENGTH; /* Skip the handshake message header */ data += SSL3_HM_HEADER_LENGTH; /* Skip client version and random */ data += CLIENT_VERSION_LEN + SSL3_RANDOM_SIZE; if (data + SESSION_ID_LEN_LEN > dataend) goto end; /* Skip session id */ tmplen = *data; data += SESSION_ID_LEN_LEN + tmplen; if (data + CIPHERS_LEN_LEN > dataend) goto end; /* Skip ciphers */ tmplen = ((*data) << 8) | *(data + 1); data += CIPHERS_LEN_LEN + tmplen; if (data + COMPRESSION_LEN_LEN > dataend) goto end; /* Skip compression */ tmplen = *data; data += COMPRESSION_LEN_LEN + tmplen; if (data + EXTENSIONS_LEN_LEN > dataend) goto end; /* Extensions len */ tmplen = ((*data) << 8) | *(data + 1); data += EXTENSIONS_LEN_LEN; if (data + tmplen > dataend) goto end; /* Loop through all extensions */ while (tmplen > EXTENSION_TYPE_LEN + EXTENSION_SIZE_LEN) { type = ((*data) << 8) | *(data + 1); data += EXTENSION_TYPE_LEN; size = ((*data) << 8) | *(data + 1); data += EXTENSION_SIZE_LEN; if (data + size > dataend) goto end; if (type == TLSEXT_TYPE_session_ticket) { if (currtest == TEST_SET_SESSION_TICK_DATA_TLS_1_2 || currtest == TEST_SET_SESSION_TICK_DATA_VER_NEG) { if (size == strlen(dummytick) && memcmp(data, dummytick, size) == 0) { /* Ticket data is as we expected */ testresult = 1; } else { printf("Received session ticket is not as expected\n"); } break; } } tmplen -= EXTENSION_TYPE_LEN + EXTENSION_SIZE_LEN + size; data += size; } end: SSL_free(con); SSL_CTX_free(ctx); if (!testresult) { printf("ClientHello test: FAILED (Test %d)\n", currtest); break; } } ERR_free_strings(); ERR_remove_thread_state(NULL); EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); CRYPTO_mem_leaks(err); return testresult?0:1; }