parse_protos(extra->server.npn_protocols,
&server_ctx_data->npn_protocols,
&server_ctx_data->npn_protocols_len);
- SSL_CTX_set_next_protos_advertised_cb(server_ctx, server_npn_cb,
- server_ctx_data);
+ SSL_CTX_set_npn_advertised_cb(server_ctx, server_npn_cb,
+ server_ctx_data);
}
if (extra->server2.npn_protocols != NULL) {
parse_protos(extra->server2.npn_protocols,
&server2_ctx_data->npn_protocols,
&server2_ctx_data->npn_protocols_len);
TEST_check(server2_ctx != NULL);
- SSL_CTX_set_next_protos_advertised_cb(server2_ctx, server_npn_cb,
- server2_ctx_data);
+ SSL_CTX_set_npn_advertised_cb(server2_ctx, server_npn_cb,
+ server2_ctx_data);
}
if (extra->client.npn_protocols != NULL) {
parse_protos(extra->client.npn_protocols,
}
}
-static void do_reneg_setup_step(PEER *peer)
+static void do_reneg_setup_step(const SSL_TEST_CTX *test_ctx, PEER *peer)
{
int ret;
char buf;
TEST_check(peer->status == PEER_RETRY);
- /* We only support client initiated reneg at the moment */
- /* TODO: server side */
- if (!SSL_is_server(peer->ssl)) {
- ret = SSL_renegotiate(peer->ssl);
- if (!ret) {
- peer->status = PEER_ERROR;
- return;
- }
- do_handshake_step(peer);
+ TEST_check(test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_SERVER
+ || test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT);
+
+ /* Check if we are the peer that is going to initiate */
+ if ((test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_SERVER
+ && SSL_is_server(peer->ssl))
+ || (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT
+ && !SSL_is_server(peer->ssl))) {
/*
- * If status is PEER_RETRY it means we're waiting on the server to
- * continue the handshake. As far as setting up the renegotiation is
- * concerned that is a success. The next step will continue the
- * handshake to its conclusion.
+ * If we already asked for a renegotiation then fall through to the
+ * SSL_read() below.
*/
- if (peer->status == PEER_RETRY)
- peer->status = PEER_SUCCESS;
- return;
+ if (!SSL_renegotiate_pending(peer->ssl)) {
+ /*
+ * If we are the client we will always attempt to resume the
+ * session. The server may or may not resume dependant on the
+ * setting of SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+ */
+ if (SSL_is_server(peer->ssl)) {
+ ret = SSL_renegotiate(peer->ssl);
+ } else {
+ if (test_ctx->extra.client.reneg_ciphers != NULL) {
+ if (!SSL_set_cipher_list(peer->ssl,
+ test_ctx->extra.client.reneg_ciphers)) {
+ peer->status = PEER_ERROR;
+ return;
+ }
+ ret = SSL_renegotiate(peer->ssl);
+ } else {
+ ret = SSL_renegotiate_abbreviated(peer->ssl);
+ }
+ }
+ if (!ret) {
+ peer->status = PEER_ERROR;
+ return;
+ }
+ do_handshake_step(peer);
+ /*
+ * If status is PEER_RETRY it means we're waiting on the peer to
+ * continue the handshake. As far as setting up the renegotiation is
+ * concerned that is a success. The next step will continue the
+ * handshake to its conclusion.
+ *
+ * If status is PEER_SUCCESS then we are the server and we have
+ * successfully sent the HelloRequest. We need to continue to wait
+ * until the handshake arrives from the client.
+ */
+ if (peer->status == PEER_RETRY)
+ peer->status = PEER_SUCCESS;
+ else if (peer->status == PEER_SUCCESS)
+ peer->status = PEER_RETRY;
+ return;
+ }
}
/*
*/
ret = SSL_read(peer->ssl, &buf, sizeof(buf));
if (ret >= 0) {
- /* We're not actually expecting data - we're expect a reneg to start */
+ /*
+ * We're not actually expecting data - we're expecting a reneg to
+ * start
+ */
peer->status = PEER_ERROR;
return;
} else {
int error = SSL_get_error(peer->ssl, ret);
- if (error != SSL_ERROR_WANT_READ || !SSL_in_init(peer->ssl)) {
+ if (error != SSL_ERROR_WANT_READ) {
peer->status = PEER_ERROR;
return;
}
+ /* If we're no in init yet then we're not done with setup yet */
+ if (!SSL_in_init(peer->ssl))
+ return;
}
peer->status = PEER_SUCCESS;
{
switch (phase) {
case HANDSHAKE:
- if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEGOTIATE)
+ if (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_SERVER
+ || test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT)
return RENEG_APPLICATION_DATA;
return APPLICATION_DATA;
case RENEG_APPLICATION_DATA:
return -1;
}
-static void do_connect_step(PEER *peer, connect_phase_t phase)
+static void do_connect_step(const SSL_TEST_CTX *test_ctx, PEER *peer,
+ connect_phase_t phase)
{
switch (phase) {
case HANDSHAKE:
do_app_data_step(peer);
break;
case RENEG_SETUP:
- do_reneg_setup_step(peer);
+ do_reneg_setup_step(test_ctx, peer);
break;
case RENEG_HANDSHAKE:
do_handshake_step(peer);
{
char *ret;
- if(len == 0)
+ if (len == 0)
return NULL;
/* Assert that the string does not contain NUL-bytes. */
return ret;
}
+static int pkey_type(EVP_PKEY *pkey)
+{
+ int nid = EVP_PKEY_id(pkey);
+
+#ifndef OPENSSL_NO_EC
+ if (nid == EVP_PKEY_EC) {
+ const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
+ return EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
+ }
+#endif
+ return nid;
+}
+
+static int peer_pkey_type(SSL *s)
+{
+ X509 *x = SSL_get_peer_certificate(s);
+
+ if (x != NULL) {
+ int nid = pkey_type(X509_get0_pubkey(x));
+
+ X509_free(x);
+ return nid;
+ }
+ return NID_undef;
+}
+
/*
* Note that |extra| points to the correct client/server configuration
* within |test_ctx|. When configuring the handshake, general mode settings
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;
+ int client_turn = 1, client_turn_count = 0;
connect_phase_t phase = HANDSHAKE;
handshake_status_t status = HANDSHAKE_RETRY;
const unsigned char* tick = NULL;
const unsigned char *proto = NULL;
/* API dictates unsigned int rather than size_t. */
unsigned int proto_len = 0;
+ EVP_PKEY *tmp_key;
memset(&server_ctx_data, 0, sizeof(server_ctx_data));
memset(&server2_ctx_data, 0, sizeof(server2_ctx_data));
*/
for(;;) {
if (client_turn) {
- do_connect_step(&client, phase);
+ do_connect_step(test_ctx, &client, phase);
status = handshake_status(client.status, server.status,
1 /* client went last */);
} else {
- do_connect_step(&server, phase);
+ do_connect_step(test_ctx, &server, phase);
status = handshake_status(server.status, client.status,
0 /* server went last */);
}
switch (status) {
case HANDSHAKE_SUCCESS:
+ client_turn_count = 0;
phase = next_phase(test_ctx, phase);
if (phase == CONNECTION_DONE) {
ret->result = SSL_TEST_SUCCESS;
ret->result = SSL_TEST_INTERNAL_ERROR;
goto err;
case HANDSHAKE_RETRY:
+ if (client_turn_count++ >= 2000) {
+ /*
+ * At this point, there's been so many PEER_RETRY in a row
+ * that it's likely both sides are stuck waiting for a read.
+ * It's time to give up.
+ */
+ ret->result = SSL_TEST_INTERNAL_ERROR;
+ goto err;
+ }
+
/* Continue. */
client_turn ^= 1;
break;
if (session_out != NULL)
*session_out = SSL_get1_session(client.ssl);
+ if (SSL_get_server_tmp_key(client.ssl, &tmp_key)) {
+ ret->tmp_key_type = pkey_type(tmp_key);
+ EVP_PKEY_free(tmp_key);
+ }
+
+ SSL_get_peer_signature_nid(client.ssl, &ret->server_sign_hash);
+ SSL_get_peer_signature_nid(server.ssl, &ret->client_sign_hash);
+
+ SSL_get_peer_signature_type_nid(client.ssl, &ret->server_sign_type);
+ SSL_get_peer_signature_type_nid(server.ssl, &ret->client_sign_type);
+
+ ret->server_cert_type = peer_pkey_type(client.ssl);
+ ret->client_cert_type = peer_pkey_type(server.ssl);
+
ctx_data_free_data(&server_ctx_data);
ctx_data_free_data(&server2_ctx_data);
ctx_data_free_data(&client_ctx_data);