/*
* Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
#include <openssl/srp.h>
#endif
-#include "../ssl/ssl_locl.h"
+#include "../ssl/ssl_local.h"
#include "internal/sockets.h"
#include "internal/nelem.h"
#include "handshake_helper.h"
#include "testutil.h"
-HANDSHAKE_RESULT *HANDSHAKE_RESULT_new()
+#if !defined(OPENSSL_NO_SCTP) && !defined(OPENSSL_NO_SOCK)
+#include <netinet/sctp.h>
+#endif
+
+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. */
*/
return INTERNAL_ERROR;
}
+ break;
case PEER_RETRY:
return HANDSHAKE_RETRY;
#if !defined(OPENSSL_NO_SCTP) && !defined(OPENSSL_NO_SOCK)
static int set_sock_as_sctp(int sock)
{
+ struct sctp_assocparams assocparams;
+ struct sctp_rtoinfo rto_info;
+ BIO *tmpbio;
+
+ /*
+ * To allow tests to fail fast (within a second or so), reduce the
+ * retransmission timeouts and the number of retransmissions.
+ */
+ memset(&rto_info, 0, sizeof(struct sctp_rtoinfo));
+ rto_info.srto_initial = 100;
+ rto_info.srto_max = 200;
+ rto_info.srto_min = 50;
+ (void)setsockopt(sock, IPPROTO_SCTP, SCTP_RTOINFO,
+ (const void *)&rto_info, sizeof(struct sctp_rtoinfo));
+ memset(&assocparams, 0, sizeof(struct sctp_assocparams));
+ assocparams.sasoc_asocmaxrxt = 2;
+ (void)setsockopt(sock, IPPROTO_SCTP, SCTP_ASSOCINFO,
+ (const void *)&assocparams,
+ sizeof(struct sctp_assocparams));
+
/*
* For SCTP we have to set various options on the socket prior to
* connecting. This is done automatically by BIO_new_dgram_sctp().
* We don't actually need the created BIO though so we free it again
* immediately.
*/
- BIO *tmpbio = BIO_new_dgram_sctp(sock, BIO_NOCLOSE);
+ tmpbio = BIO_new_dgram_sctp(sock, BIO_NOCLOSE);
if (tmpbio == NULL)
return 0;
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;
return NULL;
}
+#if !defined(OPENSSL_NO_SCTP) && !defined(OPENSSL_NO_SOCK)
+ if (test_ctx->enable_client_sctp_label_bug)
+ SSL_CTX_set_mode(client_ctx, SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG);
+ if (test_ctx->enable_server_sctp_label_bug)
+ SSL_CTX_set_mode(server_ctx, SSL_MODE_DTLS_SCTP_LABEL_LENGTH_BUG);
+#endif
+
/* Setup SSL and buffers; additional configuration happens below. */
if (!create_peer(&server, server_ctx)) {
TEST_note("creating server context");
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)) {
+ if (SSL_get_peer_tmp_key(client.ssl, &tmp_key)) {
ret->tmp_key_type = pkey_type(tmp_key);
EVP_PKEY_free(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;
}