X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=test%2Fsslapitest.c;h=1cf5c4fc6cecddaa50f08d33295ea38c8000f917;hp=1ff0f5e31b1399b86c70aa33f7c3442a90d1aec4;hb=b38ede8043439d99a3c6c174f17b91875cce66ac;hpb=976e53232d4ee8174e2e0f5a15ad04a9d7bea351 diff --git a/test/sslapitest.c b/test/sslapitest.c index 1ff0f5e31b..1cf5c4fc6c 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -40,6 +40,7 @@ static X509 *ocspcert = NULL; #endif #define NUM_EXTRA_CERTS 40 +#define CLIENT_VERSION_LEN 2 /* * This structure is used to validate that the correct number of log messages @@ -253,6 +254,7 @@ static int test_keylog_output(char *buffer, const SSL *ssl, return 1; } +#if !defined(OPENSSL_NO_TLS1_2) || defined(OPENSSL_NO_TLS1_3) static int test_keylog(void) { SSL_CTX *cctx = NULL, *sctx = NULL; @@ -329,6 +331,7 @@ end: return testresult; } +#endif #ifndef OPENSSL_NO_TLS1_3 static int test_keylog_no_master_key(void) @@ -401,7 +404,7 @@ end: #endif #ifndef OPENSSL_NO_TLS1_2 -static int full_early_callback(SSL *s, int *al, void *arg) +static int full_client_hello_callback(SSL *s, int *al, void *arg) { int *ctr = arg; const unsigned char *p; @@ -422,26 +425,27 @@ static int full_early_callback(SSL *s, int *al, void *arg) /* Make sure we can defer processing and get called back. */ if ((*ctr)++ == 0) - return -1; + return SSL_CLIENT_HELLO_RETRY; - len = SSL_early_get0_ciphers(s, &p); + len = SSL_client_hello_get0_ciphers(s, &p); if (!TEST_mem_eq(p, len, expected_ciphers, sizeof(expected_ciphers)) - || !TEST_size_t_eq(SSL_early_get0_compression_methods(s, &p), 1) + || !TEST_size_t_eq( + SSL_client_hello_get0_compression_methods(s, &p), 1) || !TEST_int_eq(*p, 0)) - return 0; - if (!SSL_early_get1_extensions_present(s, &exts, &len)) - return 0; + return SSL_CLIENT_HELLO_ERROR; + if (!SSL_client_hello_get1_extensions_present(s, &exts, &len)) + return SSL_CLIENT_HELLO_ERROR; if (len != OSSL_NELEM(expected_extensions) || memcmp(exts, expected_extensions, len * sizeof(*exts)) != 0) { - printf("Early callback expected ClientHello extensions mismatch\n"); + printf("ClientHello callback expected extensions mismatch\n"); OPENSSL_free(exts); - return 0; + return SSL_CLIENT_HELLO_ERROR; } OPENSSL_free(exts); - return 1; + return SSL_CLIENT_HELLO_SUCCESS; } -static int test_early_cb(void) +static int test_client_hello_cb(void) { SSL_CTX *cctx = NULL, *sctx = NULL; SSL *clientssl = NULL, *serverssl = NULL; @@ -451,7 +455,7 @@ static int test_early_cb(void) TLS_client_method(), &sctx, &cctx, cert, privkey))) goto end; - SSL_CTX_set_early_cb(sctx, full_early_callback, &testctr); + SSL_CTX_set_client_hello_cb(sctx, full_client_hello_callback, &testctr); /* The gimpy cipher list we configure can't do TLS 1.3. */ SSL_CTX_set_max_proto_version(cctx, TLS1_2_VERSION); @@ -461,12 +465,13 @@ static int test_early_cb(void) || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) || !TEST_false(create_ssl_connection(serverssl, clientssl, - SSL_ERROR_WANT_EARLY)) + SSL_ERROR_WANT_CLIENT_HELLO_CB)) /* * Passing a -1 literal is a hack since * the real value was lost. * */ - || !TEST_int_eq(SSL_get_error(serverssl, -1), SSL_ERROR_WANT_EARLY) + || !TEST_int_eq(SSL_get_error(serverssl, -1), + SSL_ERROR_WANT_CLIENT_HELLO_CB) || !TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) goto end; @@ -1270,6 +1275,7 @@ static int test_ssl_bio_change_wbio(void) return execute_test_ssl_bio(0, CHANGE_WBIO); } +#if !defined(OPENSSL_NO_TLS1_2) || defined(OPENSSL_NO_TLS1_3) typedef struct { /* The list of sig algs */ const int *list; @@ -1284,25 +1290,25 @@ typedef struct { } sigalgs_list; static const int validlist1[] = {NID_sha256, EVP_PKEY_RSA}; -#ifndef OPENSSL_NO_EC +# ifndef OPENSSL_NO_EC static const int validlist2[] = {NID_sha256, EVP_PKEY_RSA, NID_sha512, EVP_PKEY_EC}; static const int validlist3[] = {NID_sha512, EVP_PKEY_EC}; -#endif +# endif static const int invalidlist1[] = {NID_undef, EVP_PKEY_RSA}; static const int invalidlist2[] = {NID_sha256, NID_undef}; static const int invalidlist3[] = {NID_sha256, EVP_PKEY_RSA, NID_sha256}; static const int invalidlist4[] = {NID_sha256}; static const sigalgs_list testsigalgs[] = { {validlist1, OSSL_NELEM(validlist1), NULL, 1, 1}, -#ifndef OPENSSL_NO_EC +# ifndef OPENSSL_NO_EC {validlist2, OSSL_NELEM(validlist2), NULL, 1, 1}, {validlist3, OSSL_NELEM(validlist3), NULL, 1, 0}, -#endif +# endif {NULL, 0, "RSA+SHA256", 1, 1}, -#ifndef OPENSSL_NO_EC +# ifndef OPENSSL_NO_EC {NULL, 0, "RSA+SHA256:ECDSA+SHA512", 1, 1}, {NULL, 0, "ECDSA+SHA512", 1, 0}, -#endif +# endif {invalidlist1, OSSL_NELEM(invalidlist1), NULL, 0, 0}, {invalidlist2, OSSL_NELEM(invalidlist2), NULL, 0, 0}, {invalidlist3, OSSL_NELEM(invalidlist3), NULL, 0, 0}, @@ -1398,8 +1404,12 @@ static int test_set_sigalgs(int idx) return testresult; } +#endif -static SSL_SESSION *psk = NULL; +#ifndef OPENSSL_NO_TLS1_3 + +static SSL_SESSION *clientpsk = NULL; +static SSL_SESSION *serverpsk = NULL; static const char *pskid = "Identity"; static const char *srvid; @@ -1427,10 +1437,10 @@ static int use_session_cb(SSL *ssl, const EVP_MD *md, const unsigned char **id, return 0; } - if (psk != NULL) - SSL_SESSION_up_ref(psk); + if (clientpsk != NULL) + SSL_SESSION_up_ref(clientpsk); - *sess = psk; + *sess = clientpsk; *id = (const unsigned char *)pskid; *idlen = strlen(pskid); @@ -1446,7 +1456,7 @@ static int find_session_cb(SSL *ssl, const unsigned char *identity, if (find_session_cb_cnt > 2) return 0; - if (psk == NULL) + if (serverpsk == NULL) return 0; /* Identity should match that set by the client */ @@ -1457,14 +1467,12 @@ static int find_session_cb(SSL *ssl, const unsigned char *identity, return 1; } - SSL_SESSION_up_ref(psk); - *sess = psk; + SSL_SESSION_up_ref(serverpsk); + *sess = serverpsk; return 1; } -#ifndef OPENSSL_NO_TLS1_3 - #define MSG1 "Hello" #define MSG2 "World." #define MSG3 "This" @@ -1504,6 +1512,16 @@ static int setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx, SSL **clientssl, NULL, NULL))) return 0; + /* + * For one of the run throughs (doesn't matter which one), we'll try sending + * some SNI data in the initial ClientHello. This will be ignored (because + * there is no SNI cb set up by the server), so it should not impact + * early_data. + */ + if (idx == 1 + && !TEST_true(SSL_set_tlsext_host_name(*clientssl, "localhost"))) + return 0; + if (idx == 2) { /* Create the PSK */ const SSL_CIPHER *cipher = NULL; @@ -1516,27 +1534,30 @@ static int setupearly_data_test(SSL_CTX **cctx, SSL_CTX **sctx, SSL **clientssl, }; cipher = SSL_CIPHER_find(*clientssl, TLS13_AES_256_GCM_SHA384_BYTES); - psk = SSL_SESSION_new(); - if (!TEST_ptr(psk) + clientpsk = SSL_SESSION_new(); + if (!TEST_ptr(clientpsk) || !TEST_ptr(cipher) - || !TEST_true(SSL_SESSION_set1_master_key(psk, key, + || !TEST_true(SSL_SESSION_set1_master_key(clientpsk, key, sizeof(key))) - || !TEST_true(SSL_SESSION_set_cipher(psk, cipher)) + || !TEST_true(SSL_SESSION_set_cipher(clientpsk, cipher)) || !TEST_true( - SSL_SESSION_set_protocol_version(psk, + SSL_SESSION_set_protocol_version(clientpsk, TLS1_3_VERSION)) /* * We just choose an arbitrary value for max_early_data which * should be big enough for testing purposes. */ - || !TEST_true(SSL_SESSION_set_max_early_data(psk, 0x100))) { - SSL_SESSION_free(psk); - psk = NULL; + || !TEST_true(SSL_SESSION_set_max_early_data(clientpsk, + 0x100)) + || !TEST_true(SSL_SESSION_up_ref(clientpsk))) { + SSL_SESSION_free(clientpsk); + clientpsk = NULL; return 0; } + serverpsk = clientpsk; if (sess != NULL) - *sess = psk; + *sess = clientpsk; return 1; } @@ -1757,8 +1778,11 @@ static int test_early_data_read_write(int idx) testresult = 1; end: - SSL_SESSION_free(sess); - psk = NULL; + if (sess != clientpsk) + SSL_SESSION_free(sess); + SSL_SESSION_free(clientpsk); + SSL_SESSION_free(serverpsk); + clientpsk = serverpsk = NULL; SSL_free(serverssl); SSL_free(clientssl); SSL_CTX_free(sctx); @@ -1799,7 +1823,7 @@ static int early_data_skip_helper(int hrr, int idx) * time. It could be any value as long as it is not within tolerance. * This should mean the ticket is rejected. */ - if (!TEST_true(SSL_SESSION_set_time(sess, time(NULL) - 20))) + if (!TEST_true(SSL_SESSION_set_time(sess, (long)(time(NULL) - 20)))) goto end; } @@ -1842,9 +1866,10 @@ static int early_data_skip_helper(int hrr, int idx) testresult = 1; end: - if (sess != psk) - SSL_SESSION_free(psk); - psk = NULL; + if (sess != clientpsk) + SSL_SESSION_free(clientpsk); + SSL_SESSION_free(serverpsk); + clientpsk = serverpsk = NULL; SSL_SESSION_free(sess); SSL_free(serverssl); SSL_free(clientssl); @@ -1929,8 +1954,10 @@ static int test_early_data_not_sent(int idx) testresult = 1; end: + /* If using PSK then clientpsk and sess are the same */ SSL_SESSION_free(sess); - psk = NULL; + SSL_SESSION_free(serverpsk); + clientpsk = serverpsk = NULL; SSL_free(serverssl); SSL_free(clientssl); SSL_CTX_free(sctx); @@ -1938,13 +1965,11 @@ static int test_early_data_not_sent(int idx) return testresult; } -static const char *servhostname; - static int hostname_cb(SSL *s, int *al, void *arg) { const char *hostname = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); - if (hostname != NULL && strcmp(hostname, servhostname) == 0) + if (hostname != NULL && strcmp(hostname, "goodhost") == 0) return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_NOACK; @@ -1952,19 +1977,20 @@ static int hostname_cb(SSL *s, int *al, void *arg) static const char *servalpn; -static int alpn_select_cb (SSL *ssl, const unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen, void *arg) +static int alpn_select_cb(SSL *ssl, const unsigned char **out, + unsigned char *outlen, const unsigned char *in, + unsigned int inlen, void *arg) { - unsigned int i, protlen = 0; + unsigned int protlen = 0; const unsigned char *prot; - for (i = 0, prot = in; i < inlen; i += protlen, prot += protlen) { - protlen = *(prot++); - if (inlen - i < protlen) + for (prot = in; prot < in + inlen; prot += protlen) { + protlen = *prot++; + if (in + inlen < prot + protlen) return SSL_TLSEXT_ERR_NOACK; if (protlen == strlen(servalpn) - && memcmp(prot, "goodalpn", protlen) == 0) { + && memcmp(prot, servalpn, protlen) == 0) { *out = prot; *outlen = protlen; return SSL_TLSEXT_ERR_OK; @@ -1974,18 +2000,25 @@ static int alpn_select_cb (SSL *ssl, const unsigned char **out, unsigned char *o return SSL_TLSEXT_ERR_NOACK; } +/* Test that a PSK can be used to send early_data */ static int test_early_data_psk(int idx) { SSL_CTX *cctx = NULL, *sctx = NULL; SSL *clientssl = NULL, *serverssl = NULL; int testresult = 0; SSL_SESSION *sess = NULL; - unsigned char badalpn[] = { 0x07, 'b', 'a', 'd', 'a', 'l', 'p', 'n' }; - unsigned char goodalpn[] = { 0x08, 'g', 'o', 'o', 'd', 'a', 'l', 'p', 'n' }; - int err; + unsigned char alpnlist[] = { + 0x08, 'g', 'o', 'o', 'd', 'a', 'l', 'p', 'n', 0x07, 'b', 'a', 'd', 'a', + 'l', 'p', 'n' + }; +#define GOODALPNLEN 9 +#define BADALPNLEN 8 +#define GOODALPN (alpnlist) +#define BADALPN (alpnlist + GOODALPNLEN) + int err = 0; unsigned char buf[20]; size_t readbytes, written; - int readearlyres = SSL_READ_EARLY_DATA_SUCCESS; + int readearlyres = SSL_READ_EARLY_DATA_SUCCESS, connectres = 1; int edstatus = SSL_EARLY_DATA_ACCEPTED; /* We always set this up with a final parameter of "2" for PSK */ @@ -1993,12 +2026,17 @@ static int test_early_data_psk(int idx) &serverssl, &sess, 2))) goto end; - servhostname = "goodhost"; servalpn = "goodalpn"; + /* + * Note: There is no test for inconsistent SNI with late client detection. + * This is because servers do not acknowledge SNI even if they are using + * it in a resumption handshake - so it is not actually possible for a + * client to detect a problem. + */ switch (idx) { case 0: - /* Set inconsistent SNI (client detected) */ + /* Set inconsistent SNI (early client detection) */ err = SSL_R_INCONSISTENT_EARLY_DATA_SNI; if (!TEST_true(SSL_SESSION_set1_hostname(sess, "goodhost")) || !TEST_true(SSL_set_tlsext_host_name(clientssl, "badhost"))) @@ -2006,13 +2044,13 @@ static int test_early_data_psk(int idx) break; case 1: - /* Set inconsistent ALPN (client detected) */ + /* Set inconsistent ALPN (early client detection) */ err = SSL_R_INCONSISTENT_EARLY_DATA_ALPN; /* SSL_set_alpn_protos returns 0 for success and 1 for failure */ - if (!TEST_true(SSL_SESSION_set1_alpn_selected(sess, goodalpn, - sizeof(goodalpn))) - || !TEST_false(SSL_set_alpn_protos(clientssl, badalpn, - sizeof(badalpn)))) + if (!TEST_true(SSL_SESSION_set1_alpn_selected(sess, GOODALPN, + GOODALPNLEN)) + || !TEST_false(SSL_set_alpn_protos(clientssl, BADALPN, + BADALPNLEN))) goto end; break; @@ -2032,13 +2070,16 @@ static int test_early_data_psk(int idx) * Set inconsistent SNI (server detected). In this case the connection * will succeed but reject early_data. */ - servhostname = "badhost"; + SSL_SESSION_free(serverpsk); + serverpsk = SSL_SESSION_dup(clientpsk); + if (!TEST_ptr(serverpsk) + || !TEST_true(SSL_SESSION_set1_hostname(serverpsk, "badhost"))) + goto end; edstatus = SSL_EARLY_DATA_REJECTED; readearlyres = SSL_READ_EARLY_DATA_FINISH; /* Fall through */ case 4: /* Set consistent SNI */ - err = 0; if (!TEST_true(SSL_SESSION_set1_hostname(sess, "goodhost")) || !TEST_true(SSL_set_tlsext_host_name(clientssl, "goodhost")) || !TEST_true(SSL_CTX_set_tlsext_servername_callback(sctx, @@ -2056,23 +2097,43 @@ static int test_early_data_psk(int idx) readearlyres = SSL_READ_EARLY_DATA_FINISH; /* Fall through */ case 6: - /* Set consistent ALPN */ - err = 0; /* + * Set consistent ALPN. * SSL_set_alpn_protos returns 0 for success and 1 for failure. It * accepts a list of protos (each one length prefixed). * SSL_set1_alpn_selected accepts a single protocol (not length * prefixed) */ - if (!TEST_true(SSL_SESSION_set1_alpn_selected(sess, goodalpn + 1, - sizeof(goodalpn) - 1)) - || !TEST_false(SSL_set_alpn_protos(clientssl, goodalpn, - sizeof(goodalpn)))) + if (!TEST_true(SSL_SESSION_set1_alpn_selected(sess, GOODALPN + 1, + GOODALPNLEN - 1)) + || !TEST_false(SSL_set_alpn_protos(clientssl, GOODALPN, + GOODALPNLEN))) goto end; SSL_CTX_set_alpn_select_cb(sctx, alpn_select_cb, NULL); break; + case 7: + /* Set inconsistent ALPN (late client detection) */ + SSL_SESSION_free(serverpsk); + serverpsk = SSL_SESSION_dup(clientpsk); + if (!TEST_ptr(serverpsk) + || !TEST_true(SSL_SESSION_set1_alpn_selected(clientpsk, + BADALPN + 1, + BADALPNLEN - 1)) + || !TEST_true(SSL_SESSION_set1_alpn_selected(serverpsk, + GOODALPN + 1, + GOODALPNLEN - 1)) + || !TEST_false(SSL_set_alpn_protos(clientssl, alpnlist, + sizeof(alpnlist)))) + goto end; + SSL_CTX_set_alpn_select_cb(sctx, alpn_select_cb, NULL); + edstatus = SSL_EARLY_DATA_ACCEPTED; + readearlyres = SSL_READ_EARLY_DATA_SUCCESS; + /* SSL_connect() call should fail */ + connectres = -1; + break; + default: TEST_error("Bad test index"); goto end; @@ -2087,20 +2148,24 @@ static int test_early_data_psk(int idx) goto end; } else { if (!TEST_true(SSL_write_early_data(clientssl, MSG1, strlen(MSG1), - &written)) - || !TEST_int_eq(SSL_read_early_data(serverssl, buf, sizeof(buf), - &readbytes), readearlyres) + &written))) + goto end; + + if (!TEST_int_eq(SSL_read_early_data(serverssl, buf, sizeof(buf), + &readbytes), readearlyres) || (readearlyres == SSL_READ_EARLY_DATA_SUCCESS && !TEST_mem_eq(buf, readbytes, MSG1, strlen(MSG1))) - || !TEST_int_eq(SSL_get_early_data_status(serverssl), edstatus)) + || !TEST_int_eq(SSL_get_early_data_status(serverssl), edstatus) + || !TEST_int_eq(SSL_connect(clientssl), connectres)) goto end; } testresult = 1; end: - SSL_SESSION_free(sess); - psk = NULL; + SSL_SESSION_free(clientpsk); + SSL_SESSION_free(serverpsk); + clientpsk = serverpsk = NULL; SSL_free(serverssl); SSL_free(clientssl); SSL_CTX_free(sctx); @@ -2155,8 +2220,10 @@ static int test_early_data_not_expected(int idx) testresult = 1; end: + /* If using PSK then clientpsk and sess are the same */ SSL_SESSION_free(sess); - psk = NULL; + SSL_SESSION_free(serverpsk); + clientpsk = serverpsk = NULL; SSL_free(serverssl); SSL_free(clientssl); SSL_CTX_free(sctx); @@ -2227,8 +2294,10 @@ static int test_early_data_tls1_2(int idx) testresult = 1; end: - SSL_SESSION_free(psk); - psk = NULL; + /* If using PSK then clientpsk and sess are the same */ + SSL_SESSION_free(clientpsk); + SSL_SESSION_free(serverpsk); + clientpsk = serverpsk = NULL; SSL_free(serverssl); SSL_free(clientssl); SSL_CTX_free(sctx); @@ -2267,6 +2336,7 @@ static int test_ciphersuite_change(void) SSL_free(clientssl); serverssl = clientssl = NULL; +# if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305) /* Check we can resume a session with a different SHA-256 ciphersuite */ if (!TEST_true(SSL_CTX_set_cipher_list(cctx, "TLS13-CHACHA20-POLY1305-SHA256")) @@ -2285,6 +2355,7 @@ static int test_ciphersuite_change(void) SSL_free(serverssl); SSL_free(clientssl); serverssl = clientssl = NULL; +# endif /* * Check attempting to resume a SHA-256 session with no SHA-256 ciphersuites @@ -2410,14 +2481,17 @@ static int test_tls13_psk(void) /* Create the PSK */ cipher = SSL_CIPHER_find(clientssl, TLS13_AES_256_GCM_SHA384_BYTES); - psk = SSL_SESSION_new(); - if (!TEST_ptr(psk) + clientpsk = SSL_SESSION_new(); + if (!TEST_ptr(clientpsk) || !TEST_ptr(cipher) - || !TEST_true(SSL_SESSION_set1_master_key(psk, key, sizeof(key))) - || !TEST_true(SSL_SESSION_set_cipher(psk, cipher)) - || !TEST_true(SSL_SESSION_set_protocol_version(psk, - TLS1_3_VERSION))) + || !TEST_true(SSL_SESSION_set1_master_key(clientpsk, key, + sizeof(key))) + || !TEST_true(SSL_SESSION_set_cipher(clientpsk, cipher)) + || !TEST_true(SSL_SESSION_set_protocol_version(clientpsk, + TLS1_3_VERSION)) + || !TEST_true(SSL_SESSION_up_ref(clientpsk))) goto end; + serverpsk = clientpsk; /* Check we can create a connection and the PSK is used */ if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)) @@ -2474,7 +2548,9 @@ static int test_tls13_psk(void) testresult = 1; end: - SSL_SESSION_free(psk); + SSL_SESSION_free(clientpsk); + SSL_SESSION_free(serverpsk); + clientpsk = serverpsk = NULL; SSL_free(serverssl); SSL_free(clientssl); SSL_CTX_free(sctx); @@ -2482,6 +2558,95 @@ static int test_tls13_psk(void) return testresult; } +static unsigned char cookie_magic_value[] = "cookie magic"; + +static int generate_cookie_callback(SSL *ssl, unsigned char *cookie, + unsigned int *cookie_len) +{ + /* + * Not suitable as a real cookie generation function but good enough for + * testing! + */ + memcpy(cookie, cookie_magic_value, sizeof(cookie_magic_value) - 1); + *cookie_len = sizeof(cookie_magic_value) - 1; + + return 1; +} + +static int verify_cookie_callback(SSL *ssl, const unsigned char *cookie, + unsigned int cookie_len) +{ + if (cookie_len == sizeof(cookie_magic_value) - 1 + && memcmp(cookie, cookie_magic_value, cookie_len) == 0) + return 1; + + return 0; +} + +static int test_stateless(void) +{ + SSL_CTX *sctx = NULL, *cctx = NULL; + SSL *serverssl = NULL, *clientssl = NULL; + int testresult = 0; + + if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), + TLS_client_method(), &sctx, + &cctx, cert, privkey))) + goto end; + + /* Set up the cookie generation and verification callbacks */ + SSL_CTX_set_cookie_generate_cb(sctx, generate_cookie_callback); + SSL_CTX_set_cookie_verify_cb(sctx, verify_cookie_callback); + + /* The arrival of CCS messages can confuse the test */ + SSL_CTX_clear_options(cctx, SSL_OP_ENABLE_MIDDLEBOX_COMPAT); + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL)) + /* Send the first ClientHello */ + || !TEST_false(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_WANT_READ)) + /* This should fail because there is no cookie */ + || !TEST_false(SSL_stateless(serverssl))) + goto end; + + /* Abandon the connection from this client */ + SSL_free(clientssl); + clientssl = NULL; + + /* + * Now create a connection from a new client but with the same server SSL + * object + */ + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL)) + /* Send the first ClientHello */ + || !TEST_false(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_WANT_READ)) + /* This should fail because there is no cookie */ + || !TEST_false(SSL_stateless(serverssl)) + /* Send the second ClientHello */ + || !TEST_false(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_WANT_READ)) + /* This should succeed because a cookie is now present */ + || !TEST_true(SSL_stateless(serverssl)) + /* Complete the connection */ + || !TEST_true(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE))) + goto end; + + shutdown_ssl_connection(serverssl, clientssl); + serverssl = clientssl = NULL; + testresult = 1; + + end: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + return testresult; + +} #endif /* OPENSSL_NO_TLS1_3 */ static int clntaddoldcb = 0; @@ -2617,6 +2782,12 @@ static int test_custom_exts(int tst) SSL_SESSION *sess = NULL; unsigned int context; +#if defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_TLS1_3) + /* Skip tests for TLSv1.2 and below in this case */ + if (tst < 3) + return 1; +#endif + /* Reset callback counters */ clntaddoldcb = clntparseoldcb = srvaddoldcb = srvparseoldcb = 0; clntaddnewcb = clntparsenewcb = srvaddnewcb = srvparsenewcb = 0; @@ -2986,6 +3157,85 @@ static int test_export_key_mat(int tst) return testresult; } +#ifndef OPENSSL_NO_TLS1_3 +/* + * Test that SSL_export_keying_material_early() produces expected + * results. There are no test vectors so all we do is test that both + * sides of the communication produce the same results for different + * protocol versions. + */ +static int test_export_key_mat_early(int idx) +{ + static const char label[] = "test label"; + static const unsigned char context[] = "context"; + int testresult = 0; + SSL_CTX *cctx = NULL, *sctx = NULL; + SSL *clientssl = NULL, *serverssl = NULL; + SSL_SESSION *sess = NULL; + const unsigned char *emptycontext = NULL; + unsigned char ckeymat1[80], ckeymat2[80]; + unsigned char skeymat1[80], skeymat2[80]; + unsigned char buf[1]; + size_t readbytes, written; + + if (!TEST_true(setupearly_data_test(&cctx, &sctx, &clientssl, &serverssl, + &sess, idx))) + goto end; + + /* Here writing 0 length early data is enough. */ + if (!TEST_true(SSL_write_early_data(clientssl, NULL, 0, &written)) + || !TEST_int_eq(SSL_read_early_data(serverssl, buf, sizeof(buf), + &readbytes), + SSL_READ_EARLY_DATA_ERROR) + || !TEST_int_eq(SSL_get_early_data_status(serverssl), + SSL_EARLY_DATA_ACCEPTED)) + goto end; + + if (!TEST_int_eq(SSL_export_keying_material_early( + clientssl, ckeymat1, sizeof(ckeymat1), label, + sizeof(label) - 1, context, sizeof(context) - 1), 1) + || !TEST_int_eq(SSL_export_keying_material_early( + clientssl, ckeymat2, sizeof(ckeymat2), label, + sizeof(label) - 1, emptycontext, 0), 1) + || !TEST_int_eq(SSL_export_keying_material_early( + serverssl, skeymat1, sizeof(skeymat1), label, + sizeof(label) - 1, context, sizeof(context) - 1), 1) + || !TEST_int_eq(SSL_export_keying_material_early( + serverssl, skeymat2, sizeof(skeymat2), label, + sizeof(label) - 1, emptycontext, 0), 1) + /* + * Check that both sides created the same key material with the + * same context. + */ + || !TEST_mem_eq(ckeymat1, sizeof(ckeymat1), skeymat1, + sizeof(skeymat1)) + /* + * Check that both sides created the same key material with an + * empty context. + */ + || !TEST_mem_eq(ckeymat2, sizeof(ckeymat2), skeymat2, + sizeof(skeymat2)) + /* Different contexts should produce different results */ + || !TEST_mem_ne(ckeymat1, sizeof(ckeymat1), ckeymat2, + sizeof(ckeymat2))) + goto end; + + testresult = 1; + + end: + if (sess != clientpsk) + SSL_SESSION_free(sess); + SSL_SESSION_free(clientpsk); + SSL_SESSION_free(serverpsk); + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + + return testresult; +} +#endif /* OPENSSL_NO_TLS1_3 */ + static int test_ssl_clear(int idx) { SSL_CTX *cctx = NULL, *sctx = NULL; @@ -3040,6 +3290,172 @@ static int test_ssl_clear(int idx) return testresult; } +/* Parse CH and retrieve any MFL extension value if present */ +static int get_MFL_from_client_hello(BIO *bio, int *mfl_codemfl_code) +{ + long len; + unsigned char *data; + PACKET pkt = {0}, pkt2 = {0}, pkt3 = {0}; + unsigned int MFL_code = 0, type = 0; + + if (!TEST_uint_gt( len = BIO_get_mem_data( bio, (char **) &data ), 0 ) ) + goto end; + + if (!TEST_true( PACKET_buf_init( &pkt, data, len ) ) + /* Skip the record header */ + || !PACKET_forward(&pkt, SSL3_RT_HEADER_LENGTH) + /* Skip the handshake message header */ + || !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_max_fragment_length) { + if (!TEST_uint_ne(PACKET_remaining(&pkt3), 0) + || !TEST_true(PACKET_get_1(&pkt3, &MFL_code))) + goto end; + + *mfl_codemfl_code = MFL_code; + return 1; + } + } + + end: + return 0; +} + +/* Maximum-Fragment-Length TLS extension mode to test */ +static const unsigned char max_fragment_len_test[] = { + TLSEXT_max_fragment_length_512, + TLSEXT_max_fragment_length_1024, + TLSEXT_max_fragment_length_2048, + TLSEXT_max_fragment_length_4096 +}; + +static int test_max_fragment_len_ext(int idx_tst) +{ + SSL_CTX *ctx; + SSL *con = NULL; + int testresult = 0, MFL_mode = 0; + BIO *rbio, *wbio; + + ctx = SSL_CTX_new(TLS_method()); + if (!TEST_ptr(ctx)) + goto end; + + if (!TEST_true(SSL_CTX_set_tlsext_max_fragment_length( + ctx, max_fragment_len_test[idx_tst]))) + goto end; + + con = SSL_new(ctx); + if (!TEST_ptr(con)) + 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 (!TEST_int_le(SSL_connect(con), 0)) { + /* This shouldn't succeed because we don't have a server! */ + goto end; + } + + if (!TEST_true(get_MFL_from_client_hello(wbio, &MFL_mode))) + /* no MFL in client hello */ + goto end; + if (!TEST_true(max_fragment_len_test[idx_tst] == MFL_mode)) + goto end; + + testresult = 1; + +end: + SSL_free(con); + SSL_CTX_free(ctx); + + return testresult; +} + +#ifndef OPENSSL_NO_TLS1_3 +static int test_pha_key_update(void) +{ + SSL_CTX *cctx = NULL, *sctx = NULL; + SSL *clientssl = NULL, *serverssl = NULL; + int testresult = 0; + + if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), + TLS_client_method(), + &sctx, &cctx, cert, privkey))) + return 0; + + if (!TEST_true(SSL_CTX_set_min_proto_version(sctx, TLS1_3_VERSION)) + || !TEST_true(SSL_CTX_set_max_proto_version(sctx, TLS1_3_VERSION)) + || !TEST_true(SSL_CTX_set_min_proto_version(cctx, TLS1_3_VERSION)) + || !TEST_true(SSL_CTX_set_max_proto_version(cctx, TLS1_3_VERSION))) + goto end; + + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, + NULL, NULL))) + goto end; + + SSL_force_post_handshake_auth(clientssl); + + if (!TEST_true(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE))) + goto end; + + SSL_set_verify(serverssl, SSL_VERIFY_PEER, NULL); + if (!TEST_true(SSL_verify_client_post_handshake(serverssl))) + goto end; + + if (!TEST_true(SSL_key_update(clientssl, SSL_KEY_UPDATE_NOT_REQUESTED))) + goto end; + + /* Start handshake on the server */ + if (!TEST_int_eq(SSL_do_handshake(serverssl), 1)) + goto end; + + /* Starts with SSL_connect(), but it's really just SSL_do_handshake() */ + if (!TEST_true(create_ssl_connection(serverssl, clientssl, + SSL_ERROR_NONE))) + goto end; + + SSL_shutdown(clientssl); + SSL_shutdown(serverssl); + + testresult = 1; + + end: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + return testresult; +} +#endif + int setup_tests(void) { if (!TEST_ptr(cert = test_get_argument(0)) @@ -3062,20 +3478,22 @@ int setup_tests(void) ADD_TEST(test_ssl_bio_pop_ssl_bio); ADD_TEST(test_ssl_bio_change_rbio); ADD_TEST(test_ssl_bio_change_wbio); +#if !defined(OPENSSL_NO_TLS1_2) || defined(OPENSSL_NO_TLS1_3) ADD_ALL_TESTS(test_set_sigalgs, OSSL_NELEM(testsigalgs) * 2); ADD_TEST(test_keylog); +#endif #ifndef OPENSSL_NO_TLS1_3 ADD_TEST(test_keylog_no_master_key); #endif #ifndef OPENSSL_NO_TLS1_2 - ADD_TEST(test_early_cb); + ADD_TEST(test_client_hello_cb); #endif #ifndef OPENSSL_NO_TLS1_3 ADD_ALL_TESTS(test_early_data_read_write, 3); ADD_ALL_TESTS(test_early_data_skip, 3); ADD_ALL_TESTS(test_early_data_skip_hrr, 3); ADD_ALL_TESTS(test_early_data_not_sent, 3); - ADD_ALL_TESTS(test_early_data_psk, 7); + ADD_ALL_TESTS(test_early_data_psk, 8); ADD_ALL_TESTS(test_early_data_not_expected, 3); # ifndef OPENSSL_NO_TLS1_2 ADD_ALL_TESTS(test_early_data_tls1_2, 3); @@ -3085,12 +3503,18 @@ int setup_tests(void) ADD_TEST(test_ciphersuite_change); ADD_TEST(test_tls13_psk); ADD_ALL_TESTS(test_custom_exts, 5); + ADD_TEST(test_stateless); + ADD_TEST(test_pha_key_update); #else ADD_ALL_TESTS(test_custom_exts, 3); #endif ADD_ALL_TESTS(test_serverinfo, 8); ADD_ALL_TESTS(test_export_key_mat, 4); +#ifndef OPENSSL_NO_TLS1_3 + ADD_ALL_TESTS(test_export_key_mat_early, 3); +#endif ADD_ALL_TESTS(test_ssl_clear, 2); + ADD_ALL_TESTS(test_max_fragment_len_ext, OSSL_NELEM(max_fragment_len_test)); return 1; }