+ break;
+
+ case 2:
+ /*
+ * Set invalid protocol version. Technically this affects PSKs without
+ * early_data too, but we test it here because it is similar to the
+ * SNI/ALPN consistency tests.
+ */
+ err = SSL_R_BAD_PSK;
+ if (!TEST_true(SSL_SESSION_set_protocol_version(sess, TLS1_2_VERSION)))
+ goto end;
+ break;
+
+ case 3:
+ /*
+ * Set inconsistent SNI (server side). In this case the connection
+ * will succeed and accept early_data. In TLSv1.3 on the server side SNI
+ * is associated with each handshake - not the session. Therefore it
+ * should not matter that we used a different server name last time.
+ */
+ SSL_SESSION_free(serverpsk);
+ serverpsk = SSL_SESSION_dup(clientpsk);
+ if (!TEST_ptr(serverpsk)
+ || !TEST_true(SSL_SESSION_set1_hostname(serverpsk, "badhost")))
+ goto end;
+ /* Fall through */
+ case 4:
+ /* Set consistent SNI */
+ 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,
+ hostname_cb)))
+ goto end;
+ break;
+
+ case 5:
+ /*
+ * Set inconsistent ALPN (server detected). In this case the connection
+ * will succeed but reject early_data.
+ */
+ servalpn = "badalpn";
+ edstatus = SSL_EARLY_DATA_REJECTED;
+ readearlyres = SSL_READ_EARLY_DATA_FINISH;
+ /* Fall through */
+ case 6:
+ /*
+ * 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,
+ 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;
+ }
+
+ SSL_set_connect_state(clientssl);
+ if (err != 0) {
+ if (!TEST_false(SSL_write_early_data(clientssl, MSG1, strlen(MSG1),
+ &written))
+ || !TEST_int_eq(SSL_get_error(clientssl, 0), SSL_ERROR_SSL)
+ || !TEST_int_eq(ERR_GET_REASON(ERR_get_error()), err))
+ goto end;
+ } else {
+ if (!TEST_true(SSL_write_early_data(clientssl, MSG1, strlen(MSG1),
+ &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_connect(clientssl), connectres))
+ goto end;
+ }
+
+ testresult = 1;
+
+ end:
+ 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);
+ SSL_CTX_free(cctx);
+ return testresult;
+}
+
+/*
+ * Test TLSv1.3 PSK can be used to send early_data with all 5 ciphersuites
+ * idx == 0: Test with TLS1_3_RFC_AES_128_GCM_SHA256
+ * idx == 1: Test with TLS1_3_RFC_AES_256_GCM_SHA384
+ * idx == 2: Test with TLS1_3_RFC_CHACHA20_POLY1305_SHA256,
+ * idx == 3: Test with TLS1_3_RFC_AES_128_CCM_SHA256
+ * idx == 4: Test with TLS1_3_RFC_AES_128_CCM_8_SHA256
+ */
+static int test_early_data_psk_with_all_ciphers(int idx)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ SSL_SESSION *sess = NULL;
+ unsigned char buf[20];
+ size_t readbytes, written;
+ const SSL_CIPHER *cipher;
+ const char *cipher_str[] = {
+ TLS1_3_RFC_AES_128_GCM_SHA256,
+ TLS1_3_RFC_AES_256_GCM_SHA384,
+# if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
+ TLS1_3_RFC_CHACHA20_POLY1305_SHA256,
+# else
+ NULL,
+# endif
+ TLS1_3_RFC_AES_128_CCM_SHA256,
+ TLS1_3_RFC_AES_128_CCM_8_SHA256
+ };
+ const unsigned char *cipher_bytes[] = {
+ TLS13_AES_128_GCM_SHA256_BYTES,
+ TLS13_AES_256_GCM_SHA384_BYTES,
+# if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
+ TLS13_CHACHA20_POLY1305_SHA256_BYTES,
+# else
+ NULL,
+# endif
+ TLS13_AES_128_CCM_SHA256_BYTES,
+ TLS13_AES_128_CCM_8_SHA256_BYTES
+ };
+
+ if (cipher_str[idx] == NULL)
+ return 1;
+ /* Skip ChaCha20Poly1305 as currently FIPS module does not support it */
+ if (idx == 2 && is_fips == 1)
+ return 1;
+
+ /* We always set this up with a final parameter of "2" for PSK */
+ if (!TEST_true(setupearly_data_test(&cctx, &sctx, &clientssl,
+ &serverssl, &sess, 2)))
+ goto end;
+
+ if (!TEST_true(SSL_set_ciphersuites(clientssl, cipher_str[idx]))
+ || !TEST_true(SSL_set_ciphersuites(serverssl, cipher_str[idx])))
+ goto end;
+
+ /*
+ * 'setupearly_data_test' creates only one instance of SSL_SESSION
+ * and assigns to both client and server with incremented reference
+ * and the same instance is updated in 'sess'.
+ * So updating ciphersuite in 'sess' which will get reflected in
+ * PSK handshake using psk use sess and find sess cb.
+ */
+ cipher = SSL_CIPHER_find(clientssl, cipher_bytes[idx]);
+ if (!TEST_ptr(cipher) || !TEST_true(SSL_SESSION_set_cipher(sess, cipher)))
+ goto end;
+
+ SSL_set_connect_state(clientssl);
+ if (!TEST_true(SSL_write_early_data(clientssl, MSG1, strlen(MSG1),
+ &written)))
+ goto end;
+
+ if (!TEST_int_eq(SSL_read_early_data(serverssl, buf, sizeof(buf),
+ &readbytes),
+ SSL_READ_EARLY_DATA_SUCCESS)
+ || !TEST_mem_eq(buf, readbytes, MSG1, strlen(MSG1))
+ || !TEST_int_eq(SSL_get_early_data_status(serverssl),
+ SSL_EARLY_DATA_ACCEPTED)
+ || !TEST_int_eq(SSL_connect(clientssl), 1)
+ || !TEST_int_eq(SSL_accept(serverssl), 1))
+ goto end;
+
+ /* Send some normal data from client to server */
+ if (!TEST_true(SSL_write_ex(clientssl, MSG2, strlen(MSG2), &written))
+ || !TEST_size_t_eq(written, strlen(MSG2)))
+ goto end;
+
+ if (!TEST_true(SSL_read_ex(serverssl, buf, sizeof(buf), &readbytes))
+ || !TEST_mem_eq(buf, readbytes, MSG2, strlen(MSG2)))
+ goto end;
+
+ testresult = 1;
+ end:
+ SSL_SESSION_free(sess);
+ SSL_SESSION_free(clientpsk);
+ SSL_SESSION_free(serverpsk);
+ clientpsk = serverpsk = NULL;
+ if (clientssl != NULL)
+ SSL_shutdown(clientssl);
+ if (serverssl != NULL)
+ SSL_shutdown(serverssl);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ return testresult;
+}
+
+/*
+ * Test that a server that doesn't try to read early data can handle a
+ * client sending some.
+ */
+static int test_early_data_not_expected(int idx)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ SSL_SESSION *sess = NULL;
+ unsigned char buf[20];
+ size_t readbytes, written;
+
+ if (!TEST_true(setupearly_data_test(&cctx, &sctx, &clientssl,
+ &serverssl, &sess, idx)))
+ goto end;
+
+ /* Write some early data */
+ if (!TEST_true(SSL_write_early_data(clientssl, MSG1, strlen(MSG1),
+ &written)))
+ goto end;
+
+ /*
+ * Server should skip over early data and then block waiting for client to
+ * continue handshake
+ */
+ if (!TEST_int_le(SSL_accept(serverssl), 0)
+ || !TEST_int_gt(SSL_connect(clientssl), 0)
+ || !TEST_int_eq(SSL_get_early_data_status(serverssl),
+ SSL_EARLY_DATA_REJECTED)
+ || !TEST_int_gt(SSL_accept(serverssl), 0)
+ || !TEST_int_eq(SSL_get_early_data_status(clientssl),
+ SSL_EARLY_DATA_REJECTED))
+ goto end;
+
+ /* Send some normal data from client to server */
+ if (!TEST_true(SSL_write_ex(clientssl, MSG2, strlen(MSG2), &written))
+ || !TEST_size_t_eq(written, strlen(MSG2)))
+ goto end;
+
+ if (!TEST_true(SSL_read_ex(serverssl, buf, sizeof(buf), &readbytes))
+ || !TEST_mem_eq(buf, readbytes, MSG2, strlen(MSG2)))
+ goto end;
+
+ testresult = 1;
+
+ end:
+ 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);
+ SSL_CTX_free(cctx);
+ return testresult;
+}
+
+
+# ifndef OPENSSL_NO_TLS1_2
+/*
+ * Test that a server attempting to read early data can handle a connection
+ * from a TLSv1.2 client.
+ */
+static int test_early_data_tls1_2(int idx)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ unsigned char buf[20];
+ size_t readbytes, written;
+
+ if (!TEST_true(setupearly_data_test(&cctx, &sctx, &clientssl,
+ &serverssl, NULL, idx)))
+ goto end;
+
+ /* Write some data - should block due to handshake with server */
+ SSL_set_max_proto_version(clientssl, TLS1_2_VERSION);
+ SSL_set_connect_state(clientssl);
+ if (!TEST_false(SSL_write_ex(clientssl, MSG1, strlen(MSG1), &written)))
+ goto end;
+
+ /*
+ * Server should do TLSv1.2 handshake. First it will block waiting for more
+ * messages from client after ServerDone. Then SSL_read_early_data should
+ * finish and detect that early data has not been sent
+ */
+ if (!TEST_int_eq(SSL_read_early_data(serverssl, buf, sizeof(buf),
+ &readbytes),
+ SSL_READ_EARLY_DATA_ERROR))
+ goto end;
+
+ /*
+ * Continue writing the message we started earlier. Will still block waiting
+ * for the CCS/Finished from server
+ */
+ if (!TEST_false(SSL_write_ex(clientssl, MSG1, strlen(MSG1), &written))
+ || !TEST_int_eq(SSL_read_early_data(serverssl, buf, sizeof(buf),
+ &readbytes),
+ SSL_READ_EARLY_DATA_FINISH)
+ || !TEST_size_t_eq(readbytes, 0)
+ || !TEST_int_eq(SSL_get_early_data_status(serverssl),
+ SSL_EARLY_DATA_NOT_SENT))
+ goto end;
+
+ /* Continue writing the message we started earlier */
+ if (!TEST_true(SSL_write_ex(clientssl, MSG1, strlen(MSG1), &written))
+ || !TEST_size_t_eq(written, strlen(MSG1))
+ || !TEST_int_eq(SSL_get_early_data_status(clientssl),
+ SSL_EARLY_DATA_NOT_SENT)
+ || !TEST_true(SSL_read_ex(serverssl, buf, sizeof(buf), &readbytes))
+ || !TEST_mem_eq(buf, readbytes, MSG1, strlen(MSG1))
+ || !TEST_true(SSL_write_ex(serverssl, MSG2, strlen(MSG2), &written))
+ || !TEST_size_t_eq(written, strlen(MSG2))
+ || !SSL_read_ex(clientssl, buf, sizeof(buf), &readbytes)
+ || !TEST_mem_eq(buf, readbytes, MSG2, strlen(MSG2)))
+ goto end;
+
+ testresult = 1;
+
+ end:
+ SSL_SESSION_free(clientpsk);
+ SSL_SESSION_free(serverpsk);
+ clientpsk = serverpsk = NULL;
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+# endif /* OPENSSL_NO_TLS1_2 */
+
+/*
+ * Test configuring the TLSv1.3 ciphersuites
+ *
+ * Test 0: Set a default ciphersuite in the SSL_CTX (no explicit cipher_list)
+ * Test 1: Set a non-default ciphersuite in the SSL_CTX (no explicit cipher_list)
+ * Test 2: Set a default ciphersuite in the SSL (no explicit cipher_list)
+ * Test 3: Set a non-default ciphersuite in the SSL (no explicit cipher_list)
+ * Test 4: Set a default ciphersuite in the SSL_CTX (SSL_CTX cipher_list)
+ * Test 5: Set a non-default ciphersuite in the SSL_CTX (SSL_CTX cipher_list)
+ * Test 6: Set a default ciphersuite in the SSL (SSL_CTX cipher_list)
+ * Test 7: Set a non-default ciphersuite in the SSL (SSL_CTX cipher_list)
+ * Test 8: Set a default ciphersuite in the SSL (SSL cipher_list)
+ * Test 9: Set a non-default ciphersuite in the SSL (SSL cipher_list)
+ */
+static int test_set_ciphersuite(int idx)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+
+ if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
+ TLS_client_method(), TLS1_VERSION, 0,
+ &sctx, &cctx, cert, privkey))
+ || !TEST_true(SSL_CTX_set_ciphersuites(sctx,
+ "TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256")))
+ goto end;
+
+ if (idx >=4 && idx <= 7) {
+ /* SSL_CTX explicit cipher list */
+ if (!TEST_true(SSL_CTX_set_cipher_list(cctx, "AES256-GCM-SHA384")))
+ goto end;
+ }
+
+ if (idx == 0 || idx == 4) {
+ /* Default ciphersuite */
+ if (!TEST_true(SSL_CTX_set_ciphersuites(cctx,
+ "TLS_AES_128_GCM_SHA256")))
+ goto end;
+ } else if (idx == 1 || idx == 5) {
+ /* Non default ciphersuite */
+ if (!TEST_true(SSL_CTX_set_ciphersuites(cctx,
+ "TLS_AES_128_CCM_SHA256")))
+ goto end;
+ }
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
+ &clientssl, NULL, NULL)))
+ goto end;
+
+ if (idx == 8 || idx == 9) {
+ /* SSL explicit cipher list */
+ if (!TEST_true(SSL_set_cipher_list(clientssl, "AES256-GCM-SHA384")))
+ goto end;
+ }
+
+ if (idx == 2 || idx == 6 || idx == 8) {
+ /* Default ciphersuite */
+ if (!TEST_true(SSL_set_ciphersuites(clientssl,
+ "TLS_AES_128_GCM_SHA256")))
+ goto end;
+ } else if (idx == 3 || idx == 7 || idx == 9) {
+ /* Non default ciphersuite */
+ if (!TEST_true(SSL_set_ciphersuites(clientssl,
+ "TLS_AES_128_CCM_SHA256")))
+ goto end;
+ }
+
+ if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)))
+ goto end;
+
+ testresult = 1;
+
+ end:
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+
+static int test_ciphersuite_change(void)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ SSL_SESSION *clntsess = NULL;
+ int testresult = 0;
+ const SSL_CIPHER *aes_128_gcm_sha256 = NULL;
+
+ /* Create a session based on SHA-256 */
+ if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
+ TLS_client_method(), TLS1_VERSION, 0,
+ &sctx, &cctx, cert, privkey))
+ || !TEST_true(SSL_CTX_set_ciphersuites(sctx,
+ "TLS_AES_128_GCM_SHA256:"
+ "TLS_AES_256_GCM_SHA384:"
+ "TLS_AES_128_CCM_SHA256"))
+ || !TEST_true(SSL_CTX_set_ciphersuites(cctx,
+ "TLS_AES_128_GCM_SHA256"))
+ || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
+ &clientssl, NULL, NULL))
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ clntsess = SSL_get1_session(clientssl);
+ /* Save for later */
+ aes_128_gcm_sha256 = SSL_SESSION_get0_cipher(clntsess);
+ SSL_shutdown(clientssl);
+ SSL_shutdown(serverssl);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ serverssl = clientssl = NULL;
+
+ /* Check we can resume a session with a different SHA-256 ciphersuite */
+ if (!TEST_true(SSL_CTX_set_ciphersuites(cctx,
+ "TLS_AES_128_CCM_SHA256"))
+ || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
+ &clientssl, NULL, NULL))
+ || !TEST_true(SSL_set_session(clientssl, clntsess))
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE))
+ || !TEST_true(SSL_session_reused(clientssl)))
+ goto end;
+
+ SSL_SESSION_free(clntsess);
+ clntsess = SSL_get1_session(clientssl);
+ SSL_shutdown(clientssl);
+ SSL_shutdown(serverssl);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ serverssl = clientssl = NULL;
+
+ /*
+ * Check attempting to resume a SHA-256 session with no SHA-256 ciphersuites
+ * succeeds but does not resume.
+ */
+ if (!TEST_true(SSL_CTX_set_ciphersuites(cctx, "TLS_AES_256_GCM_SHA384"))
+ || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL))
+ || !TEST_true(SSL_set_session(clientssl, clntsess))
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_SSL))
+ || !TEST_false(SSL_session_reused(clientssl)))
+ goto end;
+
+ SSL_SESSION_free(clntsess);
+ clntsess = NULL;
+ SSL_shutdown(clientssl);
+ SSL_shutdown(serverssl);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ serverssl = clientssl = NULL;
+
+ /* Create a session based on SHA384 */
+ if (!TEST_true(SSL_CTX_set_ciphersuites(cctx, "TLS_AES_256_GCM_SHA384"))
+ || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
+ &clientssl, NULL, NULL))
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ clntsess = SSL_get1_session(clientssl);
+ SSL_shutdown(clientssl);
+ SSL_shutdown(serverssl);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ serverssl = clientssl = NULL;
+
+ if (!TEST_true(SSL_CTX_set_ciphersuites(cctx,
+ "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384"))
+ || !TEST_true(SSL_CTX_set_ciphersuites(sctx,
+ "TLS_AES_256_GCM_SHA384"))
+ || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL))
+ || !TEST_true(SSL_set_session(clientssl, clntsess))
+ /*
+ * We use SSL_ERROR_WANT_READ below so that we can pause the
+ * connection after the initial ClientHello has been sent to
+ * enable us to make some session changes.
+ */
+ || !TEST_false(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_WANT_READ)))
+ goto end;
+
+ /* Trick the client into thinking this session is for a different digest */
+ clntsess->cipher = aes_128_gcm_sha256;
+ clntsess->cipher_id = clntsess->cipher->id;
+
+ /*
+ * Continue the previously started connection. Server has selected a SHA-384
+ * ciphersuite, but client thinks the session is for SHA-256, so it should
+ * bail out.
+ */
+ if (!TEST_false(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_SSL))
+ || !TEST_int_eq(ERR_GET_REASON(ERR_get_error()),
+ SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED))
+ goto end;
+
+ testresult = 1;
+
+ end:
+ SSL_SESSION_free(clntsess);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+
+/*
+ * Test TLSv1.3 Key exchange
+ * Test 0 = Test all ECDHE Key exchange with TLSv1.3 client and server
+ * Test 1 = Test NID_X9_62_prime256v1 with TLSv1.3 client and server
+ * Test 2 = Test NID_secp384r1 with TLSv1.3 client and server
+ * Test 3 = Test NID_secp521r1 with TLSv1.3 client and server
+ * Test 4 = Test NID_X25519 with TLSv1.3 client and server
+ * Test 5 = Test NID_X448 with TLSv1.3 client and server
+ * Test 6 = Test all FFDHE Key exchange with TLSv1.3 client and server
+ * Test 7 = Test NID_ffdhe2048 with TLSv1.3 client and server
+ * Test 8 = Test NID_ffdhe3072 with TLSv1.3 client and server
+ * Test 9 = Test NID_ffdhe4096 with TLSv1.3 client and server
+ * Test 10 = Test NID_ffdhe6144 with TLSv1.3 client and server
+ * Test 11 = Test NID_ffdhe8192 with TLSv1.3 client and server
+ * Test 12 = Test all ECDHE with TLSv1.2 client and server
+ * Test 13 = Test all FFDHE with TLSv1.2 client and server
+ */
+static int test_key_exchange(int idx)
+{
+ SSL_CTX *sctx = NULL, *cctx = NULL;
+ SSL *serverssl = NULL, *clientssl = NULL;
+ int testresult = 0;
+# ifndef OPENSSL_NO_EC
+ int ecdhe_kexch_groups[] = {NID_X9_62_prime256v1, NID_secp384r1,
+ NID_secp521r1, NID_X25519, NID_X448};
+# endif
+# ifndef OPENSSL_NO_DH
+ int ffdhe_kexch_groups[] = {NID_ffdhe2048, NID_ffdhe3072, NID_ffdhe4096,
+ NID_ffdhe6144, NID_ffdhe8192};
+# endif
+ int kexch_alg;
+ int *kexch_groups = &kexch_alg;
+ int kexch_groups_size = 1;
+ int max_version = TLS1_3_VERSION;
+
+ switch (idx) {
+# ifndef OPENSSL_NO_EC
+# ifndef OPENSSL_NO_TLS1_2
+ case 12:
+ max_version = TLS1_2_VERSION;
+# endif
+ /* Fall through */
+ case 0:
+ kexch_groups = ecdhe_kexch_groups;
+ kexch_groups_size = OSSL_NELEM(ecdhe_kexch_groups);
+ break;
+ case 1:
+ kexch_alg = NID_X9_62_prime256v1;
+ break;
+ case 2:
+ kexch_alg = NID_secp384r1;
+ break;
+ case 3:
+ kexch_alg = NID_secp521r1;
+ break;
+ case 4:
+ kexch_alg = NID_X25519;
+ break;
+ case 5:
+ kexch_alg = NID_X448;
+ break;
+# endif
+# ifndef OPENSSL_NO_DH
+# ifndef OPENSSL_NO_TLS1_2
+ case 13:
+ max_version = TLS1_2_VERSION;
+# endif
+ /* Fall through */
+ case 6:
+ kexch_groups = ffdhe_kexch_groups;
+ kexch_groups_size = OSSL_NELEM(ffdhe_kexch_groups);
+ break;
+ case 7:
+ kexch_alg = NID_ffdhe2048;
+ break;
+ case 8:
+ kexch_alg = NID_ffdhe3072;
+ break;
+ case 9:
+ kexch_alg = NID_ffdhe4096;
+ break;
+ case 10:
+ kexch_alg = NID_ffdhe6144;
+ break;
+ case 11:
+ kexch_alg = NID_ffdhe8192;
+ break;
+# endif
+ default:
+ /* We're skipping this test */
+ return 1;
+ }
+
+ if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
+ TLS_client_method(), TLS1_VERSION,
+ max_version, &sctx, &cctx, cert,
+ privkey)))
+ goto end;
+
+ if (!TEST_true(SSL_CTX_set_ciphersuites(sctx,
+ TLS1_3_RFC_AES_128_GCM_SHA256)))
+ goto end;
+
+ if (!TEST_true(SSL_CTX_set_ciphersuites(cctx,
+ TLS1_3_RFC_AES_128_GCM_SHA256)))
+ goto end;
+
+ if (!TEST_true(SSL_CTX_set_cipher_list(sctx,
+ TLS1_TXT_RSA_WITH_AES_128_SHA)))
+ goto end;
+
+ /*
+ * Must include an EC ciphersuite so that we send supported groups in
+ * TLSv1.2
+ */
+# ifndef OPENSSL_NO_TLS1_2
+ if (!TEST_true(SSL_CTX_set_cipher_list(cctx,
+ TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CCM ":"
+ TLS1_TXT_RSA_WITH_AES_128_SHA)))
+ goto end;
+# endif
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL)))
+ goto end;
+
+ if (!TEST_true(SSL_set1_groups(serverssl, kexch_groups, kexch_groups_size))
+ || !TEST_true(SSL_set1_groups(clientssl, kexch_groups, kexch_groups_size)))
+ goto end;
+
+ if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)))
+ goto end;
+
+ /*
+ * If Handshake succeeds the negotiated kexch alg should be the first one in
+ * configured, except in the case of FFDHE groups (idx 13), which are
+ * TLSv1.3 only so we expect no shared group to exist.
+ */
+ if (!TEST_int_eq(SSL_get_shared_group(serverssl, 0),
+ idx == 13 ? 0 : kexch_groups[0]))
+ goto end;
+ if (max_version == TLS1_3_VERSION) {
+ if (!TEST_int_eq(SSL_get_negotiated_group(serverssl), kexch_groups[0]))
+ goto end;
+ if (!TEST_int_eq(SSL_get_negotiated_group(clientssl), kexch_groups[0]))
+ goto end;
+ }
+
+ testresult = 1;
+ end:
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ return testresult;
+}
+
+/*
+ * Test TLSv1.3 Cipher Suite
+ * Test 0 = Set TLS1.3 cipher on context
+ * Test 1 = Set TLS1.3 cipher on SSL
+ * Test 2 = Set TLS1.3 and TLS1.2 cipher on context
+ * Test 3 = Set TLS1.3 and TLS1.2 cipher on SSL
+ */
+static int test_tls13_ciphersuite(int idx)
+{
+ SSL_CTX *sctx = NULL, *cctx = NULL;
+ SSL *serverssl = NULL, *clientssl = NULL;
+ static const struct {
+ const char *ciphername;
+ int fipscapable;
+ } t13_ciphers[] = {
+ { TLS1_3_RFC_AES_128_GCM_SHA256, 1 },
+ { TLS1_3_RFC_AES_256_GCM_SHA384, 1 },
+ { TLS1_3_RFC_AES_128_CCM_SHA256, 1 },
+# if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
+ { TLS1_3_RFC_CHACHA20_POLY1305_SHA256, 0 },
+ { TLS1_3_RFC_AES_256_GCM_SHA384
+ ":" TLS1_3_RFC_CHACHA20_POLY1305_SHA256, 0 },
+# endif
+ { TLS1_3_RFC_AES_128_CCM_8_SHA256 ":" TLS1_3_RFC_AES_128_CCM_SHA256, 1 }
+ };
+ const char *t13_cipher = NULL;
+ const char *t12_cipher = NULL;
+ const char *negotiated_scipher;
+ const char *negotiated_ccipher;
+ int set_at_ctx = 0;
+ int set_at_ssl = 0;
+ int testresult = 0;
+ int max_ver;
+ size_t i;
+
+ switch (idx) {
+ case 0:
+ set_at_ctx = 1;
+ break;
+ case 1:
+ set_at_ssl = 1;
+ break;
+ case 2:
+ set_at_ctx = 1;
+ t12_cipher = TLS1_TXT_RSA_WITH_AES_128_SHA256;
+ break;
+ case 3:
+ set_at_ssl = 1;
+ t12_cipher = TLS1_TXT_RSA_WITH_AES_128_SHA256;
+ break;
+ }
+
+ for (max_ver = TLS1_2_VERSION; max_ver <= TLS1_3_VERSION; max_ver++) {
+# ifdef OPENSSL_NO_TLS1_2
+ if (max_ver == TLS1_2_VERSION)
+ continue;
+# endif
+ for (i = 0; i < OSSL_NELEM(t13_ciphers); i++) {
+ if (is_fips && !t13_ciphers[i].fipscapable)
+ continue;
+ t13_cipher = t13_ciphers[i].ciphername;
+ if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
+ TLS_client_method(),
+ TLS1_VERSION, max_ver,
+ &sctx, &cctx, cert, privkey)))
+ goto end;
+
+ if (set_at_ctx) {
+ if (!TEST_true(SSL_CTX_set_ciphersuites(sctx, t13_cipher))
+ || !TEST_true(SSL_CTX_set_ciphersuites(cctx, t13_cipher)))
+ goto end;
+ if (t12_cipher != NULL) {
+ if (!TEST_true(SSL_CTX_set_cipher_list(sctx, t12_cipher))
+ || !TEST_true(SSL_CTX_set_cipher_list(cctx,
+ t12_cipher)))
+ goto end;
+ }
+ }
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
+ &clientssl, NULL, NULL)))
+ goto end;
+
+ if (set_at_ssl) {
+ if (!TEST_true(SSL_set_ciphersuites(serverssl, t13_cipher))
+ || !TEST_true(SSL_set_ciphersuites(clientssl, t13_cipher)))
+ goto end;
+ if (t12_cipher != NULL) {
+ if (!TEST_true(SSL_set_cipher_list(serverssl, t12_cipher))
+ || !TEST_true(SSL_set_cipher_list(clientssl,
+ t12_cipher)))
+ goto end;
+ }
+ }
+
+ if (!TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ negotiated_scipher = SSL_CIPHER_get_name(SSL_get_current_cipher(
+ serverssl));
+ negotiated_ccipher = SSL_CIPHER_get_name(SSL_get_current_cipher(
+ clientssl));
+ if (!TEST_str_eq(negotiated_scipher, negotiated_ccipher))
+ goto end;
+
+ /*
+ * TEST_strn_eq is used below because t13_cipher can contain
+ * multiple ciphersuites
+ */
+ if (max_ver == TLS1_3_VERSION
+ && !TEST_strn_eq(t13_cipher, negotiated_scipher,
+ strlen(negotiated_scipher)))
+ goto end;
+
+# ifndef OPENSSL_NO_TLS1_2
+ /* Below validation is not done when t12_cipher is NULL */
+ if (max_ver == TLS1_2_VERSION && t12_cipher != NULL
+ && !TEST_str_eq(t12_cipher, negotiated_scipher))
+ goto end;
+# endif
+
+ SSL_free(serverssl);
+ serverssl = NULL;
+ SSL_free(clientssl);
+ clientssl = NULL;
+ SSL_CTX_free(sctx);
+ sctx = NULL;
+ SSL_CTX_free(cctx);
+ cctx = NULL;
+ }
+ }
+
+ testresult = 1;
+ end:
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ return testresult;
+}
+
+/*
+ * Test TLSv1.3 PSKs
+ * Test 0 = Test new style callbacks
+ * Test 1 = Test both new and old style callbacks
+ * Test 2 = Test old style callbacks
+ * Test 3 = Test old style callbacks with no certificate
+ */
+static int test_tls13_psk(int idx)
+{
+ SSL_CTX *sctx = NULL, *cctx = NULL;
+ SSL *serverssl = NULL, *clientssl = NULL;
+ const SSL_CIPHER *cipher = NULL;
+ const unsigned char key[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f
+ };
+ int testresult = 0;
+
+ if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
+ TLS_client_method(), TLS1_VERSION, 0,
+ &sctx, &cctx, idx == 3 ? NULL : cert,
+ idx == 3 ? NULL : privkey)))
+ goto end;
+
+ if (idx != 3) {
+ /*
+ * We use a ciphersuite with SHA256 to ease testing old style PSK
+ * callbacks which will always default to SHA256. This should not be
+ * necessary if we have no cert/priv key. In that case the server should
+ * prefer SHA256 automatically.
+ */
+ if (!TEST_true(SSL_CTX_set_ciphersuites(cctx,
+ "TLS_AES_128_GCM_SHA256")))
+ goto end;
+ } else {
+ /*
+ * As noted above the server should prefer SHA256 automatically. However
+ * we are careful not to offer TLS_CHACHA20_POLY1305_SHA256 so this same
+ * code works even if we are testing with only the FIPS provider loaded.
+ */
+ if (!TEST_true(SSL_CTX_set_ciphersuites(cctx,
+ "TLS_AES_256_GCM_SHA384:"
+ "TLS_AES_128_GCM_SHA256")))
+ goto end;
+ }
+
+ /*
+ * Test 0: New style callbacks only
+ * Test 1: New and old style callbacks (only the new ones should be used)
+ * Test 2: Old style callbacks only
+ */
+ if (idx == 0 || idx == 1) {
+ SSL_CTX_set_psk_use_session_callback(cctx, use_session_cb);
+ SSL_CTX_set_psk_find_session_callback(sctx, find_session_cb);
+ }
+#ifndef OPENSSL_NO_PSK
+ if (idx >= 1) {
+ SSL_CTX_set_psk_client_callback(cctx, psk_client_cb);
+ SSL_CTX_set_psk_server_callback(sctx, psk_server_cb);
+ }
+#endif
+ srvid = pskid;
+ use_session_cb_cnt = 0;
+ find_session_cb_cnt = 0;
+ psk_client_cb_cnt = 0;
+ psk_server_cb_cnt = 0;
+
+ if (idx != 3) {
+ /*
+ * Check we can create a connection if callback decides not to send a
+ * PSK
+ */
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL))
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE))
+ || !TEST_false(SSL_session_reused(clientssl))
+ || !TEST_false(SSL_session_reused(serverssl)))
+ goto end;
+
+ if (idx == 0 || idx == 1) {
+ if (!TEST_true(use_session_cb_cnt == 1)
+ || !TEST_true(find_session_cb_cnt == 0)
+ /*
+ * If no old style callback then below should be 0
+ * otherwise 1
+ */
+ || !TEST_true(psk_client_cb_cnt == idx)
+ || !TEST_true(psk_server_cb_cnt == 0))
+ goto end;
+ } else {
+ if (!TEST_true(use_session_cb_cnt == 0)
+ || !TEST_true(find_session_cb_cnt == 0)
+ || !TEST_true(psk_client_cb_cnt == 1)
+ || !TEST_true(psk_server_cb_cnt == 0))
+ goto end;
+ }
+
+ shutdown_ssl_connection(serverssl, clientssl);
+ serverssl = clientssl = NULL;
+ use_session_cb_cnt = psk_client_cb_cnt = 0;
+ }
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL)))
+ goto end;
+
+ /* Create the PSK */
+ cipher = SSL_CIPHER_find(clientssl, TLS13_AES_128_GCM_SHA256_BYTES);
+ clientpsk = SSL_SESSION_new();
+ if (!TEST_ptr(clientpsk)
+ || !TEST_ptr(cipher)
+ || !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))
+ || !TEST_true(SSL_session_reused(clientssl))
+ || !TEST_true(SSL_session_reused(serverssl)))
+ goto end;
+
+ if (idx == 0 || idx == 1) {
+ if (!TEST_true(use_session_cb_cnt == 1)
+ || !TEST_true(find_session_cb_cnt == 1)
+ || !TEST_true(psk_client_cb_cnt == 0)
+ || !TEST_true(psk_server_cb_cnt == 0))
+ goto end;
+ } else {
+ if (!TEST_true(use_session_cb_cnt == 0)
+ || !TEST_true(find_session_cb_cnt == 0)
+ || !TEST_true(psk_client_cb_cnt == 1)
+ || !TEST_true(psk_server_cb_cnt == 1))
+ goto end;
+ }
+
+ shutdown_ssl_connection(serverssl, clientssl);
+ serverssl = clientssl = NULL;
+ use_session_cb_cnt = find_session_cb_cnt = 0;
+ psk_client_cb_cnt = psk_server_cb_cnt = 0;
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL)))
+ goto end;
+
+ /* Force an HRR */
+#if defined(OPENSSL_NO_EC)
+ if (!TEST_true(SSL_set1_groups_list(serverssl, "ffdhe3072")))
+ goto end;
+#else
+ if (!TEST_true(SSL_set1_groups_list(serverssl, "P-256")))
+ goto end;
+#endif
+
+ /*
+ * Check we can create a connection, the PSK is used and the callbacks are
+ * called twice.
+ */
+ if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))
+ || !TEST_true(SSL_session_reused(clientssl))
+ || !TEST_true(SSL_session_reused(serverssl)))
+ goto end;
+
+ if (idx == 0 || idx == 1) {
+ if (!TEST_true(use_session_cb_cnt == 2)
+ || !TEST_true(find_session_cb_cnt == 2)
+ || !TEST_true(psk_client_cb_cnt == 0)
+ || !TEST_true(psk_server_cb_cnt == 0))
+ goto end;
+ } else {
+ if (!TEST_true(use_session_cb_cnt == 0)
+ || !TEST_true(find_session_cb_cnt == 0)
+ || !TEST_true(psk_client_cb_cnt == 2)
+ || !TEST_true(psk_server_cb_cnt == 2))
+ goto end;
+ }
+
+ shutdown_ssl_connection(serverssl, clientssl);
+ serverssl = clientssl = NULL;
+ use_session_cb_cnt = find_session_cb_cnt = 0;
+ psk_client_cb_cnt = psk_server_cb_cnt = 0;
+
+ if (idx != 3) {
+ /*
+ * Check that if the server rejects the PSK we can still connect, but with
+ * a full handshake
+ */
+ srvid = "Dummy Identity";
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL))
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE))
+ || !TEST_false(SSL_session_reused(clientssl))
+ || !TEST_false(SSL_session_reused(serverssl)))
+ goto end;
+
+ if (idx == 0 || idx == 1) {
+ if (!TEST_true(use_session_cb_cnt == 1)
+ || !TEST_true(find_session_cb_cnt == 1)
+ || !TEST_true(psk_client_cb_cnt == 0)
+ /*
+ * If no old style callback then below should be 0
+ * otherwise 1
+ */
+ || !TEST_true(psk_server_cb_cnt == idx))
+ goto end;
+ } else {
+ if (!TEST_true(use_session_cb_cnt == 0)
+ || !TEST_true(find_session_cb_cnt == 0)
+ || !TEST_true(psk_client_cb_cnt == 1)
+ || !TEST_true(psk_server_cb_cnt == 1))
+ goto end;
+ }
+
+ shutdown_ssl_connection(serverssl, clientssl);
+ serverssl = clientssl = NULL;
+ }
+ testresult = 1;
+
+ end:
+ SSL_SESSION_free(clientpsk);
+ SSL_SESSION_free(serverpsk);
+ clientpsk = serverpsk = NULL;
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ 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 generate_stateless_cookie_callback(SSL *ssl, unsigned char *cookie,
+ size_t *cookie_len)
+{
+ unsigned int temp;
+ int res = generate_cookie_callback(ssl, cookie, &temp);
+ *cookie_len = temp;
+ return res;
+}
+
+static int verify_stateless_cookie_callback(SSL *ssl, const unsigned char *cookie,
+ size_t cookie_len)
+{
+ return verify_cookie_callback(ssl, cookie, cookie_len);
+}
+
+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(libctx, TLS_server_method(),
+ TLS_client_method(), TLS1_VERSION, 0,
+ &sctx, &cctx, cert, privkey)))
+ goto end;
+
+ /* 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 with a -1 return because we have no callbacks
+ * set up
+ */
+ || !TEST_int_eq(SSL_stateless(serverssl), -1))
+ goto end;
+
+ /* Fatal error so abandon the connection from this client */
+ SSL_free(clientssl);
+ clientssl = NULL;
+
+ /* Set up the cookie generation and verification callbacks */
+ SSL_CTX_set_stateless_cookie_generate_cb(sctx, generate_stateless_cookie_callback);
+ SSL_CTX_set_stateless_cookie_verify_cb(sctx, verify_stateless_cookie_callback);
+
+ /*
+ * Create a new connection from the client (we can reuse the 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_int_eq(SSL_stateless(serverssl), 0))
+ 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_int_eq(SSL_stateless(serverssl), 0)
+ /* 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_int_eq(SSL_stateless(serverssl), 1)
+ /* 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;
+static int clntparseoldcb = 0;
+static int srvaddoldcb = 0;
+static int srvparseoldcb = 0;
+static int clntaddnewcb = 0;
+static int clntparsenewcb = 0;
+static int srvaddnewcb = 0;
+static int srvparsenewcb = 0;
+static int snicb = 0;
+
+#define TEST_EXT_TYPE1 0xff00
+
+static int old_add_cb(SSL *s, unsigned int ext_type, const unsigned char **out,
+ size_t *outlen, int *al, void *add_arg)
+{
+ int *server = (int *)add_arg;
+ unsigned char *data;
+
+ if (SSL_is_server(s))
+ srvaddoldcb++;
+ else
+ clntaddoldcb++;
+
+ if (*server != SSL_is_server(s)
+ || (data = OPENSSL_malloc(sizeof(*data))) == NULL)
+ return -1;
+
+ *data = 1;
+ *out = data;
+ *outlen = sizeof(char);
+ return 1;
+}
+
+static void old_free_cb(SSL *s, unsigned int ext_type, const unsigned char *out,
+ void *add_arg)
+{
+ OPENSSL_free((unsigned char *)out);
+}
+
+static int old_parse_cb(SSL *s, unsigned int ext_type, const unsigned char *in,
+ size_t inlen, int *al, void *parse_arg)
+{
+ int *server = (int *)parse_arg;
+
+ if (SSL_is_server(s))
+ srvparseoldcb++;
+ else
+ clntparseoldcb++;
+
+ if (*server != SSL_is_server(s)
+ || inlen != sizeof(char)
+ || *in != 1)
+ return -1;
+
+ return 1;
+}
+
+static int new_add_cb(SSL *s, unsigned int ext_type, unsigned int context,
+ const unsigned char **out, size_t *outlen, X509 *x,
+ size_t chainidx, int *al, void *add_arg)
+{
+ int *server = (int *)add_arg;
+ unsigned char *data;
+
+ if (SSL_is_server(s))
+ srvaddnewcb++;
+ else
+ clntaddnewcb++;
+
+ if (*server != SSL_is_server(s)
+ || (data = OPENSSL_malloc(sizeof(*data))) == NULL)
+ return -1;
+
+ *data = 1;
+ *out = data;
+ *outlen = sizeof(*data);
+ return 1;
+}
+
+static void new_free_cb(SSL *s, unsigned int ext_type, unsigned int context,
+ const unsigned char *out, void *add_arg)
+{
+ OPENSSL_free((unsigned char *)out);
+}
+
+static int new_parse_cb(SSL *s, unsigned int ext_type, unsigned int context,
+ const unsigned char *in, size_t inlen, X509 *x,
+ size_t chainidx, int *al, void *parse_arg)
+{
+ int *server = (int *)parse_arg;
+
+ if (SSL_is_server(s))
+ srvparsenewcb++;
+ else
+ clntparsenewcb++;
+
+ if (*server != SSL_is_server(s)
+ || inlen != sizeof(char) || *in != 1)
+ return -1;
+
+ return 1;
+}
+
+static int sni_cb(SSL *s, int *al, void *arg)
+{
+ SSL_CTX *ctx = (SSL_CTX *)arg;
+
+ if (SSL_set_SSL_CTX(s, ctx) == NULL) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ snicb++;
+ return SSL_TLSEXT_ERR_OK;
+}
+
+/*
+ * Custom call back tests.
+ * Test 0: Old style callbacks in TLSv1.2
+ * Test 1: New style callbacks in TLSv1.2
+ * Test 2: New style callbacks in TLSv1.2 with SNI
+ * Test 3: New style callbacks in TLSv1.3. Extensions in CH and EE
+ * Test 4: New style callbacks in TLSv1.3. Extensions in CH, SH, EE, Cert + NST
+ */
+static int test_custom_exts(int tst)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL, *sctx2 = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ static int server = 1;
+ static int client = 0;
+ 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;
+ snicb = 0;
+
+ if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
+ TLS_client_method(), TLS1_VERSION, 0,
+ &sctx, &cctx, cert, privkey)))
+ goto end;
+
+ if (tst == 2
+ && !TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), NULL,
+ TLS1_VERSION, 0,
+ &sctx2, NULL, cert, privkey)))
+ goto end;
+
+
+ if (tst < 3) {
+ SSL_CTX_set_options(cctx, SSL_OP_NO_TLSv1_3);
+ SSL_CTX_set_options(sctx, SSL_OP_NO_TLSv1_3);
+ if (sctx2 != NULL)
+ SSL_CTX_set_options(sctx2, SSL_OP_NO_TLSv1_3);
+ }
+
+ if (tst == 4) {
+ context = SSL_EXT_CLIENT_HELLO
+ | SSL_EXT_TLS1_2_SERVER_HELLO
+ | SSL_EXT_TLS1_3_SERVER_HELLO
+ | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+ | SSL_EXT_TLS1_3_CERTIFICATE
+ | SSL_EXT_TLS1_3_NEW_SESSION_TICKET;
+ } else {
+ context = SSL_EXT_CLIENT_HELLO
+ | SSL_EXT_TLS1_2_SERVER_HELLO
+ | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS;
+ }
+
+ /* Create a client side custom extension */
+ if (tst == 0) {
+ if (!TEST_true(SSL_CTX_add_client_custom_ext(cctx, TEST_EXT_TYPE1,
+ old_add_cb, old_free_cb,
+ &client, old_parse_cb,
+ &client)))
+ goto end;
+ } else {
+ if (!TEST_true(SSL_CTX_add_custom_ext(cctx, TEST_EXT_TYPE1, context,
+ new_add_cb, new_free_cb,
+ &client, new_parse_cb, &client)))
+ goto end;
+ }
+
+ /* Should not be able to add duplicates */
+ if (!TEST_false(SSL_CTX_add_client_custom_ext(cctx, TEST_EXT_TYPE1,
+ old_add_cb, old_free_cb,
+ &client, old_parse_cb,
+ &client))
+ || !TEST_false(SSL_CTX_add_custom_ext(cctx, TEST_EXT_TYPE1,
+ context, new_add_cb,
+ new_free_cb, &client,
+ new_parse_cb, &client)))
+ goto end;
+
+ /* Create a server side custom extension */
+ if (tst == 0) {
+ if (!TEST_true(SSL_CTX_add_server_custom_ext(sctx, TEST_EXT_TYPE1,
+ old_add_cb, old_free_cb,
+ &server, old_parse_cb,
+ &server)))
+ goto end;
+ } else {
+ if (!TEST_true(SSL_CTX_add_custom_ext(sctx, TEST_EXT_TYPE1, context,
+ new_add_cb, new_free_cb,
+ &server, new_parse_cb, &server)))
+ goto end;
+ if (sctx2 != NULL
+ && !TEST_true(SSL_CTX_add_custom_ext(sctx2, TEST_EXT_TYPE1,
+ context, new_add_cb,
+ new_free_cb, &server,
+ new_parse_cb, &server)))
+ goto end;
+ }
+
+ /* Should not be able to add duplicates */
+ if (!TEST_false(SSL_CTX_add_server_custom_ext(sctx, TEST_EXT_TYPE1,
+ old_add_cb, old_free_cb,
+ &server, old_parse_cb,
+ &server))
+ || !TEST_false(SSL_CTX_add_custom_ext(sctx, TEST_EXT_TYPE1,
+ context, new_add_cb,
+ new_free_cb, &server,
+ new_parse_cb, &server)))
+ goto end;
+
+ if (tst == 2) {
+ /* Set up SNI */
+ if (!TEST_true(SSL_CTX_set_tlsext_servername_callback(sctx, sni_cb))
+ || !TEST_true(SSL_CTX_set_tlsext_servername_arg(sctx, sctx2)))
+ goto end;
+ }
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
+ &clientssl, NULL, NULL))
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ if (tst == 0) {
+ if (clntaddoldcb != 1
+ || clntparseoldcb != 1
+ || srvaddoldcb != 1
+ || srvparseoldcb != 1)
+ goto end;
+ } else if (tst == 1 || tst == 2 || tst == 3) {
+ if (clntaddnewcb != 1
+ || clntparsenewcb != 1
+ || srvaddnewcb != 1
+ || srvparsenewcb != 1
+ || (tst != 2 && snicb != 0)
+ || (tst == 2 && snicb != 1))
+ goto end;
+ } else {
+ /* In this case there 2 NewSessionTicket messages created */
+ if (clntaddnewcb != 1
+ || clntparsenewcb != 5
+ || srvaddnewcb != 5
+ || srvparsenewcb != 1)
+ goto end;
+ }
+
+ sess = SSL_get1_session(clientssl);
+ SSL_shutdown(clientssl);
+ SSL_shutdown(serverssl);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ serverssl = clientssl = NULL;
+
+ if (tst == 3) {
+ /* We don't bother with the resumption aspects for this test */
+ testresult = 1;
+ goto end;
+ }
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL))
+ || !TEST_true(SSL_set_session(clientssl, sess))
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ /*
+ * For a resumed session we expect to add the ClientHello extension. For the
+ * old style callbacks we ignore it on the server side because they set
+ * SSL_EXT_IGNORE_ON_RESUMPTION. The new style callbacks do not ignore
+ * them.
+ */
+ if (tst == 0) {
+ if (clntaddoldcb != 2
+ || clntparseoldcb != 1
+ || srvaddoldcb != 1
+ || srvparseoldcb != 1)
+ goto end;
+ } else if (tst == 1 || tst == 2 || tst == 3) {
+ if (clntaddnewcb != 2
+ || clntparsenewcb != 2
+ || srvaddnewcb != 2
+ || srvparsenewcb != 2)
+ goto end;
+ } else {
+ /*
+ * No Certificate message extensions in the resumption handshake,
+ * 2 NewSessionTickets in the initial handshake, 1 in the resumption
+ */
+ if (clntaddnewcb != 2
+ || clntparsenewcb != 8
+ || srvaddnewcb != 8
+ || srvparsenewcb != 2)
+ goto end;
+ }
+
+ testresult = 1;
+
+end:
+ SSL_SESSION_free(sess);
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx2);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ return testresult;
+}
+
+/*
+ * Test loading of serverinfo data in various formats. test_sslmessages actually
+ * tests to make sure the extensions appear in the handshake
+ */
+static int test_serverinfo(int tst)
+{
+ unsigned int version;
+ unsigned char *sibuf;
+ size_t sibuflen;
+ int ret, expected, testresult = 0;
+ SSL_CTX *ctx;
+
+ ctx = SSL_CTX_new_with_libctx(libctx, NULL, TLS_method());
+ if (!TEST_ptr(ctx))
+ goto end;
+
+ if ((tst & 0x01) == 0x01)
+ version = SSL_SERVERINFOV2;
+ else
+ version = SSL_SERVERINFOV1;
+
+ if ((tst & 0x02) == 0x02) {
+ sibuf = serverinfov2;
+ sibuflen = sizeof(serverinfov2);
+ expected = (version == SSL_SERVERINFOV2);
+ } else {
+ sibuf = serverinfov1;
+ sibuflen = sizeof(serverinfov1);
+ expected = (version == SSL_SERVERINFOV1);
+ }
+
+ if ((tst & 0x04) == 0x04) {
+ ret = SSL_CTX_use_serverinfo_ex(ctx, version, sibuf, sibuflen);
+ } else {
+ ret = SSL_CTX_use_serverinfo(ctx, sibuf, sibuflen);
+
+ /*
+ * The version variable is irrelevant in this case - it's what is in the
+ * buffer that matters
+ */
+ if ((tst & 0x02) == 0x02)
+ expected = 0;
+ else
+ expected = 1;
+ }
+
+ if (!TEST_true(ret == expected))
+ goto end;
+
+ testresult = 1;
+
+ end:
+ SSL_CTX_free(ctx);
+
+ return testresult;
+}
+
+/*
+ * Test that SSL_export_keying_material() 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.
+ */
+#define SMALL_LABEL_LEN 10
+#define LONG_LABEL_LEN 249
+static int test_export_key_mat(int tst)
+{
+ int testresult = 0;
+ SSL_CTX *cctx = NULL, *sctx = NULL, *sctx2 = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ const char label[LONG_LABEL_LEN + 1] = "test label";
+ const unsigned char context[] = "context";
+ const unsigned char *emptycontext = NULL;
+ unsigned char ckeymat1[80], ckeymat2[80], ckeymat3[80];
+ unsigned char skeymat1[80], skeymat2[80], skeymat3[80];
+ size_t labellen;
+ const int protocols[] = {
+ TLS1_VERSION,
+ TLS1_1_VERSION,
+ TLS1_2_VERSION,
+ TLS1_3_VERSION,
+ TLS1_3_VERSION,
+ TLS1_3_VERSION
+ };
+
+#ifdef OPENSSL_NO_TLS1
+ if (tst == 0)
+ return 1;
+#endif
+#ifdef OPENSSL_NO_TLS1_1
+ if (tst == 1)
+ return 1;
+#endif
+ if (is_fips && (tst == 0 || tst == 1))
+ return 1;
+#ifdef OPENSSL_NO_TLS1_2
+ if (tst == 2)
+ return 1;
+#endif
+#ifdef OPENSSL_NO_TLS1_3
+ if (tst >= 3)
+ return 1;
+#endif
+ if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
+ TLS_client_method(), TLS1_VERSION, 0,
+ &sctx, &cctx, cert, privkey)))
+ goto end;
+
+ OPENSSL_assert(tst >= 0 && (size_t)tst < OSSL_NELEM(protocols));
+ SSL_CTX_set_max_proto_version(cctx, protocols[tst]);
+ SSL_CTX_set_min_proto_version(cctx, protocols[tst]);
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL,
+ NULL))
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ if (tst == 5) {
+ /*
+ * TLSv1.3 imposes a maximum label len of 249 bytes. Check we fail if we
+ * go over that.
+ */
+ if (!TEST_int_le(SSL_export_keying_material(clientssl, ckeymat1,
+ sizeof(ckeymat1), label,
+ LONG_LABEL_LEN + 1, context,
+ sizeof(context) - 1, 1), 0))
+ goto end;
+
+ testresult = 1;
+ goto end;
+ } else if (tst == 4) {
+ labellen = LONG_LABEL_LEN;
+ } else {
+ labellen = SMALL_LABEL_LEN;
+ }
+
+ if (!TEST_int_eq(SSL_export_keying_material(clientssl, ckeymat1,
+ sizeof(ckeymat1), label,
+ labellen, context,
+ sizeof(context) - 1, 1), 1)
+ || !TEST_int_eq(SSL_export_keying_material(clientssl, ckeymat2,
+ sizeof(ckeymat2), label,
+ labellen,
+ emptycontext,
+ 0, 1), 1)
+ || !TEST_int_eq(SSL_export_keying_material(clientssl, ckeymat3,
+ sizeof(ckeymat3), label,
+ labellen,
+ NULL, 0, 0), 1)
+ || !TEST_int_eq(SSL_export_keying_material(serverssl, skeymat1,
+ sizeof(skeymat1), label,
+ labellen,
+ context,
+ sizeof(context) -1, 1),
+ 1)
+ || !TEST_int_eq(SSL_export_keying_material(serverssl, skeymat2,
+ sizeof(skeymat2), label,
+ labellen,
+ emptycontext,
+ 0, 1), 1)
+ || !TEST_int_eq(SSL_export_keying_material(serverssl, skeymat3,
+ sizeof(skeymat3), label,
+ labellen,
+ NULL, 0, 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))
+ /*
+ * Check that both sides created the same key material without a
+ * context.
+ */
+ || !TEST_mem_eq(ckeymat3, sizeof(ckeymat3), skeymat3,
+ sizeof(skeymat3))
+ /* Different contexts should produce different results */
+ || !TEST_mem_ne(ckeymat1, sizeof(ckeymat1), ckeymat2,
+ sizeof(ckeymat2)))
+ goto end;
+
+ /*
+ * Check that an empty context and no context produce different results in
+ * protocols less than TLSv1.3. In TLSv1.3 they should be the same.
+ */
+ if ((tst < 3 && !TEST_mem_ne(ckeymat2, sizeof(ckeymat2), ckeymat3,
+ sizeof(ckeymat3)))
+ || (tst >= 3 && !TEST_mem_eq(ckeymat2, sizeof(ckeymat2), ckeymat3,
+ sizeof(ckeymat3))))
+ goto end;
+
+ testresult = 1;
+
+ end:
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx2);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+
+ 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:
+ 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);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+
+#define NUM_KEY_UPDATE_MESSAGES 40
+/*
+ * Test KeyUpdate.
+ */
+static int test_key_update(void)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0, i, j;
+ char buf[20];
+ static char *mess = "A test message";
+
+ if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
+ TLS_client_method(),
+ TLS1_3_VERSION,
+ 0,
+ &sctx, &cctx, cert, privkey))
+ || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL))
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ for (j = 0; j < 2; j++) {
+ /* Send lots of KeyUpdate messages */
+ for (i = 0; i < NUM_KEY_UPDATE_MESSAGES; i++) {
+ if (!TEST_true(SSL_key_update(clientssl,
+ (j == 0)
+ ? SSL_KEY_UPDATE_NOT_REQUESTED
+ : SSL_KEY_UPDATE_REQUESTED))
+ || !TEST_true(SSL_do_handshake(clientssl)))
+ goto end;
+ }
+
+ /* Check that sending and receiving app data is ok */
+ if (!TEST_int_eq(SSL_write(clientssl, mess, strlen(mess)), strlen(mess))
+ || !TEST_int_eq(SSL_read(serverssl, buf, sizeof(buf)),
+ strlen(mess)))
+ goto end;
+
+ if (!TEST_int_eq(SSL_write(serverssl, mess, strlen(mess)), strlen(mess))
+ || !TEST_int_eq(SSL_read(clientssl, buf, sizeof(buf)),
+ strlen(mess)))
+ goto end;
+ }
+
+ testresult = 1;
+
+ end:
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+
+/*
+ * Test we can handle a KeyUpdate (update requested) message while write data
+ * is pending.
+ * Test 0: Client sends KeyUpdate while Server is writing
+ * Test 1: Server sends KeyUpdate while Client is writing
+ */
+static int test_key_update_in_write(int tst)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+ char buf[20];
+ static char *mess = "A test message";
+ BIO *bretry = BIO_new(bio_s_always_retry());
+ BIO *tmp = NULL;
+ SSL *peerupdate = NULL, *peerwrite = NULL;
+
+ if (!TEST_ptr(bretry)
+ || !TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
+ TLS_client_method(),
+ TLS1_3_VERSION,
+ 0,
+ &sctx, &cctx, cert, privkey))
+ || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL))
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ peerupdate = tst == 0 ? clientssl : serverssl;
+ peerwrite = tst == 0 ? serverssl : clientssl;
+
+ if (!TEST_true(SSL_key_update(peerupdate, SSL_KEY_UPDATE_REQUESTED))
+ || !TEST_true(SSL_do_handshake(peerupdate)))
+ goto end;
+
+ /* Swap the writing endpoint's write BIO to force a retry */
+ tmp = SSL_get_wbio(peerwrite);
+ if (!TEST_ptr(tmp) || !TEST_true(BIO_up_ref(tmp))) {
+ tmp = NULL;
+ goto end;
+ }
+ SSL_set0_wbio(peerwrite, bretry);
+ bretry = NULL;
+
+ /* Write data that we know will fail with SSL_ERROR_WANT_WRITE */
+ if (!TEST_int_eq(SSL_write(peerwrite, mess, strlen(mess)), -1)
+ || !TEST_int_eq(SSL_get_error(peerwrite, 0), SSL_ERROR_WANT_WRITE))
+ goto end;
+
+ /* Reinstate the original writing endpoint's write BIO */
+ SSL_set0_wbio(peerwrite, tmp);
+ tmp = NULL;
+
+ /* Now read some data - we will read the key update */
+ if (!TEST_int_eq(SSL_read(peerwrite, buf, sizeof(buf)), -1)
+ || !TEST_int_eq(SSL_get_error(peerwrite, 0), SSL_ERROR_WANT_READ))
+ goto end;
+
+ /*
+ * Complete the write we started previously and read it from the other
+ * endpoint
+ */
+ if (!TEST_int_eq(SSL_write(peerwrite, mess, strlen(mess)), strlen(mess))
+ || !TEST_int_eq(SSL_read(peerupdate, buf, sizeof(buf)), strlen(mess)))
+ goto end;
+
+ /* Write more data to ensure we send the KeyUpdate message back */
+ if (!TEST_int_eq(SSL_write(peerwrite, mess, strlen(mess)), strlen(mess))
+ || !TEST_int_eq(SSL_read(peerupdate, buf, sizeof(buf)), strlen(mess)))
+ goto end;
+
+ testresult = 1;
+
+ end:
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+ BIO_free(bretry);
+ BIO_free(tmp);
+
+ return testresult;
+}
+#endif /* OPENSSL_NO_TLS1_3 */
+
+static int test_ssl_clear(int idx)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int testresult = 0;
+
+#ifdef OPENSSL_NO_TLS1_2
+ if (idx == 1)
+ return 1;
+#endif
+
+ /* Create an initial connection */
+ if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
+ TLS_client_method(), TLS1_VERSION, 0,
+ &sctx, &cctx, cert, privkey))
+ || (idx == 1
+ && !TEST_true(SSL_CTX_set_max_proto_version(cctx,
+ TLS1_2_VERSION)))
+ || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl,
+ &clientssl, NULL, NULL))
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE)))
+ goto end;
+
+ SSL_shutdown(clientssl);
+ SSL_shutdown(serverssl);
+ SSL_free(serverssl);
+ serverssl = NULL;
+
+ /* Clear clientssl - we're going to reuse the object */
+ if (!TEST_true(SSL_clear(clientssl)))
+ goto end;
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL))
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE))
+ || !TEST_true(SSL_session_reused(clientssl)))
+ 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;
+}
+
+/* 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, pkt2, pkt3;
+ unsigned int MFL_code = 0, type = 0;
+
+ if (!TEST_uint_gt( len = BIO_get_mem_data( bio, (char **) &data ), 0 ) )
+ goto end;
+
+ memset(&pkt, 0, sizeof(pkt));
+ memset(&pkt2, 0, sizeof(pkt2));
+ memset(&pkt3, 0, sizeof(pkt3));
+
+ 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_with_libctx(libctx, NULL, 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(libctx, TLS_server_method(),
+ TLS_client_method(), TLS1_VERSION, 0,
+ &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;
+
+ SSL_CTX_set_post_handshake_auth(cctx, 1);
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL)))
+ goto end;
+
+ 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
+
+#if !defined(OPENSSL_NO_SRP) && !defined(OPENSSL_NO_TLS1_2)
+
+static SRP_VBASE *vbase = NULL;
+
+DEFINE_STACK_OF(SRP_user_pwd)
+
+static int ssl_srp_cb(SSL *s, int *ad, void *arg)
+{
+ int ret = SSL3_AL_FATAL;
+ char *username;
+ SRP_user_pwd *user = NULL;
+
+ username = SSL_get_srp_username(s);
+ if (username == NULL) {
+ *ad = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+
+ user = SRP_VBASE_get1_by_user(vbase, username);
+ if (user == NULL) {
+ *ad = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+
+ if (SSL_set_srp_server_param(s, user->N, user->g, user->s, user->v,
+ user->info) <= 0) {
+ *ad = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+
+ ret = 0;
+
+ err:
+ SRP_user_pwd_free(user);
+ return ret;
+}
+
+static int create_new_vfile(char *userid, char *password, const char *filename)
+{
+ char *gNid = NULL;
+ OPENSSL_STRING *row = OPENSSL_zalloc(sizeof(row) * (DB_NUMBER + 1));
+ TXT_DB *db = NULL;
+ int ret = 0;
+ BIO *out = NULL, *dummy = BIO_new_mem_buf("", 0);
+ size_t i;
+
+ if (!TEST_ptr(dummy) || !TEST_ptr(row))
+ goto end;
+
+ gNid = SRP_create_verifier_ex(userid, password, &row[DB_srpsalt],
+ &row[DB_srpverifier], NULL, NULL, libctx, NULL);
+ if (!TEST_ptr(gNid))
+ goto end;
+
+ /*
+ * The only way to create an empty TXT_DB is to provide a BIO with no data
+ * in it!
+ */
+ db = TXT_DB_read(dummy, DB_NUMBER);
+ if (!TEST_ptr(db))
+ goto end;
+
+ out = BIO_new_file(filename, "w");
+ if (!TEST_ptr(out))
+ goto end;
+
+ row[DB_srpid] = OPENSSL_strdup(userid);
+ row[DB_srptype] = OPENSSL_strdup("V");
+ row[DB_srpgN] = OPENSSL_strdup(gNid);
+
+ if (!TEST_ptr(row[DB_srpid])
+ || !TEST_ptr(row[DB_srptype])
+ || !TEST_ptr(row[DB_srpgN])
+ || !TEST_true(TXT_DB_insert(db, row)))
+ goto end;
+
+ row = NULL;
+
+ if (!TXT_DB_write(out, db))
+ goto end;
+
+ ret = 1;
+ end:
+ if (row != NULL) {
+ for (i = 0; i < DB_NUMBER; i++)
+ OPENSSL_free(row[i]);
+ }
+ OPENSSL_free(row);
+ BIO_free(dummy);
+ BIO_free(out);
+ TXT_DB_free(db);
+
+ return ret;
+}
+
+static int create_new_vbase(char *userid, char *password)
+{
+ BIGNUM *verifier = NULL, *salt = NULL;
+ const SRP_gN *lgN = NULL;
+ SRP_user_pwd *user_pwd = NULL;
+ int ret = 0;
+
+ lgN = SRP_get_default_gN(NULL);
+ if (!TEST_ptr(lgN))
+ goto end;
+
+ if (!TEST_true(SRP_create_verifier_BN_ex(userid, password, &salt, &verifier,
+ lgN->N, lgN->g, libctx, NULL)))
+ goto end;
+
+ user_pwd = OPENSSL_zalloc(sizeof(*user_pwd));
+ if (!TEST_ptr(user_pwd))
+ goto end;
+
+ user_pwd->N = lgN->N;
+ user_pwd->g = lgN->g;
+ user_pwd->id = OPENSSL_strdup(userid);
+ if (!TEST_ptr(user_pwd->id))
+ goto end;
+
+ user_pwd->v = verifier;
+ user_pwd->s = salt;
+ verifier = salt = NULL;
+
+ if (sk_SRP_user_pwd_insert(vbase->users_pwd, user_pwd, 0) == 0)
+ goto end;
+ user_pwd = NULL;
+
+ ret = 1;
+end:
+ SRP_user_pwd_free(user_pwd);
+ BN_free(salt);
+ BN_free(verifier);
+
+ return ret;
+}
+
+/*
+ * SRP tests
+ *
+ * Test 0: Simple successful SRP connection, new vbase
+ * Test 1: Connection failure due to bad password, new vbase
+ * Test 2: Simple successful SRP connection, vbase loaded from existing file
+ * Test 3: Connection failure due to bad password, vbase loaded from existing
+ * file
+ * Test 4: Simple successful SRP connection, vbase loaded from new file
+ * Test 5: Connection failure due to bad password, vbase loaded from new file
+ */
+static int test_srp(int tst)
+{
+ char *userid = "test", *password = "password", *tstsrpfile;
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ int ret, testresult = 0;
+
+ vbase = SRP_VBASE_new(NULL);
+ if (!TEST_ptr(vbase))
+ goto end;
+
+ if (tst == 0 || tst == 1) {
+ if (!TEST_true(create_new_vbase(userid, password)))
+ goto end;
+ } else {
+ if (tst == 4 || tst == 5) {
+ if (!TEST_true(create_new_vfile(userid, password, tmpfilename)))
+ goto end;
+ tstsrpfile = tmpfilename;
+ } else {
+ tstsrpfile = srpvfile;
+ }
+ if (!TEST_int_eq(SRP_VBASE_init(vbase, tstsrpfile), SRP_NO_ERROR))
+ goto end;
+ }
+
+ if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
+ TLS_client_method(), TLS1_VERSION, 0,
+ &sctx, &cctx, cert, privkey)))
+ goto end;
+
+ if (!TEST_int_gt(SSL_CTX_set_srp_username_callback(sctx, ssl_srp_cb), 0)
+ || !TEST_true(SSL_CTX_set_cipher_list(cctx, "SRP-AES-128-CBC-SHA"))
+ || !TEST_true(SSL_CTX_set_max_proto_version(sctx, TLS1_2_VERSION))
+ || !TEST_true(SSL_CTX_set_max_proto_version(cctx, TLS1_2_VERSION))
+ || !TEST_int_gt(SSL_CTX_set_srp_username(cctx, userid), 0))
+ goto end;
+
+ if (tst % 2 == 1) {
+ if (!TEST_int_gt(SSL_CTX_set_srp_password(cctx, "badpass"), 0))
+ goto end;
+ } else {
+ if (!TEST_int_gt(SSL_CTX_set_srp_password(cctx, password), 0))
+ goto end;
+ }
+
+ if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl,
+ NULL, NULL)))
+ goto end;
+
+ ret = create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE);
+ if (ret) {
+ if (!TEST_true(tst % 2 == 0))
+ goto end;
+ } else {
+ if (!TEST_true(tst % 2 == 1))
+ goto end;
+ }
+
+ testresult = 1;
+
+ end:
+ SRP_VBASE_free(vbase);
+ vbase = NULL;
+ SSL_free(serverssl);
+ SSL_free(clientssl);
+ SSL_CTX_free(sctx);
+ SSL_CTX_free(cctx);
+
+ return testresult;
+}
+#endif
+
+static int info_cb_failed = 0;
+static int info_cb_offset = 0;
+static int info_cb_this_state = -1;
+
+static struct info_cb_states_st {
+ int where;
+ const char *statestr;
+} info_cb_states[][60] = {
+ {
+ /* TLSv1.2 server followed by resumption */
+ {SSL_CB_HANDSHAKE_START, NULL}, {SSL_CB_LOOP, "PINIT "},
+ {SSL_CB_LOOP, "PINIT "}, {SSL_CB_LOOP, "TRCH"}, {SSL_CB_LOOP, "TWSH"},
+ {SSL_CB_LOOP, "TWSC"}, {SSL_CB_LOOP, "TWSKE"}, {SSL_CB_LOOP, "TWSD"},
+ {SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "TWSD"}, {SSL_CB_LOOP, "TRCKE"},
+ {SSL_CB_LOOP, "TRCCS"}, {SSL_CB_LOOP, "TRFIN"}, {SSL_CB_LOOP, "TWST"},
+ {SSL_CB_LOOP, "TWCCS"}, {SSL_CB_LOOP, "TWFIN"},
+ {SSL_CB_HANDSHAKE_DONE, NULL}, {SSL_CB_EXIT, NULL},
+ {SSL_CB_ALERT, NULL}, {SSL_CB_HANDSHAKE_START, NULL},
+ {SSL_CB_LOOP, "PINIT "}, {SSL_CB_LOOP, "PINIT "}, {SSL_CB_LOOP, "TRCH"},
+ {SSL_CB_LOOP, "TWSH"}, {SSL_CB_LOOP, "TWCCS"}, {SSL_CB_LOOP, "TWFIN"},
+ {SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "TWFIN"}, {SSL_CB_LOOP, "TRCCS"},
+ {SSL_CB_LOOP, "TRFIN"}, {SSL_CB_HANDSHAKE_DONE, NULL},
+ {SSL_CB_EXIT, NULL}, {0, NULL},
+ }, {
+ /* TLSv1.2 client followed by resumption */
+ {SSL_CB_HANDSHAKE_START, NULL}, {SSL_CB_LOOP, "PINIT "},
+ {SSL_CB_LOOP, "TWCH"}, {SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "TWCH"},
+ {SSL_CB_LOOP, "TRSH"}, {SSL_CB_LOOP, "TRSC"}, {SSL_CB_LOOP, "TRSKE"},
+ {SSL_CB_LOOP, "TRSD"}, {SSL_CB_LOOP, "TWCKE"}, {SSL_CB_LOOP, "TWCCS"},
+ {SSL_CB_LOOP, "TWFIN"}, {SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "TWFIN"},
+ {SSL_CB_LOOP, "TRST"}, {SSL_CB_LOOP, "TRCCS"}, {SSL_CB_LOOP, "TRFIN"},
+ {SSL_CB_HANDSHAKE_DONE, NULL}, {SSL_CB_EXIT, NULL}, {SSL_CB_ALERT, NULL},
+ {SSL_CB_HANDSHAKE_START, NULL}, {SSL_CB_LOOP, "PINIT "},
+ {SSL_CB_LOOP, "TWCH"}, {SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "TWCH"},
+ {SSL_CB_LOOP, "TRSH"}, {SSL_CB_LOOP, "TRCCS"}, {SSL_CB_LOOP, "TRFIN"},
+ {SSL_CB_LOOP, "TWCCS"}, {SSL_CB_LOOP, "TWFIN"},
+ {SSL_CB_HANDSHAKE_DONE, NULL}, {SSL_CB_EXIT, NULL}, {0, NULL},
+ }, {
+ /* TLSv1.3 server followed by resumption */
+ {SSL_CB_HANDSHAKE_START, NULL}, {SSL_CB_LOOP, "PINIT "},
+ {SSL_CB_LOOP, "PINIT "}, {SSL_CB_LOOP, "TRCH"}, {SSL_CB_LOOP, "TWSH"},
+ {SSL_CB_LOOP, "TWCCS"}, {SSL_CB_LOOP, "TWEE"}, {SSL_CB_LOOP, "TWSC"},
+ {SSL_CB_LOOP, "TRSCV"}, {SSL_CB_LOOP, "TWFIN"}, {SSL_CB_LOOP, "TED"},
+ {SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "TED"}, {SSL_CB_LOOP, "TRFIN"},
+ {SSL_CB_HANDSHAKE_DONE, NULL}, {SSL_CB_LOOP, "TWST"},
+ {SSL_CB_LOOP, "TWST"}, {SSL_CB_EXIT, NULL}, {SSL_CB_ALERT, NULL},
+ {SSL_CB_HANDSHAKE_START, NULL}, {SSL_CB_LOOP, "PINIT "},
+ {SSL_CB_LOOP, "PINIT "}, {SSL_CB_LOOP, "TRCH"}, {SSL_CB_LOOP, "TWSH"},
+ {SSL_CB_LOOP, "TWCCS"}, {SSL_CB_LOOP, "TWEE"}, {SSL_CB_LOOP, "TWFIN"},
+ {SSL_CB_LOOP, "TED"}, {SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "TED"},
+ {SSL_CB_LOOP, "TRFIN"}, {SSL_CB_HANDSHAKE_DONE, NULL},
+ {SSL_CB_LOOP, "TWST"}, {SSL_CB_EXIT, NULL}, {0, NULL},
+ }, {
+ /* TLSv1.3 client followed by resumption */
+ {SSL_CB_HANDSHAKE_START, NULL}, {SSL_CB_LOOP, "PINIT "},
+ {SSL_CB_LOOP, "TWCH"}, {SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "TWCH"},
+ {SSL_CB_LOOP, "TRSH"}, {SSL_CB_LOOP, "TREE"}, {SSL_CB_LOOP, "TRSC"},
+ {SSL_CB_LOOP, "TRSCV"}, {SSL_CB_LOOP, "TRFIN"}, {SSL_CB_LOOP, "TWCCS"},
+ {SSL_CB_LOOP, "TWFIN"}, {SSL_CB_HANDSHAKE_DONE, NULL},
+ {SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "SSLOK "}, {SSL_CB_LOOP, "SSLOK "},
+ {SSL_CB_LOOP, "TRST"}, {SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "SSLOK "},
+ {SSL_CB_LOOP, "SSLOK "}, {SSL_CB_LOOP, "TRST"}, {SSL_CB_EXIT, NULL},
+ {SSL_CB_ALERT, NULL}, {SSL_CB_HANDSHAKE_START, NULL},
+ {SSL_CB_LOOP, "PINIT "}, {SSL_CB_LOOP, "TWCH"}, {SSL_CB_EXIT, NULL},
+ {SSL_CB_LOOP, "TWCH"}, {SSL_CB_LOOP, "TRSH"}, {SSL_CB_LOOP, "TREE"},
+ {SSL_CB_LOOP, "TRFIN"}, {SSL_CB_LOOP, "TWCCS"}, {SSL_CB_LOOP, "TWFIN"},
+ {SSL_CB_HANDSHAKE_DONE, NULL}, {SSL_CB_EXIT, NULL},
+ {SSL_CB_LOOP, "SSLOK "}, {SSL_CB_LOOP, "SSLOK "}, {SSL_CB_LOOP, "TRST"},
+ {SSL_CB_EXIT, NULL}, {0, NULL},
+ }, {
+ /* TLSv1.3 server, early_data */
+ {SSL_CB_HANDSHAKE_START, NULL}, {SSL_CB_LOOP, "PINIT "},
+ {SSL_CB_LOOP, "PINIT "}, {SSL_CB_LOOP, "TRCH"}, {SSL_CB_LOOP, "TWSH"},
+ {SSL_CB_LOOP, "TWCCS"}, {SSL_CB_LOOP, "TWEE"}, {SSL_CB_LOOP, "TWFIN"},
+ {SSL_CB_HANDSHAKE_DONE, NULL}, {SSL_CB_EXIT, NULL},
+ {SSL_CB_HANDSHAKE_START, NULL}, {SSL_CB_LOOP, "TED"},
+ {SSL_CB_LOOP, "TED"}, {SSL_CB_LOOP, "TWEOED"}, {SSL_CB_LOOP, "TRFIN"},
+ {SSL_CB_HANDSHAKE_DONE, NULL}, {SSL_CB_LOOP, "TWST"},
+ {SSL_CB_EXIT, NULL}, {0, NULL},
+ }, {
+ /* TLSv1.3 client, early_data */
+ {SSL_CB_HANDSHAKE_START, NULL}, {SSL_CB_LOOP, "PINIT "},
+ {SSL_CB_LOOP, "TWCH"}, {SSL_CB_LOOP, "TWCCS"},
+ {SSL_CB_HANDSHAKE_DONE, NULL}, {SSL_CB_EXIT, NULL},
+ {SSL_CB_HANDSHAKE_START, NULL}, {SSL_CB_LOOP, "TED"},
+ {SSL_CB_LOOP, "TED"}, {SSL_CB_LOOP, "TRSH"}, {SSL_CB_LOOP, "TREE"},
+ {SSL_CB_LOOP, "TRFIN"}, {SSL_CB_LOOP, "TPEDE"}, {SSL_CB_LOOP, "TWEOED"},
+ {SSL_CB_LOOP, "TWFIN"}, {SSL_CB_HANDSHAKE_DONE, NULL},
+ {SSL_CB_EXIT, NULL}, {SSL_CB_LOOP, "SSLOK "}, {SSL_CB_LOOP, "SSLOK "},
+ {SSL_CB_LOOP, "TRST"}, {SSL_CB_EXIT, NULL}, {0, NULL},
+ }, {
+ {0, NULL},
+ }
+};
+
+static void sslapi_info_callback(const SSL *s, int where, int ret)
+{
+ struct info_cb_states_st *state = info_cb_states[info_cb_offset];
+
+ /* We do not ever expect a connection to fail in this test */
+ if (!TEST_false(ret == 0)) {
+ info_cb_failed = 1;
+ return;
+ }
+
+ /*
+ * Do some sanity checks. We never expect these things to happen in this
+ * test
+ */
+ if (!TEST_false((SSL_is_server(s) && (where & SSL_ST_CONNECT) != 0))
+ || !TEST_false(!SSL_is_server(s) && (where & SSL_ST_ACCEPT) != 0)
+ || !TEST_int_ne(state[++info_cb_this_state].where, 0)) {
+ info_cb_failed = 1;
+ return;
+ }
+
+ /* Now check we're in the right state */
+ if (!TEST_true((where & state[info_cb_this_state].where) != 0)) {
+ info_cb_failed = 1;
+ return;
+ }
+ if ((where & SSL_CB_LOOP) != 0
+ && !TEST_int_eq(strcmp(SSL_state_string(s),
+ state[info_cb_this_state].statestr), 0)) {
+ info_cb_failed = 1;
+ return;
+ }
+
+ /*
+ * Check that, if we've got SSL_CB_HANDSHAKE_DONE we are not in init
+ */
+ if ((where & SSL_CB_HANDSHAKE_DONE)
+ && SSL_in_init((SSL *)s) != 0) {
+ info_cb_failed = 1;
+ return;
+ }
+}
+
+/*
+ * Test the info callback gets called when we expect it to.
+ *
+ * Test 0: TLSv1.2, server
+ * Test 1: TLSv1.2, client
+ * Test 2: TLSv1.3, server
+ * Test 3: TLSv1.3, client
+ * Test 4: TLSv1.3, server, early_data
+ * Test 5: TLSv1.3, client, early_data
+ */
+static int test_info_callback(int tst)
+{
+ SSL_CTX *cctx = NULL, *sctx = NULL;
+ SSL *clientssl = NULL, *serverssl = NULL;
+ SSL_SESSION *clntsess = NULL;
+ int testresult = 0;
+ int tlsvers;
+
+ if (tst < 2) {
+/* We need either ECDHE or DHE for the TLSv1.2 test to work */
+#if !defined(OPENSSL_NO_TLS1_2) && (!defined(OPENSSL_NO_EC) \
+ || !defined(OPENSSL_NO_DH))
+ tlsvers = TLS1_2_VERSION;
+#else
+ return 1;
+#endif
+ } else {
+#ifndef OPENSSL_NO_TLS1_3
+ tlsvers = TLS1_3_VERSION;
+#else
+ return 1;
+#endif
+ }
+
+ /* Reset globals */
+ info_cb_failed = 0;
+ info_cb_this_state = -1;
+ info_cb_offset = tst;
+
+#ifndef OPENSSL_NO_TLS1_3
+ if (tst >= 4) {
+ SSL_SESSION *sess = NULL;
+ size_t written, readbytes;
+ unsigned char buf[80];
+
+ /* early_data tests */
+ if (!TEST_true(setupearly_data_test(&cctx, &sctx, &clientssl,
+ &serverssl, &sess, 0)))
+ goto end;
+
+ /* We don't actually need this reference */
+ SSL_SESSION_free(sess);
+
+ SSL_set_info_callback((tst % 2) == 0 ? serverssl : clientssl,
+ sslapi_info_callback);
+
+ /* Write and read some early data and then complete the connection */
+ if (!TEST_true(SSL_write_early_data(clientssl, MSG1, strlen(MSG1),
+ &written))
+ || !TEST_size_t_eq(written, strlen(MSG1))
+ || !TEST_int_eq(SSL_read_early_data(serverssl, buf,
+ sizeof(buf), &readbytes),
+ SSL_READ_EARLY_DATA_SUCCESS)
+ || !TEST_mem_eq(MSG1, readbytes, buf, strlen(MSG1))
+ || !TEST_int_eq(SSL_get_early_data_status(serverssl),
+ SSL_EARLY_DATA_ACCEPTED)
+ || !TEST_true(create_ssl_connection(serverssl, clientssl,
+ SSL_ERROR_NONE))
+ || !TEST_false(info_cb_failed))
+ goto end;
+
+ testresult = 1;
+ goto end;