#include "handshake_helper.h"
#include "testutil.h"
-HANDSHAKE_RESULT *HANDSHAKE_RESULT_new()
+HANDSHAKE_RESULT *HANDSHAKE_RESULT_new(void)
{
HANDSHAKE_RESULT *ret;
OPENSSL_free(result->server_npn_negotiated);
OPENSSL_free(result->client_alpn_negotiated);
OPENSSL_free(result->server_alpn_negotiated);
+ OPENSSL_free(result->result_session_ticket_app_data);
sk_X509_NAME_pop_free(result->server_ca_names, X509_NAME_free);
sk_X509_NAME_pop_free(result->client_ca_names, X509_NAME_free);
OPENSSL_free(result->cipher);
size_t alpn_protocols_len;
char *srp_user;
char *srp_password;
+ char *session_ticket_app_data;
} CTX_DATA;
/* |ctx_data| itself is stack-allocated. */
ctx_data->srp_user = NULL;
OPENSSL_free(ctx_data->srp_password);
ctx_data->srp_password = NULL;
+ OPENSSL_free(ctx_data->session_ticket_app_data);
+ ctx_data->session_ticket_app_data = NULL;
}
static int ex_data_idx;
}
#endif /* !OPENSSL_NO_SRP */
+static int generate_session_ticket_cb(SSL *s, void *arg)
+{
+ CTX_DATA *server_ctx_data = arg;
+ SSL_SESSION *ss = SSL_get_session(s);
+ char *app_data = server_ctx_data->session_ticket_app_data;
+
+ if (ss == NULL || app_data == NULL)
+ return 0;
+
+ return SSL_SESSION_set1_ticket_appdata(ss, app_data, strlen(app_data));
+}
+
+static int decrypt_session_ticket_cb(SSL *s, SSL_SESSION *ss,
+ const unsigned char *keyname,
+ size_t keyname_len,
+ SSL_TICKET_STATUS status,
+ void *arg)
+{
+ switch (status) {
+ case SSL_TICKET_EMPTY:
+ case SSL_TICKET_NO_DECRYPT:
+ return SSL_TICKET_RETURN_IGNORE_RENEW;
+ case SSL_TICKET_SUCCESS:
+ return SSL_TICKET_RETURN_USE;
+ case SSL_TICKET_SUCCESS_RENEW:
+ return SSL_TICKET_RETURN_USE_RENEW;
+ default:
+ break;
+ }
+ return SSL_TICKET_RETURN_ABORT;
+}
+
/*
* Configure callbacks and other properties that can't be set directly
* in the server/client CONF.
OPENSSL_free(alpn_protos);
}
+ if (extra->server.session_ticket_app_data != NULL) {
+ server_ctx_data->session_ticket_app_data =
+ OPENSSL_strdup(extra->server.session_ticket_app_data);
+ SSL_CTX_set_session_ticket_cb(server_ctx, generate_session_ticket_cb,
+ decrypt_session_ticket_cb, server_ctx_data);
+ }
+ if (extra->server2.session_ticket_app_data != NULL) {
+ if (!TEST_ptr(server2_ctx))
+ goto err;
+ server2_ctx_data->session_ticket_app_data =
+ OPENSSL_strdup(extra->server2.session_ticket_app_data);
+ SSL_CTX_set_session_ticket_cb(server2_ctx, NULL,
+ decrypt_session_ticket_cb, server2_ctx_data);
+ }
+
/*
* Use fixed session ticket keys so that we can decrypt a ticket created with
* one CTX in another CTX. Don't address server2 for the moment.
if (extra->client.servername != SSL_TEST_SERVERNAME_NONE)
SSL_set_tlsext_host_name(client,
ssl_servername_name(extra->client.servername));
- if (extra->client.force_pha)
- SSL_force_post_handshake_auth(client);
+ if (extra->client.enable_pha)
+ SSL_set_post_handshake_auth(client, 1);
}
/* The status for each connection phase. */
static HANDSHAKE_RESULT *do_handshake_internal(
SSL_CTX *server_ctx, SSL_CTX *server2_ctx, SSL_CTX *client_ctx,
const SSL_TEST_CTX *test_ctx, const SSL_TEST_EXTRA_CONF *extra,
- SSL_SESSION *session_in, SSL_SESSION **session_out)
+ SSL_SESSION *session_in, SSL_SESSION *serv_sess_in,
+ SSL_SESSION **session_out, SSL_SESSION **serv_sess_out)
{
PEER server, client;
BIO *client_to_server = NULL, *server_to_client = NULL;
HANDSHAKE_EX_DATA server_ex_data, client_ex_data;
CTX_DATA client_ctx_data, server_ctx_data, server2_ctx_data;
HANDSHAKE_RESULT *ret = HANDSHAKE_RESULT_new();
- int client_turn = 1, client_turn_count = 0;
+ int client_turn = 1, client_turn_count = 0, client_wait_count = 0;
connect_phase_t phase = HANDSHAKE;
handshake_status_t status = HANDSHAKE_RETRY;
const unsigned char* tick = NULL;
configure_handshake_ssl(server.ssl, client.ssl, extra);
if (session_in != NULL) {
+ SSL_SESSION_get_id(serv_sess_in, &sess_id_len);
/* In case we're testing resumption without tickets. */
- if (!TEST_true(SSL_CTX_add_session(server_ctx, session_in))
+ if ((sess_id_len > 0
+ && !TEST_true(SSL_CTX_add_session(server_ctx,
+ serv_sess_in)))
|| !TEST_true(SSL_set_session(client.ssl, session_in)))
goto err;
+ sess_id_len = 0;
}
ret->result = SSL_TEST_INTERNAL_ERROR;
ret->result = SSL_TEST_INTERNAL_ERROR;
goto err;
}
-
- /* Continue. */
- client_turn ^= 1;
+ if (client_turn && server.status == PEER_SUCCESS) {
+ /*
+ * The server may finish before the client because the
+ * client spends some turns processing NewSessionTickets.
+ */
+ if (client_wait_count++ >= 2) {
+ ret->result = SSL_TEST_INTERNAL_ERROR;
+ goto err;
+ }
+ } else {
+ /* Continue. */
+ client_turn ^= 1;
+ }
}
break;
}
SSL_get0_alpn_selected(server.ssl, &proto, &proto_len);
ret->server_alpn_negotiated = dup_str(proto, proto_len);
+ if ((sess = SSL_get0_session(server.ssl)) != NULL) {
+ SSL_SESSION_get0_ticket_appdata(sess, (void**)&tick, &tick_len);
+ ret->result_session_ticket_app_data = OPENSSL_strndup((const char*)tick, tick_len);
+ }
+
ret->client_resumed = SSL_session_reused(client.ssl);
ret->server_resumed = SSL_session_reused(server.ssl);
if (session_out != NULL)
*session_out = SSL_get1_session(client.ssl);
+ if (serv_sess_out != NULL) {
+ SSL_SESSION *tmp = SSL_get_session(server.ssl);
+
+ /*
+ * We create a fresh copy that is not in the server session ctx linked
+ * list.
+ */
+ if (tmp != NULL)
+ *serv_sess_out = SSL_SESSION_dup(tmp);
+ }
if (SSL_get_server_tmp_key(client.ssl, &tmp_key)) {
ret->tmp_key_type = pkey_type(tmp_key);
const SSL_TEST_CTX *test_ctx)
{
HANDSHAKE_RESULT *result;
- SSL_SESSION *session = NULL;
+ SSL_SESSION *session = NULL, *serv_sess = NULL;
result = do_handshake_internal(server_ctx, server2_ctx, client_ctx,
test_ctx, &test_ctx->extra,
- NULL, &session);
+ NULL, NULL, &session, &serv_sess);
if (result == NULL
|| test_ctx->handshake_mode != SSL_TEST_HANDSHAKE_RESUME
|| result->result == SSL_TEST_INTERNAL_ERROR)
/* We don't support SNI on second handshake yet, so server2_ctx is NULL. */
result = do_handshake_internal(resume_server_ctx, NULL, resume_client_ctx,
test_ctx, &test_ctx->resume_extra,
- session, NULL);
+ session, serv_sess, NULL, NULL);
end:
SSL_SESSION_free(session);
+ SSL_SESSION_free(serv_sess);
return result;
}