/*
* Copyright 2016 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
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <string.h>
#include <openssl/bio.h>
#include <openssl/x509_vfy.h>
#include <openssl/ssl.h>
#include "handshake_helper.h"
#include "testutil.h"
HANDSHAKE_RESULT *HANDSHAKE_RESULT_new()
{
HANDSHAKE_RESULT *ret = OPENSSL_zalloc(sizeof(*ret));
TEST_check(ret != NULL);
return ret;
}
void HANDSHAKE_RESULT_free(HANDSHAKE_RESULT *result)
{
if (result == NULL)
return;
OPENSSL_free(result->client_npn_negotiated);
OPENSSL_free(result->server_npn_negotiated);
OPENSSL_free(result->client_alpn_negotiated);
OPENSSL_free(result->server_alpn_negotiated);
OPENSSL_free(result);
}
/*
* Since there appears to be no way to extract the sent/received alert
* from the SSL object directly, we use the info callback and stash
* the result in ex_data.
*/
typedef struct handshake_ex_data_st {
int alert_sent;
int num_fatal_alerts_sent;
int alert_received;
int session_ticket_do_not_call;
ssl_servername_t servername;
} HANDSHAKE_EX_DATA;
typedef struct ctx_data_st {
unsigned char *npn_protocols;
size_t npn_protocols_len;
unsigned char *alpn_protocols;
size_t alpn_protocols_len;
} CTX_DATA;
/* |ctx_data| itself is stack-allocated. */
static void ctx_data_free_data(CTX_DATA *ctx_data)
{
OPENSSL_free(ctx_data->npn_protocols);
ctx_data->npn_protocols = NULL;
OPENSSL_free(ctx_data->alpn_protocols);
ctx_data->alpn_protocols = NULL;
}
static int ex_data_idx;
static void info_cb(const SSL *s, int where, int ret)
{
if (where & SSL_CB_ALERT) {
HANDSHAKE_EX_DATA *ex_data =
(HANDSHAKE_EX_DATA*)(SSL_get_ex_data(s, ex_data_idx));
if (where & SSL_CB_WRITE) {
ex_data->alert_sent = ret;
if (strcmp(SSL_alert_type_string(ret), "F") == 0
|| strcmp(SSL_alert_desc_string(ret), "CN") == 0)
ex_data->num_fatal_alerts_sent++;
} else {
ex_data->alert_received = ret;
}
}
}
/* Select the appropriate server CTX.
* Returns SSL_TLSEXT_ERR_OK if a match was found.
* If |ignore| is 1, returns SSL_TLSEXT_ERR_NOACK on mismatch.
* Otherwise, returns SSL_TLSEXT_ERR_ALERT_FATAL on mismatch.
* An empty SNI extension also returns SSL_TSLEXT_ERR_NOACK.
*/
static int select_server_ctx(SSL *s, void *arg, int ignore)
{
const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
HANDSHAKE_EX_DATA *ex_data =
(HANDSHAKE_EX_DATA*)(SSL_get_ex_data(s, ex_data_idx));
if (servername == NULL) {
ex_data->servername = SSL_TEST_SERVERNAME_SERVER1;
return SSL_TLSEXT_ERR_NOACK;
}
if (strcmp(servername, "server2") == 0) {
SSL_CTX *new_ctx = (SSL_CTX*)arg;
SSL_set_SSL_CTX(s, new_ctx);
/*
* Copy over all the SSL_CTX options - reasonable behavior
* allows testing of cases where the options between two
* contexts differ/conflict
*/
SSL_clear_options(s, 0xFFFFFFFFL);
SSL_set_options(s, SSL_CTX_get_options(new_ctx));
ex_data->servername = SSL_TEST_SERVERNAME_SERVER2;
return SSL_TLSEXT_ERR_OK;
} else if (strcmp(servername, "server1") == 0) {
ex_data->servername = SSL_TEST_SERVERNAME_SERVER1;
return SSL_TLSEXT_ERR_OK;
} else if (ignore) {
ex_data->servername = SSL_TEST_SERVERNAME_SERVER1;
return SSL_TLSEXT_ERR_NOACK;
} else {
/* Don't set an explicit alert, to test library defaults. */
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
}
/*
* (RFC 6066):
* If the server understood the ClientHello extension but
* does not recognize the server name, the server SHOULD take one of two
* actions: either abort the handshake by sending a fatal-level