2018-08-26 14:30:26 +08:00
|
|
|
|
/*
|
|
|
|
|
|
* SSL stream implementation.
|
|
|
|
|
|
* Use promise as parameter of every asynchronous function call. e.g. callback functions of libevent or future-promise.
|
|
|
|
|
|
* Author: zhengchao@iie.ac.cn
|
|
|
|
|
|
* Create: 2018-8-17
|
|
|
|
|
|
*/
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
#include <assert.h>
|
2018-08-23 19:46:38 +08:00
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
#include <sys/socket.h>
|
2018-08-21 16:11:50 +08:00
|
|
|
|
|
|
|
|
|
|
#include <event2/event.h>
|
|
|
|
|
|
#include <event2/listener.h>
|
|
|
|
|
|
#include <event2/bufferevent.h>
|
|
|
|
|
|
#include <event2/bufferevent_ssl.h>
|
|
|
|
|
|
#include <event2/buffer.h>
|
|
|
|
|
|
#include <event2/thread.h>
|
|
|
|
|
|
#include <event2/dns.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include <openssl/ssl.h>
|
|
|
|
|
|
#include <openssl/err.h>
|
|
|
|
|
|
#include <openssl/rand.h>
|
|
|
|
|
|
#include <openssl/x509.h>
|
|
|
|
|
|
#include <openssl/x509v3.h>
|
|
|
|
|
|
|
2018-08-21 19:01:10 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#include <tfe_stream.h>
|
|
|
|
|
|
#include <tfe_utils.h>
|
|
|
|
|
|
#include <tfe_future.h>
|
|
|
|
|
|
#include <stream.h>
|
2018-08-26 18:26:24 +08:00
|
|
|
|
#include <key_keeper.h>
|
2018-08-24 19:22:43 +08:00
|
|
|
|
#include <ssl_sess_cache.h>
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#include <ssl.h>
|
2018-08-23 19:46:38 +08:00
|
|
|
|
#include <MESA_htable.h>
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
#define SSL_EX_DATA_IDX_SSLMGR 0
|
|
|
|
|
|
#define MAX_NET_RETRIES 50
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct ssl_mgr {
|
|
|
|
|
|
int sslcomp;
|
|
|
|
|
|
int no_ssl2;
|
|
|
|
|
|
int no_ssl3;
|
|
|
|
|
|
int no_tls10;
|
|
|
|
|
|
int no_tls11;
|
|
|
|
|
|
int no_tls12;
|
|
|
|
|
|
CONST_SSL_METHOD * (*sslmethod) (void); //Parameter of SSL_CTX_new
|
|
|
|
|
|
int sslversion;
|
|
|
|
|
|
char ssl_session_context[8];
|
|
|
|
|
|
int cache_slot_num;
|
|
|
|
|
|
int sess_expire_seconds;
|
|
|
|
|
|
struct sess_cache * down_sess_cache;
|
|
|
|
|
|
struct sess_cache * up_sess_cache;
|
2018-08-26 18:26:24 +08:00
|
|
|
|
char default_ciphers[TFE_STRING_MAX];
|
2018-08-26 14:30:26 +08:00
|
|
|
|
DH * dh;
|
|
|
|
|
|
char * ecdhcurve;
|
|
|
|
|
|
char * crlurl;
|
|
|
|
|
|
uint8_t SSL_MODE_RELEASE_BUFFERS;
|
|
|
|
|
|
void * logger;
|
2018-08-26 18:26:24 +08:00
|
|
|
|
char trust_CA_file[TFE_STRING_MAX];
|
|
|
|
|
|
char trust_CA_dir[TFE_STRING_MAX];
|
|
|
|
|
|
X509_STORE* trust_CA_store;
|
|
|
|
|
|
struct key_keeper * keeper_of_keys;
|
2018-08-23 19:46:38 +08:00
|
|
|
|
};
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-26 18:26:24 +08:00
|
|
|
|
struct __ssl_stream_debug
|
|
|
|
|
|
{
|
|
|
|
|
|
evutil_socket_t fd;
|
|
|
|
|
|
};
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct ssl_stream {
|
2018-08-24 10:55:47 +08:00
|
|
|
|
enum tfe_conn_dir dir;
|
2018-08-26 14:30:26 +08:00
|
|
|
|
SSL * ssl;
|
|
|
|
|
|
struct ssl_mgr * mgr;
|
2018-08-26 18:26:24 +08:00
|
|
|
|
union
|
|
|
|
|
|
{
|
|
|
|
|
|
struct ssl_chello * client_hello; //dir=upstream, a little weird, which send by downstream client.
|
|
|
|
|
|
struct keyring* keyring; //dir=downstream.
|
|
|
|
|
|
};
|
|
|
|
|
|
struct __ssl_stream_debug _do_not_use;
|
2018-08-23 19:46:38 +08:00
|
|
|
|
};
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct ssl_chello {
|
2018-08-24 19:22:43 +08:00
|
|
|
|
//client hello
|
2018-08-26 14:30:26 +08:00
|
|
|
|
int version;
|
|
|
|
|
|
char * sni;
|
|
|
|
|
|
char * cipher_suites;
|
2018-08-24 19:22:43 +08:00
|
|
|
|
};
|
2018-08-21 19:01:10 +08:00
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
struct peek_client_hello_ctx {
|
|
|
|
|
|
struct ssl_chello chello;
|
|
|
|
|
|
unsigned char sni_peek_retries; /* max 64 SNI parse retries */
|
|
|
|
|
|
struct event * ev;
|
|
|
|
|
|
struct event_base * evbase;
|
|
|
|
|
|
void * logger;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
};
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct ssl_connect_origin_ctx {
|
|
|
|
|
|
struct bufferevent * bev;
|
|
|
|
|
|
struct ssl_stream * s_stream;
|
|
|
|
|
|
struct ssl_mgr * mgr;
|
2018-08-23 19:46:38 +08:00
|
|
|
|
struct sockaddr addr;
|
2018-08-26 14:30:26 +08:00
|
|
|
|
socklen_t addrlen;
|
|
|
|
|
|
void * logger;
|
|
|
|
|
|
|
|
|
|
|
|
evutil_socket_t fd_upstream;
|
|
|
|
|
|
evutil_socket_t fd_downstream;
|
|
|
|
|
|
struct event_base * evbase;
|
|
|
|
|
|
struct future * f_peek_chello;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-08-26 18:26:24 +08:00
|
|
|
|
struct ask_keyring_ctx {
|
2018-08-26 14:30:26 +08:00
|
|
|
|
int keyring_id;
|
|
|
|
|
|
struct ssl_stream * origin_ssl;
|
|
|
|
|
|
X509 * origin_crt;
|
2018-08-26 18:26:24 +08:00
|
|
|
|
int is_origin_crt_vaild;
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct ssl_mgr * ssl_mgr;
|
|
|
|
|
|
evutil_socket_t fd_downstream;
|
|
|
|
|
|
struct event_base * evbase;
|
|
|
|
|
|
|
|
|
|
|
|
struct future * f_query_cert;
|
|
|
|
|
|
struct bufferevent * bev_down;
|
|
|
|
|
|
struct ssl_stream* downstream;
|
2018-08-23 19:46:38 +08:00
|
|
|
|
};
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
2018-08-24 10:55:47 +08:00
|
|
|
|
/*
|
|
|
|
|
|
* SSL shutdown context.
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct ssl_shutdown_ctx {
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct ssl_stream * s_stream;
|
|
|
|
|
|
struct event_base * evbase;
|
|
|
|
|
|
struct event * ev;
|
|
|
|
|
|
unsigned int retries;
|
2018-08-24 10:55:47 +08:00
|
|
|
|
};
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-26 18:26:24 +08:00
|
|
|
|
struct ssl_stream * ssl_stream_new(struct ssl_mgr * mgr, evutil_socket_t fd, enum tfe_conn_dir dir, struct ssl_chello * client_hello, struct keyring* crt)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct sockaddr addr;
|
|
|
|
|
|
socklen_t addrlen;
|
|
|
|
|
|
int ret=0;
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct ssl_stream * s_stream = ALLOC(struct ssl_stream, 1);
|
2018-08-26 18:26:24 +08:00
|
|
|
|
s_stream->dir=dir;
|
|
|
|
|
|
s_stream->mgr=mgr;
|
|
|
|
|
|
s_stream->_do_not_use.fd=fd;
|
|
|
|
|
|
ret = getpeername(fd , &addr, &addrlen);
|
|
|
|
|
|
assert(ret == 0);
|
|
|
|
|
|
switch (dir)
|
|
|
|
|
|
{
|
|
|
|
|
|
case CONN_DIR_DOWNSTREAM:
|
|
|
|
|
|
s_stream->ssl= downstream_ssl_create(mgr, crt);
|
|
|
|
|
|
s_stream->keyring=crt;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CONN_DIR_UPSTREAM:
|
|
|
|
|
|
s_stream->ssl= upstream_ssl_create(mgr, client_hello, fd);
|
|
|
|
|
|
s_stream->client_hello=client_hello;
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
assert(0);
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
return s_stream;
|
2018-08-26 18:26:24 +08:00
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void ssl_stream_free(struct ssl_stream * s_stream)
|
|
|
|
|
|
{
|
|
|
|
|
|
SSL_free(s_stream->ssl);
|
|
|
|
|
|
s_stream->ssl = NULL;
|
2018-08-26 18:26:24 +08:00
|
|
|
|
switch (s_stream->dir)
|
|
|
|
|
|
{
|
|
|
|
|
|
case CONN_DIR_DOWNSTREAM:
|
|
|
|
|
|
if(s_stream->keyring!=NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
key_keeper_free_keyring(s_stream->keyring);
|
|
|
|
|
|
s_stream->keyring=NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case CONN_DIR_UPSTREAM:
|
|
|
|
|
|
if(s_stream->client_hello!=NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
ssl_free_chello(s_stream->client_hello);
|
|
|
|
|
|
s_stream->client_hello=NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
assert(0);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
s_stream->mgr = NULL;
|
|
|
|
|
|
free(s_stream);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int sslver_str2num(const char * version_str)
|
2018-08-23 19:46:38 +08:00
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
int sslversion = -1;
|
|
|
|
|
|
|
2018-08-24 19:22:43 +08:00
|
|
|
|
assert(OPENSSL_VERSION_NUMBER >= 0x10100000L);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-24 19:22:43 +08:00
|
|
|
|
/*
|
|
|
|
|
|
* Support for SSLv2 and the corresponding SSLv2_method(),
|
|
|
|
|
|
* SSLv2_server_method() and SSLv2_client_method() functions were
|
|
|
|
|
|
* removed in OpenSSL 1.1.0.
|
|
|
|
|
|
*/
|
2018-08-26 18:26:24 +08:00
|
|
|
|
if (!strcmp(version_str, "ssl3"))
|
|
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
sslversion = SSL3_VERSION;
|
2018-08-24 19:22:43 +08:00
|
|
|
|
}
|
2018-08-26 18:26:24 +08:00
|
|
|
|
else if (!strcmp(version_str, "tls10") || !strcmp(version_str, "tls1"))
|
|
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
sslversion = TLS1_VERSION;
|
2018-08-24 19:22:43 +08:00
|
|
|
|
}
|
2018-08-26 18:26:24 +08:00
|
|
|
|
else if (!strcmp(version_str, "tls11"))
|
|
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
sslversion = TLS1_1_VERSION;
|
|
|
|
|
|
}
|
2018-08-26 18:26:24 +08:00
|
|
|
|
else if (!strcmp(version_str, "tls12"))
|
|
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
sslversion = TLS1_2_VERSION;
|
2018-08-24 19:22:43 +08:00
|
|
|
|
}
|
2018-08-26 18:26:24 +08:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
sslversion = -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-24 19:22:43 +08:00
|
|
|
|
return sslversion;
|
2018-08-23 19:46:38 +08:00
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ssl_manager_destroy(struct ssl_mgr * mgr)
|
2018-08-23 19:46:38 +08:00
|
|
|
|
{
|
2018-08-26 18:26:24 +08:00
|
|
|
|
if(mgr->keeper_of_keys!=NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
key_keeper_destroy(mgr->keeper_of_keys);
|
|
|
|
|
|
}
|
|
|
|
|
|
if(mgr->trust_CA_store!=NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
X509_STORE_free(mgr->trust_CA_store);
|
|
|
|
|
|
mgr->trust_CA_store=NULL;
|
|
|
|
|
|
}
|
2018-08-23 19:46:38 +08:00
|
|
|
|
free(mgr);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
struct ssl_mgr * ssl_manager_init(const char * ini_profile, const char * section, void * logger) {
|
|
|
|
|
|
struct ssl_mgr * mgr = ALLOC(struct ssl_mgr, 1);
|
|
|
|
|
|
int ret = 0, value = 0;
|
|
|
|
|
|
char version_str[TFE_SYMBOL_MAX];
|
|
|
|
|
|
mgr->logger = logger;
|
|
|
|
|
|
MESA_load_profile_string_def(ini_profile, section, "ssl_version", version_str, sizeof(version_str), "tls12");
|
|
|
|
|
|
mgr->sslversion = sslver_str2num(version_str);
|
|
|
|
|
|
|
|
|
|
|
|
if (mgr->sslversion < 0) {
|
|
|
|
|
|
TFE_LOG_ERROR(logger, "Unsupported SSL/TLS protocol %s", version_str);
|
2018-08-24 19:22:43 +08:00
|
|
|
|
goto error_out;
|
2018-08-23 19:46:38 +08:00
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
2018-08-24 19:22:43 +08:00
|
|
|
|
//tfe2a uses SSLv23_method, it was been deprecated and replaced with the TLS_method() in openssl 1.1.0.
|
2018-08-26 14:30:26 +08:00
|
|
|
|
mgr->sslmethod = TLS_method;
|
|
|
|
|
|
MESA_load_profile_int_def(ini_profile, section, "ssl_compression", & (mgr->sslcomp), 1);
|
|
|
|
|
|
MESA_load_profile_int_def(ini_profile, section, "no_ssl2", & (mgr->no_ssl2), 1);
|
|
|
|
|
|
MESA_load_profile_int_def(ini_profile, section, "no_ssl3", & (mgr->no_ssl3), 1);
|
|
|
|
|
|
MESA_load_profile_int_def(ini_profile, section, "no_tls10", & (mgr->no_tls10), 1);
|
|
|
|
|
|
MESA_load_profile_int_def(ini_profile, section, "no_tls11", & (mgr->no_tls11), 0);
|
|
|
|
|
|
MESA_load_profile_int_def(ini_profile, section, "no_tls12", & (mgr->no_tls12), 0);
|
|
|
|
|
|
MESA_load_profile_int_def(ini_profile, section, "session_cache_slot_num", & (mgr->cache_slot_num),
|
|
|
|
|
|
4 * 1024 * 1024);
|
|
|
|
|
|
MESA_load_profile_int_def(ini_profile, section, "session_cache_slot_num", & (mgr->sess_expire_seconds), 30 * 60);
|
2018-08-23 19:46:38 +08:00
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
mgr->up_sess_cache = ssl_sess_cache_create(mgr->cache_slot_num, mgr->sess_expire_seconds, CONN_DIR_UPSTREAM);
|
|
|
|
|
|
mgr->down_sess_cache = ssl_sess_cache_create(mgr->cache_slot_num, mgr->sess_expire_seconds, CONN_DIR_DOWNSTREAM);
|
|
|
|
|
|
|
2018-08-26 18:26:24 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mgr->keeper_of_keys = key_keeper_init(ini_profile, section, logger);
|
|
|
|
|
|
|
|
|
|
|
|
if (mgr->keeper_of_keys == NULL)
|
|
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
TFE_LOG_ERROR(logger, "Certificate Manager initiate failed.");
|
|
|
|
|
|
goto error_out;
|
|
|
|
|
|
}
|
2018-08-26 18:26:24 +08:00
|
|
|
|
mgr->trust_CA_store=X509_STORE_new();
|
|
|
|
|
|
if(mgr->trust_CA_store==NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
TFE_LOG_ERROR(logger,"Failed at creating X509_STORE");
|
|
|
|
|
|
goto error_out;
|
|
|
|
|
|
}
|
|
|
|
|
|
ret=X509_STORE_set_default_paths(mgr->trust_CA_store);
|
|
|
|
|
|
if(ret==0)
|
|
|
|
|
|
{
|
|
|
|
|
|
TFE_LOG_ERROR(logger,"Failed at setting default paths for X509_STORE");
|
|
|
|
|
|
goto error_out;
|
|
|
|
|
|
}
|
|
|
|
|
|
MESA_load_profile_string_def(ini_profile, section, "trust_CA_file", mgr->trust_CA_file, sizeof(mgr->trust_CA_file), "");
|
|
|
|
|
|
MESA_load_profile_string_def(ini_profile, section, "trust_CA_dir", mgr->trust_CA_dir, sizeof(mgr->trust_CA_dir), "");
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-26 18:26:24 +08:00
|
|
|
|
ret=X509_STORE_load_locations(mgr->trust_CA_store,strlen(mgr->trust_CA_file)>0? mgr->trust_CA_file:NULL
|
|
|
|
|
|
,strlen(mgr->trust_CA_dir)>0? mgr->trust_CA_dir:NULL);
|
|
|
|
|
|
if(ret==0)
|
|
|
|
|
|
{
|
|
|
|
|
|
TFE_LOG_ERROR(logger,"Failed at setting load locations for X509_STORE");
|
|
|
|
|
|
goto error_out;
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
memcpy(mgr->ssl_session_context, "mesa-tfe", sizeof(mgr->ssl_session_context));
|
2018-08-24 19:22:43 +08:00
|
|
|
|
return mgr;
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-24 19:22:43 +08:00
|
|
|
|
error_out:
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-24 19:22:43 +08:00
|
|
|
|
ssl_manager_destroy(mgr);
|
|
|
|
|
|
return NULL;
|
2018-08-26 18:26:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
int ssl_conn_verify_cert(X509_STORE *store, const SSL * ssl)
|
|
|
|
|
|
{
|
|
|
|
|
|
int ret=0;
|
|
|
|
|
|
STACK_OF(X509) * cert_chain = SSL_get_peer_cert_chain(ssl);
|
|
|
|
|
|
if(cert_chain==NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
// The peer certificate chain is not necessarily available after reusing a session, in which case a NULL pointer is returned.
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
X509_STORE_CTX *ctx=X509_STORE_CTX_new();
|
|
|
|
|
|
X509 * cert = sk_X509_value(cert_chain, 0);
|
|
|
|
|
|
ret=X509_STORE_CTX_init(ctx, store, cert, cert_chain);
|
|
|
|
|
|
assert(ret==1);
|
|
|
|
|
|
|
|
|
|
|
|
//If a complete chain can be built and validated this function returns 1, otherwise it return zero or negtive code.
|
|
|
|
|
|
ret=X509_verify_cert(ctx);
|
|
|
|
|
|
X509_STORE_CTX_free(ctx);
|
|
|
|
|
|
return (ret==1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void peek_client_hello_ctx_free(void * ctx)
|
2018-08-21 16:11:50 +08:00
|
|
|
|
{
|
2018-08-26 18:26:24 +08:00
|
|
|
|
struct peek_client_hello_ctx * _ctx = (struct peek_client_hello_ctx *)ctx;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
event_free(_ctx->ev);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
_ctx->ev = NULL;
|
|
|
|
|
|
free(_ctx->chello.sni);
|
|
|
|
|
|
_ctx->chello.sni = NULL;
|
|
|
|
|
|
free(_ctx->chello.cipher_suites);
|
|
|
|
|
|
_ctx->chello.cipher_suites = NULL;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
free(_ctx);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
2018-08-26 18:26:24 +08:00
|
|
|
|
struct ssl_chello * ssl_peek_result_release_chello(future_result_t * result)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct ssl_chello * p = (struct ssl_chello *)result, *copy = NULL;
|
|
|
|
|
|
copy = ALLOC(struct ssl_chello, 1);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
if (p != NULL) {
|
|
|
|
|
|
copy->sni = tfe_strdup(p->sni);
|
|
|
|
|
|
copy->cipher_suites = tfe_strdup(p->cipher_suites);
|
|
|
|
|
|
copy->version = p->version;
|
2018-08-21 19:01:10 +08:00
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 19:01:10 +08:00
|
|
|
|
return copy;
|
2018-08-26 14:30:26 +08:00
|
|
|
|
} void ssl_free_chello(struct ssl_chello * p)
|
2018-08-21 19:01:10 +08:00
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
if (p == NULL) {
|
2018-08-21 19:01:10 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 19:01:10 +08:00
|
|
|
|
free(p->sni);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
p->sni = NULL;
|
2018-08-21 19:01:10 +08:00
|
|
|
|
free(p->cipher_suites);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
p->cipher_suites = NULL;
|
2018-08-21 19:01:10 +08:00
|
|
|
|
free(p);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2018-08-21 16:11:50 +08:00
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 19:01:10 +08:00
|
|
|
|
static void peek_client_hello_cb(evutil_socket_t fd, short what, void * arg)
|
2018-08-21 16:11:50 +08:00
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct promise * promise = (struct promise *)arg;
|
2018-08-26 18:26:24 +08:00
|
|
|
|
//use promise_get_ctx instead of promise_dettach_ctx for try more times.
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct peek_client_hello_ctx * ctx = (struct peek_client_hello_ctx *)promise_get_ctx(promise);
|
|
|
|
|
|
const char * reason_too_many_retries = "too many tries";
|
|
|
|
|
|
const char * reason_see_no_client_hello = "see no client hello";
|
|
|
|
|
|
const char * reason = NULL;
|
|
|
|
|
|
char * sni = NULL;
|
|
|
|
|
|
unsigned char buf[1024];
|
|
|
|
|
|
ssize_t n = 0;
|
|
|
|
|
|
const unsigned char * chello = NULL;
|
|
|
|
|
|
int rv = 0;
|
|
|
|
|
|
|
|
|
|
|
|
n = recv(fd, buf, sizeof(buf), MSG_PEEK);
|
|
|
|
|
|
|
|
|
|
|
|
if (n == -1) {
|
|
|
|
|
|
TFE_LOG_ERROR(ctx->logger, "Error peeking on fd, aborting connection\n");
|
2018-08-21 19:01:10 +08:00
|
|
|
|
goto failed;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
if (n == 0) {
|
2018-08-21 19:01:10 +08:00
|
|
|
|
goto failed;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 19:01:10 +08:00
|
|
|
|
//todo: parse version and cipher suites.
|
2018-08-23 19:46:38 +08:00
|
|
|
|
//or we should use sni proxy instead? https://github.com/dlundquist/sniproxy/blob/master/src/tls.c
|
2018-08-26 14:30:26 +08:00
|
|
|
|
rv = ssl_tls_clienthello_parse(buf, n, 0, &chello, & (ctx->chello.sni));
|
|
|
|
|
|
|
|
|
|
|
|
if (rv == 0) {
|
2018-08-23 19:46:38 +08:00
|
|
|
|
promise_dettach_ctx(promise);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
promise_success(promise, & (ctx->chello));
|
2018-08-23 19:46:38 +08:00
|
|
|
|
peek_client_hello_ctx_free(ctx);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
else {
|
|
|
|
|
|
if (!chello) {
|
|
|
|
|
|
TFE_LOG_ERROR(ctx->logger, "Peeking did not yield a (truncated) ClientHello message, aborting connection\n");
|
|
|
|
|
|
reason = "see no client hello";
|
2018-08-23 19:46:38 +08:00
|
|
|
|
goto failed;
|
2018-08-26 14:30:26 +08:00
|
|
|
|
}
|
2018-08-23 19:46:38 +08:00
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
if (ctx->sni_peek_retries++ > MAX_NET_RETRIES) {
|
|
|
|
|
|
TFE_LOG_ERROR(ctx->logger, "Peek failed due to too many retries\n");
|
|
|
|
|
|
reason = "too many peek retries";
|
2018-08-23 19:46:38 +08:00
|
|
|
|
goto failed;
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
/* ssl_tls_clienthello_parse indicates that we
|
2018-08-23 19:46:38 +08:00
|
|
|
|
* should retry later when we have more data, and we
|
|
|
|
|
|
* haven't reached the maximum retry count yet.
|
|
|
|
|
|
* Reschedule this event as timeout-only event in
|
|
|
|
|
|
* order to prevent busy looping over the read event.
|
|
|
|
|
|
* Because we only peeked at the pending bytes and
|
|
|
|
|
|
* never actually read them, fd is still ready for
|
2018-08-26 14:30:26 +08:00
|
|
|
|
* reading now. We use 25 * 0.2 s = 5 s timeout. */
|
|
|
|
|
|
struct timeval retry_delay = {
|
|
|
|
|
|
0, 100
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
event_free(ctx->ev);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
ctx->ev = event_new(ctx->evbase, fd, 0, peek_client_hello_cb, promise);
|
|
|
|
|
|
assert(ctx->ev != NULL);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
event_add(ctx->ev, &retry_delay);
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
return;
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 19:01:10 +08:00
|
|
|
|
failed:
|
|
|
|
|
|
promise_dettach_ctx(promise);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
promise_failed(promise, FUTURE_ERROR_EXCEPTION, reason);
|
2018-08-23 19:46:38 +08:00
|
|
|
|
peek_client_hello_ctx_free(ctx);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-21 19:01:10 +08:00
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
static void ssl_async_peek_client_hello(struct future * future, evutil_socket_t fd, struct event_base * evbase,
|
|
|
|
|
|
void * logger)
|
2018-08-21 16:11:50 +08:00
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct event * ev = NULL;
|
|
|
|
|
|
struct promise * p = future_to_promise(future);
|
|
|
|
|
|
struct peek_client_hello_ctx * ctx = ALLOC(struct peek_client_hello_ctx, 1);
|
|
|
|
|
|
ctx->ev = event_new(evbase, fd, EV_READ, peek_client_hello_cb, p);
|
|
|
|
|
|
ctx->logger = logger;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
event_add(evbase, NULL);
|
2018-08-21 19:01:10 +08:00
|
|
|
|
promise_set_ctx(p, ctx, peek_client_hello_ctx_free);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
/*
|
|
|
|
|
|
* Create new SSL context for outgoing connections to the original destination.
|
|
|
|
|
|
* If hostname sni is provided, use it for Server Name Indication.
|
|
|
|
|
|
*/
|
2018-08-26 18:26:24 +08:00
|
|
|
|
static SSL * upstream_ssl_create(struct ssl_mgr * mgr, const struct ssl_chello * chello, evutil_socket_t fd)
|
2018-08-21 16:11:50 +08:00
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
SSL_CTX * sslctx = NULL;
|
|
|
|
|
|
SSL * ssl = NULL;
|
|
|
|
|
|
SSL_SESSION * sess = NULL;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
sslctx = SSL_CTX_new(mgr->sslmethod());
|
2018-08-23 19:46:38 +08:00
|
|
|
|
|
2018-08-24 10:55:47 +08:00
|
|
|
|
sslctx_set_opts(sslctx, mgr);
|
2018-08-23 19:46:38 +08:00
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
if (mgr->sslversion) {
|
|
|
|
|
|
if (SSL_CTX_set_min_proto_version(sslctx, chello->version) == 0 ||
|
2018-08-26 14:30:26 +08:00
|
|
|
|
SSL_CTX_set_max_proto_version(sslctx, chello->version) == 0) {
|
2018-08-23 19:46:38 +08:00
|
|
|
|
SSL_CTX_free(sslctx);
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
|
|
|
|
|
|
|
|
|
|
|
|
SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, NULL);
|
|
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
ssl = SSL_new(sslctx);
|
|
|
|
|
|
SSL_CTX_free(sslctx); /* SSL_new() increments refcount */
|
|
|
|
|
|
|
|
|
|
|
|
if (!ssl) {
|
2018-08-23 19:46:38 +08:00
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
#ifndef OPENSSL_NO_TLSEXT
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
if (chello->sni) {
|
2018-08-23 19:46:38 +08:00
|
|
|
|
SSL_set_tlsext_host_name(ssl, sni);
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
#endif /* !OPENSSL_NO_TLSEXT */
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef SSL_MODE_RELEASE_BUFFERS
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
/* lower memory footprint for idle connections */
|
|
|
|
|
|
SSL_set_mode(ssl, SSL_get_mode(ssl) | SSL_MODE_RELEASE_BUFFERS);
|
|
|
|
|
|
#endif /* SSL_MODE_RELEASE_BUFFERS */
|
|
|
|
|
|
|
2018-08-26 18:26:24 +08:00
|
|
|
|
struct sockaddr addr;
|
|
|
|
|
|
socklen_t addrlen;
|
|
|
|
|
|
int ret=0;
|
|
|
|
|
|
ret = getpeername(fd , &addr, &addrlen);
|
|
|
|
|
|
assert(ret==0);
|
2018-08-23 19:46:38 +08:00
|
|
|
|
/* session resuming based on remote endpoint address and port */
|
2018-08-26 18:26:24 +08:00
|
|
|
|
sess = up_session_get(mgr->up_sess_cache, &addr, addrlen, chello->sni); /* new sess insert */
|
|
|
|
|
|
if (sess)
|
|
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
SSL_set_session(ssl, sess); /* increments sess refcount */
|
2018-08-23 19:46:38 +08:00
|
|
|
|
SSL_SESSION_free(sess);
|
|
|
|
|
|
}
|
|
|
|
|
|
return ssl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
void ssl_connect_origin_ctx_free(struct ssl_connect_origin_ctx * ctx)
|
2018-08-21 16:11:50 +08:00
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
if (ctx->s_stream != NULL) {
|
|
|
|
|
|
ssl_stream_free(ctx->s_stream);
|
2018-08-23 19:46:38 +08:00
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
if (ctx->bev != NULL) {
|
|
|
|
|
|
bufferevent_free(ctx->bev);
|
|
|
|
|
|
ctx->bev = NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (ctx->f_peek_chello != NULL) {
|
|
|
|
|
|
future_destroy(ctx->f_peek_chello);
|
|
|
|
|
|
ctx->f_peek_chello = NULL;
|
2018-08-23 19:46:38 +08:00
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
free(ctx);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct ssl_stream * ssl_conn_origin_result_release_stream(future_result_t * result) {
|
|
|
|
|
|
struct ssl_connect_origin_ctx * ctx = (struct ssl_connect_origin_ctx *)result;
|
|
|
|
|
|
struct ssl_stream * ret = ctx->s_stream;
|
|
|
|
|
|
ctx->s_stream = NULL; //giveup ownership
|
2018-08-23 19:46:38 +08:00
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct bufferevent * ssl_conn_origin_result_release_bev(future_result_t * result) {
|
|
|
|
|
|
struct ssl_connect_origin_ctx * ctx = (struct ssl_connect_origin_ctx *)result;
|
|
|
|
|
|
struct bufferevent * ret = ctx->bev;
|
|
|
|
|
|
ctx->bev = NULL; //giveup ownership
|
2018-08-23 19:46:38 +08:00
|
|
|
|
return ret;
|
|
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
}
|
2018-08-23 19:46:38 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
/*
|
|
|
|
|
|
* Callback for meta events on the up- and downstream connection bufferevents.
|
|
|
|
|
|
* Called when EOF has been reached, a connection has been made, and on errors.
|
|
|
|
|
|
*/
|
|
|
|
|
|
static void ssl_connect_origin_eventcb(struct bufferevent * bev, short events, void * arg)
|
|
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct promise * promise = (struct promise *)arg;
|
|
|
|
|
|
struct ssl_connect_origin_ctx * ctx = (struct ssl_connect_origin_ctx *)promise_dettach_ctx(promise);
|
|
|
|
|
|
|
|
|
|
|
|
struct ssl_stream * s_stream = ctx->s_stream;
|
|
|
|
|
|
SSL_SESSION * ssl_sess = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
if (events & BEV_EVENT_ERROR) {
|
|
|
|
|
|
promise_failed(promise, FUTURE_ERROR_EXCEPTION, "connect to orignal server failed.");
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
if (events & BEV_EVENT_CONNECTED) {
|
|
|
|
|
|
bufferevent_setcb(ctx->bev, NULL, NULL, NULL, NULL); //leave a clean bev for on_success
|
|
|
|
|
|
ssl_sess = SSL_get0_session(s_stream->ssl);
|
|
|
|
|
|
up_session_set(s_stream->mgr->up_sess_cache, & (ctx->addr), ctx->addrlen, s_stream->client_hello.sni,
|
|
|
|
|
|
ssl_sess);
|
|
|
|
|
|
promise_success(promise, ctx);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
2018-08-21 16:11:50 +08:00
|
|
|
|
assert(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
ssl_connect_origin_ctx_free(ctx);
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
static void peek_chello_on_succ(future_result_t * result, void * user)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct promise* p= (struct promise*)user;
|
|
|
|
|
|
struct ssl_connect_origin_ctx * ctx = (struct ssl_connect_origin_ctx *) promise_dettach_ctx(p);
|
|
|
|
|
|
|
|
|
|
|
|
struct ssl_chello * chello = ssl_peek_result_release_chello(result);//chello has been saved in ssl_stream.
|
2018-08-26 18:26:24 +08:00
|
|
|
|
ctx->s_stream = ssl_stream_new(ctx->mgr, ctx->fd_upstream, CONN_DIR_UPSTREAM, chello, NULL);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
ctx->bev = bufferevent_openssl_socket_new(ctx->evbase, ctx->fd_upstream, ctx->s_stream,
|
|
|
|
|
|
BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS);
|
|
|
|
|
|
bufferevent_openssl_set_allow_dirty_shutdown(ctx->bev, 1);
|
|
|
|
|
|
bufferevent_setcb(ctx->bev, NULL, NULL, ssl_connect_origin_eventcb, ctx);
|
|
|
|
|
|
bufferevent_disable(ctx->bev, EV_READ | EV_WRITE); //waiting for connect event only
|
|
|
|
|
|
future_destroy(ctx->f_peek_chello);
|
|
|
|
|
|
ctx->f_peek_chello = NULL;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void peek_chello_on_fail(enum e_future_error err, const char * what, void * user)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct promise* p= (struct promise*)user;
|
|
|
|
|
|
struct ssl_connect_origin_ctx * ctx = (struct ssl_connect_origin_ctx *) promise_dettach_ctx(p);
|
|
|
|
|
|
|
|
|
|
|
|
promise_failed(p, FUTURE_ERROR_EXCEPTION, "upstream create failed for no client hello in downstream.");
|
|
|
|
|
|
ssl_connect_origin_ctx_free(ctx);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern void ssl_async_upstream_create(struct future * f, struct ssl_mgr * mgr, evutil_socket_t fd_upstream,
|
|
|
|
|
|
evutil_socket_t fd_downstream, struct event_base * evbase)
|
|
|
|
|
|
{
|
|
|
|
|
|
struct promise * p = future_to_promise(f);
|
|
|
|
|
|
struct ssl_connect_origin_ctx * ctx = ALLOC(struct ssl_connect_origin_ctx, 1);
|
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
struct sockaddr addr;
|
2018-08-26 14:30:26 +08:00
|
|
|
|
socklen_t addrlen;
|
|
|
|
|
|
|
|
|
|
|
|
ret = getpeername(fd_downstream, & (ctx->addr), & (ctx->addrlen));
|
|
|
|
|
|
assert(ret == 0);
|
|
|
|
|
|
ctx->fd_downstream = fd_downstream;
|
|
|
|
|
|
ctx->fd_upstream = fd_upstream;
|
|
|
|
|
|
ctx->evbase = evbase;
|
|
|
|
|
|
ctx->mgr = mgr;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
promise_set_ctx(p, ctx, ssl_connect_origin_ctx_free);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
ctx->f_peek_chello = future_create(peek_chello_on_succ, peek_chello_on_fail, p);
|
|
|
|
|
|
ssl_async_peek_client_hello(ctx->f_peek_chello, fd_downstream, evbase, mgr->logger);
|
|
|
|
|
|
return;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* Called by OpenSSL when a new src SSL session is created.
|
|
|
|
|
|
* OpenSSL increments the refcount before calling the callback and will
|
|
|
|
|
|
* decrement it again if we return 0. Returning 1 will make OpenSSL skip
|
|
|
|
|
|
* the refcount decrementing. In other words, return 0 if we did not
|
|
|
|
|
|
* keep a pointer to the object (which we never do here).
|
|
|
|
|
|
*/
|
2018-08-26 14:30:26 +08:00
|
|
|
|
static int ossl_sessnew_cb(SSL * ssl, SSL_SESSION * sess)
|
2018-08-21 16:11:50 +08:00
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct ssl_mgr * mgr = (struct ssl_mgr *)
|
|
|
|
|
|
SSL_get_ex_data(ssl, SSL_EX_DATA_IDX_SSLMGR, mgr);
|
2018-08-23 19:46:38 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#ifdef HAVE_SSLV2
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
/* Session resumption seems to fail for SSLv2 with protocol
|
|
|
|
|
|
* parsing errors, so we disable caching for SSLv2. */
|
|
|
|
|
|
if (SSL_version(ssl) == SSL2_VERSION) {
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#endif /* HAVE_SSLV2 */
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
if (sess) {
|
2018-08-23 19:46:38 +08:00
|
|
|
|
down_session_set(mgr->down_sess_cache, sess);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
/*
|
|
|
|
|
|
* Called by OpenSSL when a src SSL session should be removed.
|
|
|
|
|
|
* OpenSSL calls SSL_SESSION_free() after calling the callback;
|
|
|
|
|
|
* we do not need to free the reference here.
|
|
|
|
|
|
*/
|
2018-08-26 14:30:26 +08:00
|
|
|
|
static void ossl_sessremove_cb(UNUSED SSL_CTX * sslctx, SSL_SESSION * sess)
|
2018-08-21 16:11:50 +08:00
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct ssl_mgr * mgr = (struct ssl_mgr *)
|
|
|
|
|
|
SSL_get_ex_data(ssl, SSL_EX_DATA_IDX_SSLMGR, mgr);
|
|
|
|
|
|
assert(mgr != NULL);
|
|
|
|
|
|
|
|
|
|
|
|
if (sess) {
|
|
|
|
|
|
down_session_del(mgr->down_sess_cache, sess) ;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
return;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
/*
|
|
|
|
|
|
* Called by OpenSSL when a src SSL session is requested by the client.
|
2018-08-26 14:30:26 +08:00
|
|
|
|
OPENSSL_VERSION_NUMBER >= 0x10100000L required.
|
2018-08-21 16:11:50 +08:00
|
|
|
|
*/
|
2018-08-26 14:30:26 +08:00
|
|
|
|
static SSL_SESSION * ossl_sessget_cb(UNUSED SSL * ssl, const unsigned char * id, int idlen, int * copy)
|
2018-08-21 16:11:50 +08:00
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct ssl_mgr * mgr = (struct ssl_mgr *)
|
|
|
|
|
|
SSL_get_ex_data(ssl, SSL_EX_DATA_IDX_SSLMGR, mgr);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
SSL_SESSION * sess;
|
|
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
*copy = 0; /* SSL should not increment reference count of session */
|
|
|
|
|
|
sess = (SSL_SESSION *)
|
|
|
|
|
|
down_session_get(mgr->down_sess_cache, id, idlen);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
return sess;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
/*
|
|
|
|
|
|
* Set SSL_CTX options that are the same for incoming and outgoing SSL_CTX.
|
|
|
|
|
|
*/
|
2018-08-26 14:30:26 +08:00
|
|
|
|
static void sslctx_set_opts(SSL_CTX * sslctx, struct ssl_mgr * mgr)
|
2018-08-21 16:11:50 +08:00
|
|
|
|
{
|
|
|
|
|
|
SSL_CTX_set_options(sslctx, SSL_OP_ALL);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#ifdef SSL_OP_TLS_ROLLBACK_BUG
|
|
|
|
|
|
SSL_CTX_set_options(sslctx, SSL_OP_TLS_ROLLBACK_BUG);
|
|
|
|
|
|
#endif /* SSL_OP_TLS_ROLLBACK_BUG */
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
|
|
|
|
|
|
SSL_CTX_set_options(sslctx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
|
|
|
|
|
|
#endif /* SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION */
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
|
|
|
|
|
|
SSL_CTX_set_options(sslctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
|
|
|
|
|
|
#endif /* SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#ifdef SSL_OP_NO_TICKET
|
|
|
|
|
|
SSL_CTX_set_options(sslctx, SSL_OP_NO_TICKET);
|
|
|
|
|
|
#endif /* SSL_OP_NO_TICKET */
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef SSL_OP_NO_SSLv2
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#ifdef HAVE_SSLV2
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
if (mgr->no_ssl2) {
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#endif /* HAVE_SSLV2 */
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2);
|
|
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#ifdef HAVE_SSLV2
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#endif /* HAVE_SSLV2 */
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#endif /* !SSL_OP_NO_SSLv2 */
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#ifdef HAVE_SSLV3
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
if (mgr->no_ssl3) {
|
2018-08-21 16:11:50 +08:00
|
|
|
|
SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv3);
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#endif /* HAVE_SSLV3 */
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#ifdef HAVE_TLSV10
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
if (mgr->no_tls10) {
|
2018-08-21 16:11:50 +08:00
|
|
|
|
SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1);
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#endif /* HAVE_TLSV10 */
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#ifdef HAVE_TLSV11
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
if (mgr->no_tls11) {
|
2018-08-21 16:11:50 +08:00
|
|
|
|
SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_1);
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#endif /* HAVE_TLSV11 */
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#ifdef HAVE_TLSV12
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
if (mgr->no_tls12) {
|
2018-08-21 16:11:50 +08:00
|
|
|
|
SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_2);
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#endif /* HAVE_TLSV12 */
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef SSL_OP_NO_COMPRESSION
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
if (!mgr->sslcomp) {
|
2018-08-21 16:11:50 +08:00
|
|
|
|
SSL_CTX_set_options(sslctx, SSL_OP_NO_COMPRESSION);
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-21 16:11:50 +08:00
|
|
|
|
#endif /* SSL_OP_NO_COMPRESSION */
|
|
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
SSL_CTX_set_cipher_list(sslctx, mgr->default_ciphers);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
/*
|
|
|
|
|
|
* Create and set up a new SSL_CTX instance for terminating SSL.
|
2018-08-26 18:26:24 +08:00
|
|
|
|
* Set up all the necessary callbacks, the keyring, the keyring chain and key.
|
2018-08-23 19:46:38 +08:00
|
|
|
|
*/
|
2018-08-26 18:26:24 +08:00
|
|
|
|
static SSL* downstream_ssl_create(struct ssl_mgr * mgr, struct keyring * crt)
|
2018-08-23 19:46:38 +08:00
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
SSL_CTX * sslctx = SSL_CTX_new(mgr->sslmethod());
|
|
|
|
|
|
if (!sslctx)
|
|
|
|
|
|
return NULL;
|
2018-08-26 18:26:24 +08:00
|
|
|
|
SSL* ssl=NULL;
|
|
|
|
|
|
int ret=0;
|
2018-08-26 14:30:26 +08:00
|
|
|
|
sslctx_set_opts(sslctx, mgr);
|
|
|
|
|
|
|
|
|
|
|
|
//TFE's OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
|
|
|
|
if (mgr->sslversion) {
|
|
|
|
|
|
if (SSL_CTX_set_min_proto_version(sslctx, mgr->sslversion) == 0 ||
|
|
|
|
|
|
SSL_CTX_set_max_proto_version(sslctx, mgr->sslversion) == 0) {
|
|
|
|
|
|
SSL_CTX_free(sslctx);
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SSL_CTX_sess_set_new_cb(sslctx, ossl_sessnew_cb);
|
|
|
|
|
|
SSL_CTX_sess_set_remove_cb(sslctx, ossl_sessremove_cb);
|
|
|
|
|
|
SSL_CTX_sess_set_get_cb(sslctx, ossl_sessget_cb);
|
|
|
|
|
|
SSL_CTX_set_session_cache_mode(sslctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_INTERNAL);
|
|
|
|
|
|
SSL_CTX_set_session_id_context(sslctx, (void *) (mgr->ssl_session_context),
|
|
|
|
|
|
sizeof(mgr->ssl_session_context));
|
|
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
#ifndef OPENSSL_NO_DH
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
if (mgr->dh) {
|
|
|
|
|
|
SSL_CTX_set_tmp_dh(sslctx, mgr->dh);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
SSL_CTX_set_tmp_dh_callback(sslctx, ssl_tmp_dh_callback);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
#endif /* !OPENSSL_NO_DH */
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
#ifndef OPENSSL_NO_ECDH
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
if (mgr->ecdhcurve) {
|
|
|
|
|
|
EC_KEY * ecdh = ssl_ec_by_name(mgr->ecdhcurve);
|
|
|
|
|
|
SSL_CTX_set_tmp_ecdh(sslctx, ecdh);
|
|
|
|
|
|
EC_KEY_free(ecdh);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
EC_KEY * ecdh = ssl_ec_by_name(NULL);
|
|
|
|
|
|
SSL_CTX_set_tmp_ecdh(sslctx, ecdh);
|
|
|
|
|
|
EC_KEY_free(ecdh);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
#endif /* !OPENSSL_NO_ECDH */
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-26 18:26:24 +08:00
|
|
|
|
SSL_CTX_use_certificate(sslctx, crt->cert);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
SSL_CTX_use_PrivateKey(sslctx, crt->key);
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < sk_X509_num(crt->chain); i++) {
|
|
|
|
|
|
X509 * c = sk_X509_value(crt->chain, i);
|
|
|
|
|
|
ssl_x509_refcount_inc(c); /* next call consumes a reference */
|
|
|
|
|
|
SSL_CTX_add_extra_chain_cert(sslctx, c);
|
|
|
|
|
|
}
|
2018-08-26 18:26:24 +08:00
|
|
|
|
ssl=SSL_new(sslctx);
|
|
|
|
|
|
SSL_CTX_free(sslctx); // SSL_new() increments refcount
|
|
|
|
|
|
sslctx=NULL;
|
|
|
|
|
|
ret = SSL_set_ex_data(ssl, SSL_EX_DATA_IDX_SSLMGR, mgr);
|
|
|
|
|
|
assert(ret == 1);
|
|
|
|
|
|
|
|
|
|
|
|
if (mgr->SSL_MODE_RELEASE_BUFFERS == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
/* lower memory footprint for idle connections */
|
|
|
|
|
|
SSL_set_mode(ssl, SSL_get_mode(ssl) | SSL_MODE_RELEASE_BUFFERS);
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-26 18:26:24 +08:00
|
|
|
|
return ssl;
|
2018-08-23 19:46:38 +08:00
|
|
|
|
}
|
2018-08-21 16:11:50 +08:00
|
|
|
|
|
|
|
|
|
|
|
2018-08-26 18:26:24 +08:00
|
|
|
|
void query_cert_ctx_free(struct ask_keyring_ctx * ctx)
|
2018-08-23 19:46:38 +08:00
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
X509_free(ctx->origin_crt);
|
|
|
|
|
|
|
|
|
|
|
|
if (ctx->f_query_cert != NULL) {
|
|
|
|
|
|
future_destroy(ctx->f_query_cert);
|
|
|
|
|
|
ctx->f_query_cert = NULL;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(ctx->bev_down!=NULL)
|
2018-08-21 16:11:50 +08:00
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
bufferevent_free(ctx->bev_down);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
if(ctx->downstream!=NULL)
|
2018-08-21 16:11:50 +08:00
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
ssl_stream_free(ctx->downstream);
|
2018-08-21 16:11:50 +08:00
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct ssl_stream* ssl_downstream_create_result_release_stream(future_result_t* result)
|
|
|
|
|
|
{
|
2018-08-26 18:26:24 +08:00
|
|
|
|
struct ask_keyring_ctx * ctx = (struct ask_keyring_ctx *)result;
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct ssl_stream* ret=ctx->downstream;
|
|
|
|
|
|
ctx->downstream=NULL;
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
struct bufferevent* ssl_downstream_create_result_release_bev(future_result_t* result)
|
|
|
|
|
|
{
|
2018-08-26 18:26:24 +08:00
|
|
|
|
struct ask_keyring_ctx * ctx = (struct ask_keyring_ctx *)result;
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct bufferevent* ret=ctx->bev_down;
|
|
|
|
|
|
ctx->bev_down=NULL;
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-26 18:26:24 +08:00
|
|
|
|
void ask_keyring_on_succ(void * result, void * user)
|
2018-08-26 14:30:26 +08:00
|
|
|
|
{
|
|
|
|
|
|
struct promise* p=(struct promise*)user;
|
2018-08-26 18:26:24 +08:00
|
|
|
|
struct ask_keyring_ctx * ctx = (struct ask_keyring_ctx *)promise_dettach_ctx(promise);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
struct ssl_stream * downstream = NULL;
|
2018-08-26 18:26:24 +08:00
|
|
|
|
struct keyring* crt=NULL;
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
struct ssl_mgr* mgr=ctx->ssl_mgr;
|
|
|
|
|
|
|
|
|
|
|
|
future_destroy(ctx->f_query_cert);
|
|
|
|
|
|
ctx->f_query_cert=NULL;
|
|
|
|
|
|
|
2018-08-26 18:26:24 +08:00
|
|
|
|
crt=key_keeper_release_cert(result);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-26 18:26:24 +08:00
|
|
|
|
ctx->downstream = ssl_stream_new(mgr, ctx->fd_downstream, CONN_DIR_DOWNSTREAM, NULL, crt);
|
|
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
ctx->bev_down = bufferevent_openssl_socket_new(ctx->evbase, ctx->fd_downstream, ctx->downstream->ssl,
|
|
|
|
|
|
BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS);
|
|
|
|
|
|
bufferevent_openssl_set_allow_dirty_shutdown(ctx->bev_down, 1);
|
|
|
|
|
|
|
|
|
|
|
|
promise_success(p, ctx);
|
2018-08-26 18:26:24 +08:00
|
|
|
|
key_keeper_free_keyring(crt);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
query_cert_ctx_free(ctx);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-08-26 18:26:24 +08:00
|
|
|
|
void ask_keyring_on_fail(enum e_future_error error, const char * what, void * user)
|
2018-08-26 14:30:26 +08:00
|
|
|
|
{
|
|
|
|
|
|
struct promise* p=(struct promise*)user;
|
2018-08-26 18:26:24 +08:00
|
|
|
|
struct ask_keyring_ctx * ctx = (struct ask_keyring_ctx *)promise_dettach_ctx(promise);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
promise_failed(p, error, what);
|
|
|
|
|
|
query_cert_ctx_free(ctx);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2018-08-26 18:26:24 +08:00
|
|
|
|
* Create a SSL stream for the incoming connection, based on the upstream.
|
2018-08-26 14:30:26 +08:00
|
|
|
|
*/
|
|
|
|
|
|
void ssl_async_downstream_create(struct future * f, struct ssl_mgr * mgr, struct ssl_stream * upstream, evutil_socket_t fd_downstream, int keyring_id, struct event_base * evbase)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
assert(upstream->dir == CONN_DIR_UPSTREAM);
|
|
|
|
|
|
|
2018-08-26 18:26:24 +08:00
|
|
|
|
struct ask_keyring_ctx * ctx = ALLOC(struct ask_keyring_ctx, 1);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
ctx->keyring_id = keyring_id;
|
|
|
|
|
|
ctx->ssl_mgr = mgr;
|
|
|
|
|
|
ctx->fd_downstream = fd_downstream;
|
|
|
|
|
|
ctx->evbase = evbase;
|
2018-08-26 18:26:24 +08:00
|
|
|
|
|
|
|
|
|
|
if(upstream!=NULL)
|
|
|
|
|
|
{
|
|
|
|
|
|
ctx->origin_ssl = upstream;
|
|
|
|
|
|
ctx->origin_crt = SSL_get_peer_certificate(upstream->ssl);
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
struct promise* p = future_to_promise(f);
|
|
|
|
|
|
promise_set_ctx(p, ctx, query_cert_ctx_free);
|
2018-08-26 18:26:24 +08:00
|
|
|
|
ctx->is_origin_crt_vaild=ssl_conn_verify_cert(mgr->trust_CA_store, upstream->ssl);
|
|
|
|
|
|
|
|
|
|
|
|
ctx->f_query_cert = future_create(ask_keyring_on_succ, ask_keyring_on_fail, p);
|
|
|
|
|
|
//todo add a is_valid_cert flag to keyring manager query API.
|
|
|
|
|
|
key_keeper_async_ask(ctx->f_query_cert, mgr->keeper_of_keys, keyring_id, ctx->origin_crt, ctx->is_origin_crt_vaild, evbase);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
return;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-24 10:55:47 +08:00
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* Cleanly shut down an SSL socket. Libevent currently has no support for
|
|
|
|
|
|
* cleanly shutting down an SSL socket so we work around that by using a
|
|
|
|
|
|
* low-level event. This works for recent versions of OpenSSL. OpenSSL
|
|
|
|
|
|
* with the older SSL_shutdown() semantics, not exposing WANT_READ/WRITE
|
|
|
|
|
|
* may or may not work.
|
|
|
|
|
|
*/
|
2018-08-26 18:26:24 +08:00
|
|
|
|
static struct ssl_shutdown_ctx * ssl_shutdown_ctx_new(struct ssl_stream * s_stream, struct event_base * evbase) {
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct ssl_shutdown_ctx * ctx = ALLOC(struct ssl_shutdown_ctx, 1);
|
2018-08-24 10:55:47 +08:00
|
|
|
|
ctx->evbase = evbase;
|
|
|
|
|
|
ctx->s_stream = s_stream;
|
|
|
|
|
|
ctx->ev = NULL;
|
|
|
|
|
|
ctx->retries = 0;
|
|
|
|
|
|
return ctx;
|
2018-08-26 18:26:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void ssl_shutdown_ctx_free(struct ssl_shutdown_ctx * ctx)
|
2018-08-24 10:55:47 +08:00
|
|
|
|
{
|
|
|
|
|
|
free(ctx);
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
|
2018-08-24 10:55:47 +08:00
|
|
|
|
/*
|
|
|
|
|
|
* The shutdown socket event handler. This is either
|
|
|
|
|
|
* scheduled as a timeout-only event, or as a fd read or
|
|
|
|
|
|
* fd write event, depending on whether SSL_shutdown()
|
|
|
|
|
|
* indicates it needs read or write on the socket.
|
|
|
|
|
|
*/
|
2018-08-26 14:30:26 +08:00
|
|
|
|
static void pxy_ssl_shutdown_cb(evutil_socket_t fd, UNUSED short what, void * arg)
|
2018-08-24 10:55:47 +08:00
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct ssl_shutdown_ctx * ctx = (struct ssl_shutdown_ctx *) arg;
|
|
|
|
|
|
|
|
|
|
|
|
struct timeval retry_delay = {
|
|
|
|
|
|
0, 100
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void * logger = ctx->s_stream->mgr->logger;
|
|
|
|
|
|
short want = 0;
|
|
|
|
|
|
int rv = 0, sslerr = 0;
|
2018-08-24 10:55:47 +08:00
|
|
|
|
|
|
|
|
|
|
if (ctx->ev) {
|
|
|
|
|
|
event_free(ctx->ev);
|
2018-08-26 14:30:26 +08:00
|
|
|
|
ctx->ev = NULL;
|
2018-08-24 10:55:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* Use the new (post-2008) semantics for SSL_shutdown() on a
|
|
|
|
|
|
* non-blocking socket. SSL_shutdown() returns -1 and WANT_READ
|
|
|
|
|
|
* if the other end's close notify was not received yet, and
|
|
|
|
|
|
* WANT_WRITE it could not write our own close notify.
|
|
|
|
|
|
*
|
|
|
|
|
|
* This is a good collection of recent and relevant documents:
|
|
|
|
|
|
* http://bugs.python.org/issue8108
|
|
|
|
|
|
*/
|
2018-08-26 14:30:26 +08:00
|
|
|
|
rv = SSL_shutdown(ctx->s_stream->ssl);
|
|
|
|
|
|
|
2018-08-24 10:55:47 +08:00
|
|
|
|
if (rv == 1)
|
|
|
|
|
|
goto complete;
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-24 10:55:47 +08:00
|
|
|
|
if (rv != -1) {
|
|
|
|
|
|
goto retry;
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
switch ((sslerr = SSL_get_error(ctx->s_stream->ssl, rv)))
|
|
|
|
|
|
{
|
2018-08-24 10:55:47 +08:00
|
|
|
|
case SSL_ERROR_WANT_READ:
|
|
|
|
|
|
want = EV_READ;
|
|
|
|
|
|
goto retry;
|
|
|
|
|
|
case SSL_ERROR_WANT_WRITE:
|
|
|
|
|
|
want = EV_WRITE;
|
|
|
|
|
|
goto retry;
|
|
|
|
|
|
case SSL_ERROR_ZERO_RETURN:
|
|
|
|
|
|
goto retry;
|
|
|
|
|
|
case SSL_ERROR_SYSCALL:
|
|
|
|
|
|
case SSL_ERROR_SSL:
|
|
|
|
|
|
goto complete;
|
|
|
|
|
|
default:
|
|
|
|
|
|
TFE_LOG_ERROR(logger, "Unhandled SSL_shutdown() "
|
2018-08-26 14:30:26 +08:00
|
|
|
|
"error %i. Closing fd.\n", sslerr);
|
2018-08-24 10:55:47 +08:00
|
|
|
|
goto complete;
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-24 10:55:47 +08:00
|
|
|
|
goto complete;
|
|
|
|
|
|
|
|
|
|
|
|
retry:
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-24 19:22:43 +08:00
|
|
|
|
if (ctx->retries++ >= MAX_NET_RETRIES) {
|
2018-08-26 14:30:26 +08:00
|
|
|
|
TFE_LOG_ERROR(logger, "Failed to shutdown SSL connection cleanly: "
|
|
|
|
|
|
"Max retries reached. Closing fd.\n");
|
2018-08-24 10:55:47 +08:00
|
|
|
|
goto complete;
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
ctx->ev = event_new(ctx->evbase, fd, want, pxy_ssl_shutdown_cb, ctx);
|
|
|
|
|
|
|
2018-08-24 10:55:47 +08:00
|
|
|
|
if (ctx->ev) {
|
|
|
|
|
|
event_add(ctx->ev, &retry_delay);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
TFE_LOG_ERROR(logger, "Failed to shutdown SSL connection cleanly: "
|
|
|
|
|
|
"Cannot create event. Closing fd.\n");
|
|
|
|
|
|
|
2018-08-24 10:55:47 +08:00
|
|
|
|
|
|
|
|
|
|
complete:
|
|
|
|
|
|
ssl_stream_free(ctx->s_stream);
|
|
|
|
|
|
evutil_closesocket(fd);
|
|
|
|
|
|
ssl_shutdown_ctx_free(ctx);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-26 14:30:26 +08:00
|
|
|
|
|
2018-08-24 10:55:47 +08:00
|
|
|
|
/*
|
|
|
|
|
|
* Cleanly shutdown an SSL session on file descriptor fd using low-level
|
|
|
|
|
|
* file descriptor readiness events on event base evbase.
|
|
|
|
|
|
* Guarantees that SSL and the corresponding SSL_CTX are freed and the
|
|
|
|
|
|
* socket is closed, eventually, or in the case of fatal errors, immediately.
|
|
|
|
|
|
*/
|
2018-08-26 14:30:26 +08:00
|
|
|
|
void ssl_stream_free_and_close_fd(struct ssl_stream * s_stream, struct event_base * evbase, evutil_socket_t fd)
|
2018-08-24 10:55:47 +08:00
|
|
|
|
{
|
2018-08-26 14:30:26 +08:00
|
|
|
|
struct ssl_shutdown_ctx * sslshutctx = NULL;
|
|
|
|
|
|
sslshutctx = ssl_shutdown_ctx_new(s_stream, evbase);
|
2018-08-24 10:55:47 +08:00
|
|
|
|
pxy_ssl_shutdown_cb(fd, 0, sslshutctx);
|
|
|
|
|
|
return;
|
2018-08-21 16:11:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-23 19:46:38 +08:00
|
|
|
|
|