/*
- * 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
#include <openssl/srp.h>
#endif
-#ifndef OPENSSL_NO_SOCK
-# define USE_SOCKETS
-# include <internal/nelem.h>
-#endif
-
+#include "../ssl/ssl_locl.h"
+#include "internal/sockets.h"
+#include "internal/nelem.h"
#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);
OPENSSL_free(result);
}
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;
}
}
-static int early_select_server_ctx(SSL *s, void *arg, int ignore)
+static int client_hello_select_server_ctx(SSL *s, void *arg, int ignore)
{
const char *servername;
const unsigned char *p;
* The server_name extension was given too much extensibility when it
* was written, so parsing the normal case is a bit complex.
*/
- if (!SSL_early_get0_ext(s, TLSEXT_TYPE_server_name, &p, &remaining) ||
+ if (!SSL_client_hello_get0_ext(s, TLSEXT_TYPE_server_name, &p,
+ &remaining) ||
remaining <= 2)
return 0;
/* Extract the length of the supplied list of names. */
- len = (*(p++) << 1);
+ len = (*(p++) << 8);
len += *(p++);
if (len + 2 != remaining)
return 0;
/* Now we can finally pull out the byte array with the actual hostname. */
if (remaining <= 2)
return 0;
- len = (*(p++) << 1);
+ len = (*(p++) << 8);
len += *(p++);
if (len + 2 > remaining)
return 0;
return select_server_ctx(s, arg, 0);
}
-static int early_ignore_cb(SSL *s, int *al, void *arg)
+static int client_hello_ignore_cb(SSL *s, int *al, void *arg)
{
- if (!early_select_server_ctx(s, arg, 1)) {
+ if (!client_hello_select_server_ctx(s, arg, 1)) {
*al = SSL_AD_UNRECOGNIZED_NAME;
- return 0;
+ return SSL_CLIENT_HELLO_ERROR;
}
- return 1;
+ return SSL_CLIENT_HELLO_SUCCESS;
}
-static int early_reject_cb(SSL *s, int *al, void *arg)
+static int client_hello_reject_cb(SSL *s, int *al, void *arg)
{
- if (!early_select_server_ctx(s, arg, 0)) {
+ if (!client_hello_select_server_ctx(s, arg, 0)) {
*al = SSL_AD_UNRECOGNIZED_NAME;
- return 0;
+ return SSL_CLIENT_HELLO_ERROR;
}
- return 1;
+ return SSL_CLIENT_HELLO_SUCCESS;
}
-static int early_nov12_cb(SSL *s, int *al, void *arg)
+static int client_hello_nov12_cb(SSL *s, int *al, void *arg)
{
int ret;
unsigned int v;
const unsigned char *p;
- v = SSL_early_get0_legacy_version(s);
+ v = SSL_client_hello_get0_legacy_version(s);
if (v > TLS1_2_VERSION || v < SSL3_VERSION) {
*al = SSL_AD_PROTOCOL_VERSION;
- return 0;
+ return SSL_CLIENT_HELLO_ERROR;
}
- (void)SSL_early_get0_session_id(s, &p);
+ (void)SSL_client_hello_get0_session_id(s, &p);
if (p == NULL ||
- SSL_early_get0_random(s, &p) == 0 ||
- SSL_early_get0_ciphers(s, &p) == 0 ||
- SSL_early_get0_compression_methods(s, &p) == 0) {
+ SSL_client_hello_get0_random(s, &p) == 0 ||
+ SSL_client_hello_get0_ciphers(s, &p) == 0 ||
+ SSL_client_hello_get0_compression_methods(s, &p) == 0) {
*al = SSL_AD_INTERNAL_ERROR;
- return 0;
+ return SSL_CLIENT_HELLO_ERROR;
}
- ret = early_select_server_ctx(s, arg, 0);
+ ret = client_hello_select_server_ctx(s, arg, 0);
SSL_set_max_proto_version(s, TLS1_1_VERSION);
- if (!ret)
+ if (!ret) {
*al = SSL_AD_UNRECOGNIZED_NAME;
- return ret;
+ return SSL_CLIENT_HELLO_ERROR;
+ }
+ return SSL_CLIENT_HELLO_SUCCESS;
}
static unsigned char dummy_ocsp_resp_good_val = 0xff;
if ((*out)[i] == ',') {
if (!TEST_int_gt(i - 1, prefix))
goto err;
- (*out)[prefix] = i - 1 - prefix;
+ (*out)[prefix] = (unsigned char)(i - 1 - prefix);
prefix = i;
}
i++;
}
if (!TEST_int_gt(len, prefix))
goto err;
- (*out)[prefix] = len - prefix;
+ (*out)[prefix] = (unsigned char)(len - prefix);
return 1;
err:
}
#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 SSL_TICKET_RETURN decrypt_session_ticket_cb(SSL *s, SSL_SESSION *ss,
+ const unsigned char *keyname,
+ size_t keyname_len,
+ SSL_TICKET_RETURN retv, void *arg)
+{
+ return retv;
+}
+
/*
* Configure callbacks and other properties that can't be set directly
* in the server/client CONF.
break;
}
+ switch (extra->client.max_fragment_len_mode) {
+ case TLSEXT_max_fragment_length_512:
+ case TLSEXT_max_fragment_length_1024:
+ case TLSEXT_max_fragment_length_2048:
+ case TLSEXT_max_fragment_length_4096:
+ case TLSEXT_max_fragment_length_DISABLED:
+ SSL_CTX_set_tlsext_max_fragment_length(
+ client_ctx, extra->client.max_fragment_len_mode);
+ break;
+ }
+
/*
* Link the two contexts for SNI purposes.
- * Also do early callbacks here, as setting both early and SNI is bad.
+ * Also do ClientHello callbacks here, as setting both ClientHello and SNI
+ * is bad.
*/
switch (extra->server.servername_callback) {
case SSL_TEST_SERVERNAME_IGNORE_MISMATCH:
break;
case SSL_TEST_SERVERNAME_CB_NONE:
break;
- case SSL_TEST_SERVERNAME_EARLY_IGNORE_MISMATCH:
- SSL_CTX_set_early_cb(server_ctx, early_ignore_cb, server2_ctx);
+ case SSL_TEST_SERVERNAME_CLIENT_HELLO_IGNORE_MISMATCH:
+ SSL_CTX_set_client_hello_cb(server_ctx, client_hello_ignore_cb, server2_ctx);
break;
- case SSL_TEST_SERVERNAME_EARLY_REJECT_MISMATCH:
- SSL_CTX_set_early_cb(server_ctx, early_reject_cb, server2_ctx);
+ case SSL_TEST_SERVERNAME_CLIENT_HELLO_REJECT_MISMATCH:
+ SSL_CTX_set_client_hello_cb(server_ctx, client_hello_reject_cb, server2_ctx);
break;
- case SSL_TEST_SERVERNAME_EARLY_NO_V12:
- SSL_CTX_set_early_cb(server_ctx, early_nov12_cb, server2_ctx);
+ case SSL_TEST_SERVERNAME_CLIENT_HELLO_NO_V12:
+ SSL_CTX_set_client_hello_cb(server_ctx, client_hello_nov12_cb, server2_ctx);
}
if (extra->server.cert_status != SSL_TEST_CERT_STATUS_NONE) {
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);
}
/* The status for each connection phase. */
|| test_ctx->handshake_mode
== SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER
|| test_ctx->handshake_mode
- == SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT)) {
+ == SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT
+ || test_ctx->handshake_mode
+ == SSL_TEST_HANDSHAKE_POST_HANDSHAKE_AUTH)) {
peer->status = PEER_TEST_FAILURE;
return;
}
if (peer->status != PEER_SUCCESS)
peer->status = PEER_ERROR;
return;
+ } else if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_POST_HANDSHAKE_AUTH) {
+ if (SSL_is_server(peer->ssl)) {
+ /* Make the server believe it's received the extension */
+ if (test_ctx->extra.server.force_pha)
+ peer->ssl->post_handshake_auth = SSL_PHA_EXT_RECEIVED;
+ ret = SSL_verify_client_post_handshake(peer->ssl);
+ if (!ret) {
+ peer->status = PEER_ERROR;
+ return;
+ }
+ }
+ do_handshake_step(peer);
+ /*
+ * This is a one step handshake. We shouldn't get anything other than
+ * PEER_SUCCESS
+ */
+ if (peer->status != PEER_SUCCESS)
+ peer->status = PEER_ERROR;
+ return;
}
/*
CONNECTION_DONE
} connect_phase_t;
+
+static int renegotiate_op(const SSL_TEST_CTX *test_ctx)
+{
+ switch (test_ctx->handshake_mode) {
+ case SSL_TEST_HANDSHAKE_RENEG_SERVER:
+ case SSL_TEST_HANDSHAKE_RENEG_CLIENT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+static int post_handshake_op(const SSL_TEST_CTX *test_ctx)
+{
+ switch (test_ctx->handshake_mode) {
+ case SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT:
+ case SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER:
+ case SSL_TEST_HANDSHAKE_POST_HANDSHAKE_AUTH:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
static connect_phase_t next_phase(const SSL_TEST_CTX *test_ctx,
connect_phase_t phase)
{
switch (phase) {
case HANDSHAKE:
- if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_SERVER
- || test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT
- || test_ctx->handshake_mode
- == SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT
- || test_ctx->handshake_mode
- == SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER)
+ if (renegotiate_op(test_ctx) || post_handshake_op(test_ctx))
return RENEG_APPLICATION_DATA;
return APPLICATION_DATA;
case RENEG_APPLICATION_DATA:
return RENEG_SETUP;
case RENEG_SETUP:
- if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_KEY_UPDATE_SERVER
- || test_ctx->handshake_mode
- == SSL_TEST_HANDSHAKE_KEY_UPDATE_CLIENT)
+ if (post_handshake_op(test_ctx))
return APPLICATION_DATA;
return RENEG_HANDSHAKE;
case RENEG_HANDSHAKE:
*/
return INTERNAL_ERROR;
}
+ break;
case PEER_RETRY:
return HANDSHAKE_RETRY;
handshake_status_t status = HANDSHAKE_RETRY;
const unsigned char* tick = NULL;
size_t tick_len = 0;
+ const unsigned char* sess_id = NULL;
+ unsigned int sess_id_len = 0;
SSL_SESSION* sess = NULL;
const unsigned char *proto = NULL;
/* API dictates unsigned int rather than size_t. */
EVP_PKEY *tmp_key;
const STACK_OF(X509_NAME) *names;
time_t start;
+ const char* cipher;
if (ret == NULL)
return NULL;
ret->server_protocol = SSL_version(server.ssl);
ret->client_protocol = SSL_version(client.ssl);
ret->servername = server_ex_data.servername;
- if ((sess = SSL_get0_session(client.ssl)) != NULL)
+ if ((sess = SSL_get0_session(client.ssl)) != NULL) {
SSL_SESSION_get0_ticket(sess, &tick, &tick_len);
+ sess_id = SSL_SESSION_get_id(sess, &sess_id_len);
+ }
if (tick == NULL || tick_len == 0)
ret->session_ticket = SSL_TEST_SESSION_TICKET_NO;
else
ret->compression = (SSL_get_current_compression(client.ssl) == NULL)
? SSL_TEST_COMPRESSION_NO
: SSL_TEST_COMPRESSION_YES;
+ if (sess_id == NULL || sess_id_len == 0)
+ ret->session_id = SSL_TEST_SESSION_ID_NO;
+ else
+ ret->session_id = SSL_TEST_SESSION_ID_YES;
ret->session_ticket_do_not_call = server_ex_data.session_ticket_do_not_call;
#ifndef OPENSSL_NO_NEXTPROTONEG
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);
+ cipher = SSL_CIPHER_get_name(SSL_get_current_cipher(client.ssl));
+ ret->cipher = dup_str((const unsigned char*)cipher, strlen(cipher));
+
if (session_out != NULL)
*session_out = SSL_get1_session(client.ssl);