1、增加证书校验;2、修改cert manager为key keeper。

This commit is contained in:
zhengchao
2018-08-26 18:26:24 +08:00
parent cf07c632fc
commit 5bb6a9c965
5 changed files with 246 additions and 152 deletions

View File

@@ -1,19 +0,0 @@
#ifndef CERT_H
#define CERT_H
#include <openssl/ssl.h>
#include <pthread.h>
struct cert
{
EVP_PKEY *key;
X509 *crt;
STACK_OF(X509) * chain;
};
struct cert_mgr;
struct cert_mgr * cert_mgr_init(const char * profile, const char* section);
struct cert* cert_mgr_query_result_release_cert(future_result_t* result);
void cert_mgr_free_cert(struct cert* cert);
void cert_mgr_async_query(struct future * future, struct cert_mgr * mgr, int keyring_id,
X509 * origin_cert, struct event_base * evbase);
#endif /* !CERT_H */

View File

@@ -0,0 +1,21 @@
#ifndef CERT_H
#define CERT_H
#include <openssl/ssl.h>
#include <pthread.h>
struct keyring
{
EVP_PKEY *key;
X509 *cert;
STACK_OF(X509) * chain;
};
struct key_keeper;
struct key_keeper * key_keeper_init(const char * profile, const char* section, void* logger);
struct key_keeper * key_keeper_destroy(struct key_keeper *keeper);
struct keyring* key_keeper_release_cert(future_result_t* result);
void key_keeper_free_keyring(struct keyring* cert);
void key_keeper_async_ask(struct future * f, struct key_keeper * keeper, int keyring_id,
X509 * origin_cert, int is_cert_valid, struct event_base * evbase);
#endif /* !CERT_H */

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include <event2/event.h> #include <event2/event.h>
#include <tfe_future.h> #include <tfe_future.h>
#include <cert.h>
#include <field_stat2.h> #include <field_stat2.h>

View File

@@ -1,21 +1,21 @@
#include <cert.h> #include <key_keeper.h>
#include <string.h> #include <string.h>
#include <ssl.h> #include <ssl.h>
struct cert_mgr struct key_keeper
{ {
}; };
struct tfe_cert_private struct key_keeper_private
{ {
struct cert head; struct keyring head;
pthread_mutex_t mutex; pthread_mutex_t mutex;
size_t references; size_t references;
}; };
#if 0 #if 0
/* /*
* Certificate, including private key and cert chain. * Certificate, including private key and keyring chain.
*/ */
cert_t * cert_t *
@@ -175,7 +175,7 @@ cert_set_chain(cert_t *c, STACK_OF(X509) *chain)
} }
/* /*
* Free cert including internal objects. * Free keyring including internal objects.
*/ */
void void
cert_free(cert_t *c) cert_free(cert_t *c)
@@ -200,22 +200,22 @@ cert_free(cert_t *c)
free(c); free(c);
} }
struct cert_mgr* cert_mgr_init(const char* profile) struct key_keeper* key_keeper_init(const char* profile)
{ {
} }
void cert_mgr_async_get(struct future* future, struct cert_mgr* mgr, int keyring_id, X509* origin_cert, struct event_base* evbase) void cert_mgr_async_get(struct future* future, struct key_keeper* mgr, int keyring_id, X509* origin_cert, struct event_base* evbase)
{ {
X509* orig_cert=SSL_get_peer_certificate(origssl); X509* orig_cert=SSL_get_peer_certificate(origssl);
//todo: need implement //todo: need implement
cert_t * cert = NULL; cert_t * keyring = NULL;
if (opts->tgcrtdir) if (opts->tgcrtdir)
{ {
if (ctx->sni) if (ctx->sni)
{ {
cert = (cert_t *) cachemgr_tgcrt_get(ctx->sni); keyring = (cert_t *) cachemgr_tgcrt_get(ctx->sni);
if (!cert) if (!keyring)
{ {
char * wildcarded = ssl_wildcardify(ctx->sni); char * wildcarded = ssl_wildcardify(ctx->sni);
if (!wildcarded) if (!wildcarded)
@@ -223,12 +223,12 @@ void cert_mgr_async_get(struct future* future, struct cert_mgr* mgr, int keyring
ctx->enomem = 1; ctx->enomem = 1;
return NULL; return NULL;
} }
cert = (cert_t *) cachemgr_tgcrt_get(wildcarded); keyring = (cert_t *) cachemgr_tgcrt_get(wildcarded);
free(wildcarded); free(wildcarded);
} }
if (cert && OPTS_DEBUG(ctx->opts)) if (keyring && OPTS_DEBUG(ctx->opts))
{ {
log_dbg_printf("Target cert by SNI\n"); log_dbg_printf("Target keyring by SNI\n");
} }
} }
else if (ctx->origcrt) else if (ctx->origcrt)
@@ -236,11 +236,11 @@ void cert_mgr_async_get(struct future* future, struct cert_mgr* mgr, int keyring
char ** names = ssl_x509_names(ctx->origcrt); char ** names = ssl_x509_names(ctx->origcrt);
for (char ** p = names; *p; p++) for (char ** p = names; *p; p++)
{ {
if (!cert) if (!keyring)
{ {
cert = (cert_t *) cachemgr_tgcrt_get(*p); keyring = (cert_t *) cachemgr_tgcrt_get(*p);
} }
if (!cert) if (!keyring)
{ {
char * wildcarded = ssl_wildcardify(*p); char * wildcarded = ssl_wildcardify(*p);
if (!wildcarded) if (!wildcarded)
@@ -249,7 +249,7 @@ void cert_mgr_async_get(struct future* future, struct cert_mgr* mgr, int keyring
} }
else else
{ {
cert = (cert_t *) (wildcarded); keyring = (cert_t *) (wildcarded);
free(wildcarded); free(wildcarded);
} }
} }
@@ -260,41 +260,41 @@ void cert_mgr_async_get(struct future* future, struct cert_mgr* mgr, int keyring
{ {
return NULL; return NULL;
} }
if (cert && OPTS_DEBUG(ctx->opts)) if (keyring && OPTS_DEBUG(ctx->opts))
{ {
log_dbg_printf("Target cert by origcrt\n"); log_dbg_printf("Target keyring by origcrt\n");
} }
} }
if (cert) if (keyring)
{ {
ctx->immutable_cert = 1; ctx->immutable_cert = 1;
} }
} }
if (!cert && ctx->origcrt && ctx->opts->key) if (!keyring && ctx->origcrt && ctx->opts->key)
{ {
cert = cert_new(); keyring = cert_new();
cert->crt = (X509 *) cachemgr_fkcrt_get(ctx->origcrt); keyring->cert = (X509 *) cachemgr_fkcrt_get(ctx->origcrt);
if (cert->crt) if (keyring->cert)
{ {
if (OPTS_DEBUG(ctx->opts)) log_dbg_printf("Certificate cache: HIT\n"); if (OPTS_DEBUG(ctx->opts)) log_dbg_printf("Certificate cache: HIT\n");
} }
else else
{ {
if (OPTS_DEBUG(ctx->opts)) log_dbg_printf("Certificate cache: MISS\n"); if (OPTS_DEBUG(ctx->opts)) log_dbg_printf("Certificate cache: MISS\n");
cert->crt = ssl_x509_forge(ctx->opts->cacrt, keyring->cert = ssl_x509_forge(ctx->opts->cacrt,
ctx->opts->cakey, ctx->opts->cakey,
ctx->origcrt, ctx->origcrt,
ctx->opts->key, ctx->opts->key,
NULL, NULL,
ctx->opts->crlurl); ctx->opts->crlurl);
cachemgr_fkcrt_set(ctx->origcrt, cert->crt); cachemgr_fkcrt_set(ctx->origcrt, keyring->cert);
} }
cert_set_key(cert, ctx->opts->key); cert_set_key(keyring, ctx->opts->key);
cert_set_chain(cert, ctx->opts->chain); cert_set_chain(keyring, ctx->opts->chain);
ctx->generated_cert = 1; ctx->generated_cert = 1;
} }
@@ -306,18 +306,18 @@ void cert_mgr_async_get(struct future* future, struct cert_mgr* mgr, int keyring
} }
if ((WANT_CONNECT_LOG(ctx) || ctx->opts->certgen_writeall) && if ((WANT_CONNECT_LOG(ctx) || ctx->opts->certgen_writeall) &&
cert && cert->crt) keyring && keyring->cert)
{ {
ctx->usedcrtfpr = ssl_x509_fingerprint(cert->crt, 0); ctx->usedcrtfpr = ssl_x509_fingerprint(keyring->cert, 0);
if (!ctx->usedcrtfpr) if (!ctx->usedcrtfpr)
ctx->enomem = 1; ctx->enomem = 1;
} }
return cert; return keyring;
} }
void cert_manager_free(cert_t * cert) void cert_manager_free(cert_t * keyring)
{ {
cert_free(cert); cert_free(keyring);
return; return;
} }
#endif #endif

View File

@@ -32,7 +32,7 @@
#include <tfe_utils.h> #include <tfe_utils.h>
#include <tfe_future.h> #include <tfe_future.h>
#include <stream.h> #include <stream.h>
#include <cert.h> #include <key_keeper.h>
#include <ssl_sess_cache.h> #include <ssl_sess_cache.h>
#include <ssl.h> #include <ssl.h>
#include <MESA_htable.h> #include <MESA_htable.h>
@@ -55,22 +55,32 @@ struct ssl_mgr {
int sess_expire_seconds; int sess_expire_seconds;
struct sess_cache * down_sess_cache; struct sess_cache * down_sess_cache;
struct sess_cache * up_sess_cache; struct sess_cache * up_sess_cache;
char * default_ciphers[TFE_SYMBOL_MAX]; char default_ciphers[TFE_STRING_MAX];
DH * dh; DH * dh;
char * ecdhcurve; char * ecdhcurve;
char * crlurl; char * crlurl;
uint8_t SSL_MODE_RELEASE_BUFFERS; uint8_t SSL_MODE_RELEASE_BUFFERS;
void * logger; void * logger;
struct cert_mgr * cert_mgr; 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;
}; };
struct __ssl_stream_debug
{
evutil_socket_t fd;
};
struct ssl_stream { struct ssl_stream {
enum tfe_conn_dir dir; enum tfe_conn_dir dir;
SSL * ssl; SSL * ssl;
struct ssl_mgr * mgr; struct ssl_mgr * mgr;
struct ssl_chello * client_hello; union
struct ssl_stream* peer; {
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;
}; };
@@ -106,10 +116,11 @@ struct ssl_connect_origin_ctx {
}; };
struct query_cert_ctx { struct ask_keyring_ctx {
int keyring_id; int keyring_id;
struct ssl_stream * origin_ssl; struct ssl_stream * origin_ssl;
X509 * origin_crt; X509 * origin_crt;
int is_origin_crt_vaild;
struct ssl_mgr * ssl_mgr; struct ssl_mgr * ssl_mgr;
evutil_socket_t fd_downstream; evutil_socket_t fd_downstream;
struct event_base * evbase; struct event_base * evbase;
@@ -130,12 +141,30 @@ struct ssl_shutdown_ctx {
unsigned int retries; unsigned int retries;
}; };
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 ssl_stream * ssl_stream_create(struct ssl_chello * client_hello, struct ssl_mgr * mgr, struct sockaddr * addr, {
socklen_t addrlen) { struct sockaddr addr;
socklen_t addrlen;
int ret=0;
struct ssl_stream * s_stream = ALLOC(struct ssl_stream, 1); struct ssl_stream * s_stream = ALLOC(struct ssl_stream, 1);
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; s_stream->client_hello=client_hello;
s_stream->ssl = upstream_ssl_create(mgr, client_hello, addr, addrlen); break;
default:
assert(0);
}
return s_stream; return s_stream;
} }
@@ -144,9 +173,24 @@ static void ssl_stream_free(struct ssl_stream * s_stream)
{ {
SSL_free(s_stream->ssl); SSL_free(s_stream->ssl);
s_stream->ssl = NULL; s_stream->ssl = NULL;
switch (s_stream->dir)
if (s_stream->client_hello != NULL) { {
ssl_free_chello(s_stream->client_hello;); 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);
} }
s_stream->mgr = NULL; s_stream->mgr = NULL;
@@ -166,19 +210,24 @@ static int sslver_str2num(const char * version_str)
* SSLv2_server_method() and SSLv2_client_method() functions were * SSLv2_server_method() and SSLv2_client_method() functions were
* removed in OpenSSL 1.1.0. * removed in OpenSSL 1.1.0.
*/ */
if (!strcmp(version_str, "ssl3")) { if (!strcmp(version_str, "ssl3"))
{
sslversion = SSL3_VERSION; sslversion = SSL3_VERSION;
} }
else if (!strcmp(version_str, "tls10") || !strcmp(version_str, "tls1")) { else if (!strcmp(version_str, "tls10") || !strcmp(version_str, "tls1"))
{
sslversion = TLS1_VERSION; sslversion = TLS1_VERSION;
} }
else if (!strcmp(version_str, "tls11")) { else if (!strcmp(version_str, "tls11"))
{
sslversion = TLS1_1_VERSION; sslversion = TLS1_1_VERSION;
} }
else if (!strcmp(version_str, "tls12")) { else if (!strcmp(version_str, "tls12"))
{
sslversion = TLS1_2_VERSION; sslversion = TLS1_2_VERSION;
} }
else { else
{
sslversion = -1; sslversion = -1;
} }
@@ -188,6 +237,15 @@ static int sslver_str2num(const char * version_str)
void ssl_manager_destroy(struct ssl_mgr * mgr) void ssl_manager_destroy(struct ssl_mgr * mgr)
{ {
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;
}
free(mgr); free(mgr);
} }
@@ -220,34 +278,70 @@ struct ssl_mgr * ssl_manager_init(const char * ini_profile, const char * section
mgr->up_sess_cache = ssl_sess_cache_create(mgr->cache_slot_num, mgr->sess_expire_seconds, CONN_DIR_UPSTREAM); 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); mgr->down_sess_cache = ssl_sess_cache_create(mgr->cache_slot_num, mgr->sess_expire_seconds, CONN_DIR_DOWNSTREAM);
mgr->cert_mgr = cert_mgr_init(ini_profile, section);
if (mgr->cert_mgr == NULL) {
mgr->keeper_of_keys = key_keeper_init(ini_profile, section, logger);
if (mgr->keeper_of_keys == NULL)
{
TFE_LOG_ERROR(logger, "Certificate Manager initiate failed."); TFE_LOG_ERROR(logger, "Certificate Manager initiate failed.");
goto error_out; goto error_out;
} }
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), "");
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;
}
memcpy(mgr->ssl_session_context, "mesa-tfe", sizeof(mgr->ssl_session_context)); memcpy(mgr->ssl_session_context, "mesa-tfe", sizeof(mgr->ssl_session_context));
return mgr; return mgr;
error_out: error_out:
ssl_manager_destroy(mgr); ssl_manager_destroy(mgr);
return NULL; return NULL;
} void peek_client_hello_ctx_free(void * ctx) }
int ssl_conn_verify_cert(X509_STORE *store, const SSL * ssl)
{ {
struct peek_client_hello_ctx * _ctx = (struct peek_client_hello_ctx *) int ret=0;
ctx; 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)
{
struct peek_client_hello_ctx * _ctx = (struct peek_client_hello_ctx *)ctx;
event_free(_ctx->ev); event_free(_ctx->ev);
_ctx->ev = NULL; _ctx->ev = NULL;
free(_ctx->chello.sni); free(_ctx->chello.sni);
@@ -259,10 +353,10 @@ error_out:
} }
struct ssl_chello * ssl_peek_result_release_chello(future_result_t * result) { struct ssl_chello * ssl_peek_result_release_chello(future_result_t * result)
struct ssl_chello * p = (struct ssl_chello *) {
result, *copy = NULL; struct ssl_chello * p = (struct ssl_chello *)result, *copy = NULL;
copy = ALLOC(struct ssl_chello *, 1); copy = ALLOC(struct ssl_chello, 1);
if (p != NULL) { if (p != NULL) {
copy->sni = tfe_strdup(p->sni); copy->sni = tfe_strdup(p->sni);
@@ -270,7 +364,6 @@ struct ssl_chello * ssl_peek_result_release_chello(future_result_t * result) {
copy->version = p->version; copy->version = p->version;
} }
return copy; return copy;
} void ssl_free_chello(struct ssl_chello * p) } void ssl_free_chello(struct ssl_chello * p)
{ {
@@ -290,6 +383,7 @@ struct ssl_chello * ssl_peek_result_release_chello(future_result_t * result) {
static void peek_client_hello_cb(evutil_socket_t fd, short what, void * arg) static void peek_client_hello_cb(evutil_socket_t fd, short what, void * arg)
{ {
struct promise * promise = (struct promise *)arg; struct promise * promise = (struct promise *)arg;
//use promise_get_ctx instead of promise_dettach_ctx for try more times.
struct peek_client_hello_ctx * ctx = (struct peek_client_hello_ctx *)promise_get_ctx(promise); 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_too_many_retries = "too many tries";
const char * reason_see_no_client_hello = "see no client hello"; const char * reason_see_no_client_hello = "see no client hello";
@@ -358,7 +452,6 @@ failed:
promise_dettach_ctx(promise); promise_dettach_ctx(promise);
promise_failed(promise, FUTURE_ERROR_EXCEPTION, reason); promise_failed(promise, FUTURE_ERROR_EXCEPTION, reason);
peek_client_hello_ctx_free(ctx); peek_client_hello_ctx_free(ctx);
ssl_free_chello(result);
return; return;
} }
@@ -382,8 +475,7 @@ static void ssl_async_peek_client_hello(struct future * future, evutil_socket_t
* Create new SSL context for outgoing connections to the original destination. * Create new SSL context for outgoing connections to the original destination.
* If hostname sni is provided, use it for Server Name Indication. * If hostname sni is provided, use it for Server Name Indication.
*/ */
static SSL * upstream_ssl_create(struct ssl_mgr * mgr, const struct ssl_chello * chello, struct sockaddr * addr, static SSL * upstream_ssl_create(struct ssl_mgr * mgr, const struct ssl_chello * chello, evutil_socket_t fd)
socklen_t addrlen)
{ {
SSL_CTX * sslctx = NULL; SSL_CTX * sslctx = NULL;
SSL * ssl = NULL; SSL * ssl = NULL;
@@ -429,17 +521,18 @@ static SSL * upstream_ssl_create(struct ssl_mgr * mgr, const struct ssl_chello *
SSL_set_mode(ssl, SSL_get_mode(ssl) | SSL_MODE_RELEASE_BUFFERS); SSL_set_mode(ssl, SSL_get_mode(ssl) | SSL_MODE_RELEASE_BUFFERS);
#endif /* SSL_MODE_RELEASE_BUFFERS */ #endif /* SSL_MODE_RELEASE_BUFFERS */
//Todo: Refactor below session resumption. struct sockaddr addr;
socklen_t addrlen;
int ret=0;
ret = getpeername(fd , &addr, &addrlen);
assert(ret==0);
/* session resuming based on remote endpoint address and port */ /* session resuming based on remote endpoint address and port */
sess = up_session_get(mgr->up_sess_cache, addr, sess = up_session_get(mgr->up_sess_cache, &addr, addrlen, chello->sni); /* new sess insert */
addrlen, chello->sni); /* new sess inst */ if (sess)
{
if (sess) {
SSL_set_session(ssl, sess); /* increments sess refcount */ SSL_set_session(ssl, sess); /* increments sess refcount */
SSL_SESSION_free(sess); SSL_SESSION_free(sess);
} }
return ssl; return ssl;
} }
@@ -520,7 +613,7 @@ static void peek_chello_on_succ(future_result_t * result, void * user)
struct ssl_connect_origin_ctx * ctx = (struct ssl_connect_origin_ctx *) promise_dettach_ctx(p); 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. struct ssl_chello * chello = ssl_peek_result_release_chello(result);//chello has been saved in ssl_stream.
ctx->s_stream = ssl_stream_create(chello, ctx->mgr, & (ctx->addr), ctx->addrlen); ctx->s_stream = ssl_stream_new(ctx->mgr, ctx->fd_upstream, CONN_DIR_UPSTREAM, chello, NULL);
ctx->bev = bufferevent_openssl_socket_new(ctx->evbase, ctx->fd_upstream, ctx->s_stream, ctx->bev = bufferevent_openssl_socket_new(ctx->evbase, ctx->fd_upstream, ctx->s_stream,
BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS); BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS);
bufferevent_openssl_set_allow_dirty_shutdown(ctx->bev, 1); bufferevent_openssl_set_allow_dirty_shutdown(ctx->bev, 1);
@@ -718,15 +811,15 @@ static void sslctx_set_opts(SSL_CTX * sslctx, struct ssl_mgr * mgr)
/* /*
* Create and set up a new SSL_CTX instance for terminating SSL. * Create and set up a new SSL_CTX instance for terminating SSL.
* Set up all the necessary callbacks, the cert, the cert chain and key. * Set up all the necessary callbacks, the keyring, the keyring chain and key.
*/ */
static SSL_CTX * down_sslctx_create(struct ssl_mgr * mgr, struct cert * crt) static SSL* downstream_ssl_create(struct ssl_mgr * mgr, struct keyring * crt)
{ {
SSL_CTX * sslctx = SSL_CTX_new(mgr->sslmethod()); SSL_CTX * sslctx = SSL_CTX_new(mgr->sslmethod());
if (!sslctx) if (!sslctx)
return NULL; return NULL;
SSL* ssl=NULL;
int ret=0;
sslctx_set_opts(sslctx, mgr); sslctx_set_opts(sslctx, mgr);
//TFE's OPENSSL_VERSION_NUMBER >= 0x10100000L //TFE's OPENSSL_VERSION_NUMBER >= 0x10100000L
@@ -771,7 +864,7 @@ static SSL_CTX * down_sslctx_create(struct ssl_mgr * mgr, struct cert * crt)
#endif /* !OPENSSL_NO_ECDH */ #endif /* !OPENSSL_NO_ECDH */
SSL_CTX_use_certificate(sslctx, crt->crt); SSL_CTX_use_certificate(sslctx, crt->cert);
SSL_CTX_use_PrivateKey(sslctx, crt->key); SSL_CTX_use_PrivateKey(sslctx, crt->key);
for (int i = 0; i < sk_X509_num(crt->chain); i++) { for (int i = 0; i < sk_X509_num(crt->chain); i++) {
@@ -779,12 +872,23 @@ static SSL_CTX * down_sslctx_create(struct ssl_mgr * mgr, struct cert * crt)
ssl_x509_refcount_inc(c); /* next call consumes a reference */ ssl_x509_refcount_inc(c); /* next call consumes a reference */
SSL_CTX_add_extra_chain_cert(sslctx, c); SSL_CTX_add_extra_chain_cert(sslctx, c);
} }
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);
return sslctx; 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);
}
return ssl;
} }
void query_cert_ctx_free(struct query_cert_ctx * ctx) void query_cert_ctx_free(struct ask_keyring_ctx * ctx)
{ {
X509_free(ctx->origin_crt); X509_free(ctx->origin_crt);
@@ -805,67 +909,51 @@ void query_cert_ctx_free(struct query_cert_ctx * ctx)
struct ssl_stream* ssl_downstream_create_result_release_stream(future_result_t* result) struct ssl_stream* ssl_downstream_create_result_release_stream(future_result_t* result)
{ {
struct query_cert_ctx * ctx = (struct query_cert_ctx *)result; struct ask_keyring_ctx * ctx = (struct ask_keyring_ctx *)result;
struct ssl_stream* ret=ctx->downstream; struct ssl_stream* ret=ctx->downstream;
ctx->downstream=NULL; ctx->downstream=NULL;
return ret; return ret;
} }
struct bufferevent* ssl_downstream_create_result_release_bev(future_result_t* result) struct bufferevent* ssl_downstream_create_result_release_bev(future_result_t* result)
{ {
struct query_cert_ctx * ctx = (struct query_cert_ctx *)result; struct ask_keyring_ctx * ctx = (struct ask_keyring_ctx *)result;
struct bufferevent* ret=ctx->bev_down; struct bufferevent* ret=ctx->bev_down;
ctx->bev_down=NULL; ctx->bev_down=NULL;
return ret; return ret;
} }
void query_cert_on_succ(void * result, void * user) void ask_keyring_on_succ(void * result, void * user)
{ {
struct promise* p=(struct promise*)user; struct promise* p=(struct promise*)user;
struct query_cert_ctx * ctx = (struct query_cert_ctx *)promise_dettach_ctx(promise); struct ask_keyring_ctx * ctx = (struct ask_keyring_ctx *)promise_dettach_ctx(promise);
struct ssl_stream * downstream = NULL; struct ssl_stream * downstream = NULL;
struct cert* crt=NULL; struct keyring* crt=NULL;
SSL_CTX * sslctx=NULL;
struct ssl_mgr* mgr=ctx->ssl_mgr; struct ssl_mgr* mgr=ctx->ssl_mgr;
future_destroy(ctx->f_query_cert); future_destroy(ctx->f_query_cert);
ctx->f_query_cert=NULL; ctx->f_query_cert=NULL;
crt=cert_mgr_query_result_release_cert(result); crt=key_keeper_release_cert(result);
sslctx = down_sslctx_create(mgr, crt);
assert(sslctx!=NULL);
downstream = ALLOC(struct ssl_stream, 1); ctx->downstream = ssl_stream_new(mgr, ctx->fd_downstream, CONN_DIR_DOWNSTREAM, NULL, crt);
downstream->mgr = mgr;
downstream->dir = CONN_DIR_DOWNSTREAM;
downstream->ssl = SSL_new(sslctx);
downstream->peer = ctx->origin_ssl;
ctx->origin_ssl->peer= downstream;
int ret = SSL_set_ex_data(downstream->ssl, SSL_EX_DATA_IDX_SSLMGR, mgr);
assert(ret == 1);
SSL_CTX_free(sslctx); /* SSL_new() increments refcount */
if (mgr->SSL_MODE_RELEASE_BUFFERS == 1) {
/* lower memory footprint for idle connections */
SSL_set_mode(downstream->ssl, SSL_get_mode(downstream->ssl) | SSL_MODE_RELEASE_BUFFERS);
}
ctx->downstream = downstream;
ctx->bev_down = bufferevent_openssl_socket_new(ctx->evbase, ctx->fd_downstream, ctx->downstream->ssl, ctx->bev_down = bufferevent_openssl_socket_new(ctx->evbase, ctx->fd_downstream, ctx->downstream->ssl,
BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS); BUFFEREVENT_SSL_CONNECTING, BEV_OPT_DEFER_CALLBACKS);
bufferevent_openssl_set_allow_dirty_shutdown(ctx->bev_down, 1); bufferevent_openssl_set_allow_dirty_shutdown(ctx->bev_down, 1);
promise_success(p, ctx); promise_success(p, ctx);
cert_mgr_free_cert(crt); key_keeper_free_keyring(crt);
query_cert_ctx_free(ctx); query_cert_ctx_free(ctx);
return; return;
} }
void query_cert_on_fail(enum e_future_error error, const char * what, void * user) void ask_keyring_on_fail(enum e_future_error error, const char * what, void * user)
{ {
struct promise* p=(struct promise*)user; struct promise* p=(struct promise*)user;
struct query_cert_ctx * ctx = (struct query_cert_ctx *)promise_dettach_ctx(promise); struct ask_keyring_ctx * ctx = (struct ask_keyring_ctx *)promise_dettach_ctx(promise);
promise_failed(p, error, what); promise_failed(p, error, what);
query_cert_ctx_free(ctx); query_cert_ctx_free(ctx);
return; return;
@@ -873,26 +961,32 @@ void query_cert_on_fail(enum e_future_error error, const char * what, void * use
/* /*
* Create a SSL stream for the incoming connection, based on the a upstream. * Create a SSL stream for the incoming connection, based on the upstream.
*/ */
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) 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); assert(upstream->dir == CONN_DIR_UPSTREAM);
struct query_cert_ctx * ctx = ALLOC(struct query_cert_ctx, 1); struct ask_keyring_ctx * ctx = ALLOC(struct ask_keyring_ctx, 1);
ctx->keyring_id = keyring_id; ctx->keyring_id = keyring_id;
ctx->origin_ssl = upstream;
ctx->origin_crt = SSL_get_peer_certificate(upstream->ssl);
ctx->ssl_mgr = mgr; ctx->ssl_mgr = mgr;
ctx->fd_downstream = fd_downstream; ctx->fd_downstream = fd_downstream;
ctx->evbase = evbase; ctx->evbase = evbase;
if(upstream!=NULL)
{
ctx->origin_ssl = upstream;
ctx->origin_crt = SSL_get_peer_certificate(upstream->ssl);
}
struct promise* p = future_to_promise(f); struct promise* p = future_to_promise(f);
promise_set_ctx(p, ctx, query_cert_ctx_free); promise_set_ctx(p, ctx, query_cert_ctx_free);
//todo: verify original certificate. ctx->is_origin_crt_vaild=ssl_conn_verify_cert(mgr->trust_CA_store, upstream->ssl);
ctx->f_query_cert = future_create(query_cert_on_succ, query_cert_on_fail, p);
cert_mgr_async_query(ctx->f_query_cert, mgr->cert_mgr, keyring_id, ctx->origin_crt, evbase); 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);
return; return;
} }
@@ -904,17 +998,16 @@ void ssl_async_downstream_create(struct future * f, struct ssl_mgr * mgr, struct
* with the older SSL_shutdown() semantics, not exposing WANT_READ/WRITE * with the older SSL_shutdown() semantics, not exposing WANT_READ/WRITE
* may or may not work. * may or may not work.
*/ */
static static struct ssl_shutdown_ctx * ssl_shutdown_ctx_new(struct ssl_stream * s_stream, struct event_base * evbase) {
struct ssl_shutdown_ctx * ssl_shutdown_ctx_new(struct ssl_stream * s_stream, struct event_base * evbase) {
struct ssl_shutdown_ctx * ctx = ALLOC(struct ssl_shutdown_ctx, 1); struct ssl_shutdown_ctx * ctx = ALLOC(struct ssl_shutdown_ctx, 1);
ctx->evbase = evbase; ctx->evbase = evbase;
ctx->s_stream = s_stream; ctx->s_stream = s_stream;
ctx->ev = NULL; ctx->ev = NULL;
ctx->retries = 0; ctx->retries = 0;
return ctx; return ctx;
} static void ssl_shutdown_ctx_free(struct ssl_shutdown_ctx * ctx) }
static void ssl_shutdown_ctx_free(struct ssl_shutdown_ctx * ctx)
{ {
free(ctx); free(ctx);
} }