2363 lines
65 KiB
C
2363 lines
65 KiB
C
/**
|
|
* Copyright (c) 2021 OceanBase
|
|
* OceanBase CE is licensed under Mulan PubL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
* You may obtain a copy of Mulan PubL v2 at:
|
|
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PubL v2 for more details.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <pthread.h>
|
|
#include "io/easy_ssl.h"
|
|
#include "io/easy_log.h"
|
|
#include "io/easy_connection.h"
|
|
|
|
int easy_ssl_connection_index = -1;
|
|
easy_atomic_t* easy_ssl_lock_cs = NULL;
|
|
extern __thread easy_baseth_t* easy_baseth_self;
|
|
extern char* easy_connection_str(easy_connection_t* c);
|
|
static void easy_ssl_info_callback(const SSL* s, int where, int ret);
|
|
static int easy_ssl_handshake(easy_connection_t* c);
|
|
static void easy_ssl_connection_handshake_handler(easy_connection_t* c);
|
|
static void easy_ssl_handshake_handler(struct ev_loop* loop, ev_io* w, int revents);
|
|
static void easy_ssl_clear_error();
|
|
static void easy_ssl_error(int level, char* fmt, ...);
|
|
static ssize_t easy_ssl_read(easy_connection_t* c, char* buf, size_t size, int* pending);
|
|
static ssize_t easy_ssl_write(easy_connection_t* c, easy_list_t* l);
|
|
static void easy_ssl_connection_error(easy_connection_t* c, int sslerr, int err, char* text);
|
|
static int easy_ssl_server_create(easy_ssl_t* ssl, easy_ssl_ctx_t* ss);
|
|
static int easy_ssl_parse_set_value(easy_ssl_ctx_t* ss, char* key, char* value);
|
|
static int easy_ssl_ctx_create(easy_ssl_ctx_t* ssl);
|
|
static int easy_ssl_ctx_create_for_mysql(easy_ssl_ctx_t* ssl, const int is_babassl); // compat for mysql
|
|
static int easy_ssl_certificate(easy_ssl_ctx_t* ssl, const char* cert, const char* key);
|
|
static int easy_ssl_certificate_for_mysql(easy_ssl_ctx_t* ssl, const char* cert, const char* key);
|
|
static int easy_ssl_certificate_for_mysql_memory(easy_ssl_ctx_t* ssl, const char* cert, const char* key);
|
|
static int easy_ssl_generate_rsa512_key(easy_ssl_ctx_t* ssl);
|
|
static int easy_ssl_dhparam(easy_ssl_ctx_t* ssl, char* file);
|
|
static int easy_ssl_dhparam_mysql(easy_ssl_ctx_t* ssl);
|
|
static int easy_ssl_session_cache(easy_ssl_ctx_t* ssl, int session_cache, int timeout);
|
|
static int easy_ssl_client_certificate(easy_ssl_ctx_t* ssl, char* cert, int depth);
|
|
static int easy_ssl_client_certificate_for_mysql(easy_ssl_ctx_t* ssl, const char* cert, int depth);
|
|
static int easy_ssl_client_certificate_for_mysql_memory(easy_ssl_ctx_t* ssl, const char* cert);
|
|
static int easy_ssl_crl(easy_ssl_ctx_t* ssl, char* crl);
|
|
static int easy_ssl_handle_recv(easy_connection_t* c, ssize_t n);
|
|
static void easy_ssl_client_handshake_handler(easy_connection_t* c);
|
|
static int easy_ssl_ctx_server_cmp(const void* a, const void* b);
|
|
static int easy_ssl_pass_phrase_cb(char* buf, int size, int rwflag, void* conf);
|
|
// static void test_info_callback(const SSL *ssl,int type,int val);
|
|
|
|
const char tls_ciphers_list[] = "!aNULL:!eNULL:!EXPORT:!LOW:!MD5:!DES:!RC2:!RC4:!PSK:"
|
|
"!DHE-DSS-DES-CBC3-SHA:!DHE-RSA-DES-CBC3-SHA:"
|
|
"!ECDH-RSA-DES-CBC3-SHA:!ECDH-ECDSA-DES-CBC3-SHA:"
|
|
"!ECDHE-RSA-DES-CBC3-SHA:!ECDHE-ECDSA-DES-CBC3-SHA:"
|
|
"ECDHE-ECDSA-AES128-GCM-SHA256:"
|
|
"ECDHE-ECDSA-AES256-GCM-SHA384:"
|
|
"ECDHE-RSA-AES128-GCM-SHA256:"
|
|
"ECDHE-RSA-AES256-GCM-SHA384:"
|
|
"ECDHE-ECDSA-AES128-SHA256:"
|
|
"ECDHE-RSA-AES128-SHA256:"
|
|
"ECDHE-ECDSA-AES256-SHA384:"
|
|
"ECDHE-RSA-AES256-SHA384:"
|
|
"DHE-RSA-AES128-GCM-SHA256:"
|
|
"DHE-DSS-AES128-GCM-SHA256:"
|
|
"DHE-RSA-AES128-SHA256:"
|
|
"DHE-DSS-AES128-SHA256:"
|
|
"DHE-DSS-AES256-GCM-SHA384:"
|
|
"DHE-RSA-AES256-SHA256:"
|
|
"DHE-DSS-AES256-SHA256:"
|
|
"ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:"
|
|
"ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:"
|
|
"DHE-DSS-AES128-SHA:DHE-RSA-AES128-SHA:"
|
|
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA:DHE-RSA-AES256-SHA:"
|
|
"AES128-GCM-SHA256:DH-DSS-AES128-GCM-SHA256:"
|
|
"ECDH-ECDSA-AES128-GCM-SHA256:AES256-GCM-SHA384:"
|
|
"DH-DSS-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:"
|
|
"AES128-SHA256:DH-DSS-AES128-SHA256:ECDH-ECDSA-AES128-SHA256:AES256-SHA256:"
|
|
"DH-DSS-AES256-SHA256:ECDH-ECDSA-AES256-SHA384:AES128-SHA:"
|
|
"DH-DSS-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES256-SHA:"
|
|
"DH-DSS-AES256-SHA:ECDH-ECDSA-AES256-SHA:DHE-RSA-AES256-GCM-SHA384:"
|
|
"DH-RSA-AES128-GCM-SHA256:ECDH-RSA-AES128-GCM-SHA256:DH-RSA-AES256-GCM-SHA384:"
|
|
"ECDH-RSA-AES256-GCM-SHA384:DH-RSA-AES128-SHA256:"
|
|
"ECDH-RSA-AES128-SHA256:DH-RSA-AES256-SHA256:"
|
|
"ECDH-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:"
|
|
"ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA:"
|
|
"ECDHE-ECDSA-AES256-SHA:DHE-DSS-AES128-SHA:DHE-RSA-AES128-SHA:"
|
|
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA:DHE-RSA-AES256-SHA:"
|
|
"AES128-SHA:DH-DSS-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES256-SHA:"
|
|
"DH-DSS-AES256-SHA:ECDH-ECDSA-AES256-SHA:DH-RSA-AES128-SHA:"
|
|
"ECDH-RSA-AES128-SHA:DH-RSA-AES256-SHA:ECDH-RSA-AES256-SHA:DES-CBC3-SHA";
|
|
const char baba_tls_ciphers_list[] = "!aNULL:!eNULL:!EXPORT:!LOW:!MD5:!DES:!RC2:!RC4:!PSK:"
|
|
"!DHE-DSS-DES-CBC3-SHA:!DHE-RSA-DES-CBC3-SHA:"
|
|
"!ECDH-RSA-DES-CBC3-SHA:!ECDH-ECDSA-DES-CBC3-SHA:"
|
|
"!ECDHE-RSA-DES-CBC3-SHA:!ECDHE-ECDSA-DES-CBC3-SHA:"
|
|
"ECC-SM2-WITH-SM4-SM3:ECDHE-SM2-WITH-SM4-SM3:"
|
|
"ECDHE-ECDSA-AES128-GCM-SHA256:"
|
|
"ECDHE-ECDSA-AES256-GCM-SHA384:"
|
|
"ECDHE-RSA-AES128-GCM-SHA256:"
|
|
"ECDHE-RSA-AES256-GCM-SHA384:"
|
|
"ECDHE-ECDSA-AES128-SHA256:"
|
|
"ECDHE-RSA-AES128-SHA256:"
|
|
"ECDHE-ECDSA-AES256-SHA384:"
|
|
"ECDHE-RSA-AES256-SHA384:"
|
|
"DHE-RSA-AES128-GCM-SHA256:"
|
|
"DHE-DSS-AES128-GCM-SHA256:"
|
|
"DHE-RSA-AES128-SHA256:"
|
|
"DHE-DSS-AES128-SHA256:"
|
|
"DHE-DSS-AES256-GCM-SHA384:"
|
|
"DHE-RSA-AES256-SHA256:"
|
|
"DHE-DSS-AES256-SHA256:"
|
|
"ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:"
|
|
"ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:"
|
|
"DHE-DSS-AES128-SHA:DHE-RSA-AES128-SHA:"
|
|
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA:DHE-RSA-AES256-SHA:"
|
|
"AES128-GCM-SHA256:DH-DSS-AES128-GCM-SHA256:"
|
|
"ECDH-ECDSA-AES128-GCM-SHA256:AES256-GCM-SHA384:"
|
|
"DH-DSS-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:"
|
|
"AES128-SHA256:DH-DSS-AES128-SHA256:ECDH-ECDSA-AES128-SHA256:AES256-SHA256:"
|
|
"DH-DSS-AES256-SHA256:ECDH-ECDSA-AES256-SHA384:AES128-SHA:"
|
|
"DH-DSS-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES256-SHA:"
|
|
"DH-DSS-AES256-SHA:ECDH-ECDSA-AES256-SHA:DHE-RSA-AES256-GCM-SHA384:"
|
|
"DH-RSA-AES128-GCM-SHA256:ECDH-RSA-AES128-GCM-SHA256:DH-RSA-AES256-GCM-SHA384:"
|
|
"ECDH-RSA-AES256-GCM-SHA384:DH-RSA-AES128-SHA256:"
|
|
"ECDH-RSA-AES128-SHA256:DH-RSA-AES256-SHA256:"
|
|
"ECDH-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:"
|
|
"ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA:"
|
|
"ECDHE-ECDSA-AES256-SHA:DHE-DSS-AES128-SHA:DHE-RSA-AES128-SHA:"
|
|
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA:DHE-RSA-AES256-SHA:"
|
|
"AES128-SHA:DH-DSS-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES256-SHA:"
|
|
"DH-DSS-AES256-SHA:ECDH-ECDSA-AES256-SHA:DH-RSA-AES128-SHA:"
|
|
"ECDH-RSA-AES128-SHA:DH-RSA-AES256-SHA:ECDH-RSA-AES256-SHA:DES-CBC3-SHA";
|
|
const uint64_t tls_protocols = (SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
|
|
|
static unsigned long id_function(void)
|
|
{
|
|
return ((unsigned long)pthread_self());
|
|
}
|
|
|
|
static void locking_function(int mode, int type, const char* file, int line)
|
|
{
|
|
if (mode & CRYPTO_LOCK) {
|
|
easy_spin_lock(&easy_ssl_lock_cs[type]);
|
|
} else {
|
|
easy_spin_unlock(&easy_ssl_lock_cs[type]);
|
|
}
|
|
}
|
|
int easy_ssl_init()
|
|
{
|
|
if (easy_ssl_connection_index == -1) {
|
|
SSL_library_init();
|
|
SSL_load_error_strings();
|
|
ENGINE_load_builtin_engines();
|
|
OpenSSL_add_all_algorithms();
|
|
|
|
easy_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
|
|
|
|
if (easy_ssl_connection_index == -1) {
|
|
easy_error_log("SSL_get_ex_new_index() failed");
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
int num = CRYPTO_num_locks();
|
|
easy_ssl_lock_cs = (easy_atomic_t*)easy_malloc(num * sizeof(easy_atomic_t));
|
|
memset((char*)easy_ssl_lock_cs, 0, num * sizeof(easy_atomic_t));
|
|
CRYPTO_set_id_callback(id_function);
|
|
CRYPTO_set_locking_callback(locking_function);
|
|
}
|
|
|
|
return EASY_OK;
|
|
}
|
|
|
|
/**
|
|
* cleanup
|
|
*/
|
|
int easy_ssl_cleanup()
|
|
{
|
|
ENGINE_cleanup();
|
|
EVP_cleanup();
|
|
CRYPTO_cleanup_all_ex_data();
|
|
ERR_remove_state(0);
|
|
ERR_free_strings();
|
|
// SSL_COMP_free();
|
|
// sk_SSL_COMP_free (SSL_COMP_get_compression_methods());
|
|
CRYPTO_mem_leaks_fp(stderr);
|
|
easy_free((char*)easy_ssl_lock_cs);
|
|
|
|
return EASY_OK;
|
|
}
|
|
|
|
int easy_ssl_connection_create(easy_ssl_ctx_t* ssl, easy_connection_t* c)
|
|
{
|
|
easy_ssl_connection_t* sc;
|
|
|
|
sc = easy_pool_calloc(c->pool, sizeof(easy_ssl_connection_t));
|
|
|
|
if (sc == NULL) {
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
sc->connection = SSL_new(ssl->ctx);
|
|
|
|
if (sc->connection == NULL) {
|
|
easy_error_log("SSL_new() failed");
|
|
return EASY_ERROR;
|
|
}
|
|
SSL_clear(sc->connection);
|
|
if (SSL_set_fd(sc->connection, c->fd) == 0) {
|
|
easy_error_log("SSL_set_fd() failed");
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if (c->type == EASY_TYPE_CLIENT) {
|
|
SSL_set_connect_state(sc->connection);
|
|
} else {
|
|
SSL_set_accept_state(sc->connection);
|
|
}
|
|
|
|
if (SSL_set_ex_data(sc->connection, easy_ssl_connection_index, c) == 0) {
|
|
easy_error_log("SSL_set_ex_data() failed");
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
sc->session_reuse = ssl->conf.session_reuse;
|
|
c->sc = sc;
|
|
|
|
return EASY_OK;
|
|
}
|
|
|
|
int easy_ssl_connection_destroy(easy_connection_t* c)
|
|
{
|
|
if (c->sc) {
|
|
int n, mode;
|
|
|
|
mode = SSL_RECEIVED_SHUTDOWN | SSL_SENT_SHUTDOWN;
|
|
SSL_set_shutdown(c->sc->connection, mode);
|
|
easy_ssl_clear_error();
|
|
n = SSL_shutdown(c->sc->connection);
|
|
|
|
if (n != 1 && ERR_peek_error()) {
|
|
SSL_get_error(c->sc->connection, n);
|
|
}
|
|
|
|
SSL_free(c->sc->connection);
|
|
|
|
c->sc = NULL;
|
|
}
|
|
|
|
return EASY_OK;
|
|
}
|
|
|
|
void easy_ssl_connection_handshake(struct ev_loop* loop, ev_io* w, int revents)
|
|
{
|
|
easy_connection_t* c;
|
|
int n, rc;
|
|
char buf[1];
|
|
|
|
c = (easy_connection_t*)w->data;
|
|
assert(c->fd == w->fd);
|
|
|
|
easy_debug_log("easy_ssl_connection_handshake: %s", easy_connection_str(c));
|
|
|
|
n = recv(c->fd, (char*)buf, 1, MSG_PEEK);
|
|
|
|
if (n <= 0) {
|
|
easy_debug_log("%s n: %d, error: %s(%d)\n", easy_connection_str(c), n, strerror(errno), errno);
|
|
c->conn_has_error = (n < 0 ? 1 : 0);
|
|
goto error_exit;
|
|
}
|
|
|
|
if (!((buf[0] & 0x80) || (buf[0] == 0x16)))
|
|
goto error_exit;
|
|
|
|
easy_debug_log("ssl handshake: 0x%02Xd", buf[0]);
|
|
|
|
rc = easy_ssl_handshake(c);
|
|
|
|
if (rc == EASY_ERROR) {
|
|
goto error_exit;
|
|
} else if (rc == EASY_AGAIN) {
|
|
c->sc->handler = easy_ssl_connection_handshake_handler;
|
|
} else {
|
|
easy_ssl_connection_handshake_handler(c);
|
|
}
|
|
|
|
return;
|
|
error_exit:
|
|
EASY_CONNECTION_DESTROY(c, "ssl_handshake");
|
|
}
|
|
|
|
int easy_ssl_client_do_handshake(easy_connection_t* c)
|
|
{
|
|
int rc;
|
|
uint64_t key;
|
|
easy_ssl_ctx_t* ctx;
|
|
char* servername;
|
|
easy_ssl_ctx_server_t* cs = NULL;
|
|
easy_ssl_t* ssl = NULL;
|
|
|
|
servername = c->client->server_name;
|
|
// easy_info_log("easy_ssl_client_do_handshake %s\n", easy_connection_str(c));
|
|
|
|
if (EASY_OK != easy_spinrwlock_rdlock(&(easy_baseth_self->eio->ssl_rwlock_))) {
|
|
easy_error_log("easy_spinrwlock_rdlock failed %s, ref_cnt %ld, wait_write %ld\n",
|
|
easy_connection_str(c),
|
|
easy_baseth_self->eio->ssl_rwlock_.ref_cnt,
|
|
easy_baseth_self->eio->ssl_rwlock_.wait_write);
|
|
return EASY_ERROR;
|
|
} else {
|
|
int need_return = 0;
|
|
ssl = easy_baseth_self->eio->ssl;
|
|
ctx = ssl->client_ctx;
|
|
|
|
if (servername) {
|
|
key = easy_hash_code(servername, strlen(servername), 3);
|
|
cs = (easy_ssl_ctx_server_t*)easy_hash_find_ex(ssl->client_map, key, easy_ssl_ctx_server_cmp, servername);
|
|
|
|
if (cs) {
|
|
ctx = cs->ss;
|
|
}
|
|
}
|
|
|
|
if (easy_ssl_connection_create(ctx, c) != EASY_OK) {
|
|
easy_error_log("easy_ssl_connection_create\n");
|
|
need_return = 1;
|
|
}
|
|
|
|
if (EASY_OK != easy_spinrwlock_unlock(&(easy_baseth_self->eio->ssl_rwlock_))) {
|
|
easy_error_log("easy_spinrwlock_unlock failed %s, ref_cnt %ld, wait_write %ld\n",
|
|
easy_connection_str(c),
|
|
easy_baseth_self->eio->ssl_rwlock_.ref_cnt,
|
|
easy_baseth_self->eio->ssl_rwlock_.wait_write);
|
|
need_return = 1;
|
|
}
|
|
if (need_return) {
|
|
return EASY_ERROR;
|
|
}
|
|
}
|
|
|
|
// reuse
|
|
if (c->sc->session_reuse && c->client->ssl_session) {
|
|
if (SSL_set_session(c->sc->connection, c->client->ssl_session) == 0) {
|
|
easy_error_log("SSL_set_session() failed");
|
|
return EASY_ERROR;
|
|
}
|
|
}
|
|
|
|
// handshake
|
|
rc = easy_ssl_handshake(c);
|
|
|
|
if (rc == EASY_ERROR) {
|
|
easy_warn_log("easy_ssl_handshake() failed");
|
|
return EASY_ERROR;
|
|
} else if (rc == EASY_AGAIN) {
|
|
c->sc->handler = easy_ssl_client_handshake_handler;
|
|
} else {
|
|
easy_ssl_client_handshake_handler(c);
|
|
}
|
|
|
|
return EASY_OK;
|
|
}
|
|
void easy_ssl_client_handshake(struct ev_loop* loop, ev_io* w, int revents)
|
|
{
|
|
easy_connection_t* c;
|
|
|
|
c = (easy_connection_t*)w->data;
|
|
|
|
if (easy_ssl_client_do_handshake(c) != EASY_OK) {
|
|
easy_warn_log("easy_ssl_client_handshake failed");
|
|
EASY_CONNECTION_DESTROY(c, "ssl_client_handshake");
|
|
}
|
|
}
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/**
|
|
* ssl info callback
|
|
*/
|
|
static void easy_ssl_info_callback(const SSL* s, int where, int ret)
|
|
{
|
|
easy_connection_t* c;
|
|
|
|
if (where & SSL_CB_HANDSHAKE_START) {
|
|
c = easy_ssl_get_connection(s);
|
|
|
|
if (c->sc->handshaked) {
|
|
c->sc->renegotiation = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// void test_info_callback(const SSL *ssl,int type,int val)
|
|
//{
|
|
// easy_debug_log("test_info_callback: type=%d, val=%d, options=%ld, version=%d, type=%d, state=%d, rwstate=%d,
|
|
// in_handshake=%d, rstate=%d, init_num=%d, verify_mode=%d, error=%d, error_code=%d, packet_length=%d",
|
|
// type, val, ssl->options, ssl->version, ssl->type, ssl->state, ssl->rwstate, ssl->in_handshake, ssl->rstate,
|
|
// ssl->init_num, ssl->verify_mode, ssl->error, ssl->error_code, ssl->packet_length);
|
|
// if (ssl->packet_length > 0 && NULL != ssl->packet) {
|
|
// easy_debug_log("test_info_callback: p=%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", ssl->packet[0], ssl->packet[1],
|
|
// ssl->packet[2], ssl->packet[3], ssl->packet[4], ssl->packet[5], ssl->packet[6], ssl->packet[7], ssl->packet[8],
|
|
// ssl->packet[9], ssl->packet[10]);
|
|
// }
|
|
//}
|
|
|
|
/**
|
|
* easy_ssl_handshake
|
|
*/
|
|
static int easy_ssl_handshake(easy_connection_t* c)
|
|
{
|
|
int n, sslerr, err;
|
|
|
|
easy_ssl_clear_error();
|
|
|
|
n = SSL_do_handshake(c->sc->connection);
|
|
// SSL *ssl = c->sc->connection;
|
|
// easy_debug_log("SSL_do_handshake: %d, options=%ld, version=%d, type=%d, state=%d, rwstate=%d, in_handshake=%d,
|
|
// rstate=%d, init_num=%d, "
|
|
// "verify_mode=%d, error=%d, error_code=%d, packet_length=%d, p=%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,
|
|
// %s", n, ssl->options, ssl->version, ssl->type, ssl->state, ssl->rwstate, ssl->in_handshake,
|
|
// ssl->rstate, ssl->init_num, ssl->verify_mode, ssl->error, ssl->error_code, ssl->packet_length,
|
|
// ssl->packet[0], ssl->packet[1], ssl->packet[2], ssl->packet[3], ssl->packet[4], ssl->packet[5],
|
|
// ssl->packet[6], ssl->packet[7], ssl->packet[8], ssl->packet[9], ssl->packet[10],
|
|
// easy_connection_str(c));
|
|
|
|
if (n == 1) {
|
|
ev_io_start(c->loop, &c->read_watcher);
|
|
ev_io_start(c->loop, &c->write_watcher);
|
|
c->sc->handshaked = 1;
|
|
c->read = easy_ssl_read;
|
|
c->write = easy_ssl_write;
|
|
|
|
if (c->sc->connection->s3) {
|
|
c->sc->connection->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
|
|
}
|
|
|
|
return EASY_OK;
|
|
}
|
|
|
|
sslerr = SSL_get_error(c->sc->connection, n);
|
|
easy_debug_log("SSL_get_error: %d %s errno=%d", sslerr, easy_connection_str(c), errno);
|
|
|
|
if (sslerr == SSL_ERROR_WANT_READ) {
|
|
ev_set_cb(&c->read_watcher, easy_ssl_handshake_handler);
|
|
ev_set_cb(&c->write_watcher, easy_ssl_handshake_handler);
|
|
ev_io_start(c->loop, &c->read_watcher);
|
|
ev_io_stop(c->loop, &c->write_watcher);
|
|
|
|
return EASY_AGAIN;
|
|
}
|
|
|
|
if (sslerr == SSL_ERROR_WANT_WRITE) {
|
|
ev_set_cb(&c->read_watcher, easy_ssl_handshake_handler);
|
|
ev_set_cb(&c->write_watcher, easy_ssl_handshake_handler);
|
|
ev_io_start(c->loop, &c->write_watcher);
|
|
ev_io_stop(c->loop, &c->read_watcher);
|
|
|
|
return EASY_AGAIN;
|
|
}
|
|
|
|
err = (sslerr == SSL_ERROR_SYSCALL) ? errno : 0;
|
|
|
|
if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
|
|
easy_warn_log("peer closed connection in SSL handshake");
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
easy_ssl_connection_error(c, sslerr, err, "SSL_do_handshake() failed");
|
|
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
/**
|
|
* clear error
|
|
*/
|
|
static void easy_ssl_clear_error()
|
|
{
|
|
while (ERR_peek_error()) {
|
|
easy_ssl_error(EASY_LOG_INFO, "ignoring stale global SSL error");
|
|
}
|
|
|
|
ERR_clear_error();
|
|
}
|
|
|
|
/**
|
|
* print ssl error
|
|
*/
|
|
#define EASY_MAX_CONF_ERRSTR 1024
|
|
static void easy_ssl_error(int level, char* fmt, ...)
|
|
{
|
|
uint64_t n;
|
|
va_list args;
|
|
char *p, *last;
|
|
char errstr[EASY_MAX_CONF_ERRSTR];
|
|
|
|
va_start(args, fmt);
|
|
p = errstr + easy_vsnprintf(errstr, EASY_MAX_CONF_ERRSTR, fmt, args);
|
|
va_end(args);
|
|
last = errstr + EASY_MAX_CONF_ERRSTR;
|
|
|
|
for (;;) {
|
|
n = ERR_get_error();
|
|
|
|
if (n == 0) {
|
|
break;
|
|
}
|
|
|
|
if (p >= last) {
|
|
continue;
|
|
}
|
|
|
|
*p++ = ' ';
|
|
|
|
ERR_error_string_n(n, (char*)p, last - p);
|
|
|
|
while (p < last && *p) {
|
|
p++;
|
|
}
|
|
}
|
|
|
|
static uint64_t hash_val = 0;
|
|
if (0 == hash_val) {
|
|
hash_val = easy_fnv_hash(__FILE__ ":" EASY_STRINGIZE(__LINE__));
|
|
}
|
|
easy_log_format(level, __FILE__, __LINE__, __FUNCTION__, hash_val, "%s", errstr);
|
|
}
|
|
|
|
/**
|
|
* easy_ssl_connection_error
|
|
*/
|
|
static void easy_ssl_connection_error(easy_connection_t* c, int sslerr, int err, char* text)
|
|
{
|
|
int n = 0;
|
|
int level = EASY_LOG_ERROR;
|
|
|
|
if (sslerr == SSL_ERROR_SYSCALL) {
|
|
|
|
if (err == ECONNRESET || err == EPIPE || err == ENOTCONN || err == ETIMEDOUT || err == ECONNREFUSED ||
|
|
err == ENETDOWN || err == ENETUNREACH || err == EHOSTDOWN || err == EHOSTUNREACH) {
|
|
level = EASY_LOG_INFO;
|
|
}
|
|
|
|
} else if (sslerr == SSL_ERROR_SSL) {
|
|
|
|
n = ERR_GET_REASON(ERR_peek_error());
|
|
|
|
/* handshake failures */
|
|
if (n == SSL_R_BLOCK_CIPHER_PAD_IS_WRONG /* 129 */
|
|
|| n == SSL_R_DIGEST_CHECK_FAILED /* 149 */
|
|
|| n == SSL_R_LENGTH_MISMATCH /* 159 */
|
|
// || n == SSL_R_NO_CIPHERS_PASSED delete by yishen, openssl 1.1.1 not supported /* 182 */
|
|
|| n == SSL_R_NO_CIPHERS_SPECIFIED /* 183 */
|
|
|| n == SSL_R_NO_SHARED_CIPHER /* 193 */
|
|
|| n == SSL_R_RECORD_LENGTH_MISMATCH /* 213 */
|
|
|| n == SSL_R_UNEXPECTED_MESSAGE /* 244 */
|
|
|| n == SSL_R_UNEXPECTED_RECORD /* 245 */
|
|
|| n == SSL_R_UNKNOWN_ALERT_TYPE /* 246 */
|
|
|| n == SSL_R_UNKNOWN_PROTOCOL /* 252 */
|
|
|| n == SSL_R_WRONG_VERSION_NUMBER /* 267 */
|
|
|| n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC /* 281 */
|
|
|| n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */
|
|
|| n == SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE /* 1010 */
|
|
|| n == SSL_R_SSLV3_ALERT_BAD_RECORD_MAC /* 1020 */
|
|
|| n == SSL_R_TLSV1_ALERT_DECRYPTION_FAILED /* 1021 */
|
|
|| n == SSL_R_TLSV1_ALERT_RECORD_OVERFLOW /* 1022 */
|
|
|| n == SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE /* 1030 */
|
|
|| n == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE /* 1040 */
|
|
|| n == SSL_R_SSLV3_ALERT_NO_CERTIFICATE /* 1041 */
|
|
|| n == SSL_R_SSLV3_ALERT_BAD_CERTIFICATE /* 1042 */
|
|
|| n == SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE /* 1043 */
|
|
|| n == SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED /* 1044 */
|
|
|| n == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED /* 1045 */
|
|
|| n == SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN /* 1046 */
|
|
|| n == SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER /* 1047 */
|
|
|| n == SSL_R_TLSV1_ALERT_UNKNOWN_CA /* 1048 */
|
|
|| n == SSL_R_TLSV1_ALERT_ACCESS_DENIED /* 1049 */
|
|
|| n == SSL_R_TLSV1_ALERT_DECODE_ERROR /* 1050 */
|
|
|| n == SSL_R_TLSV1_ALERT_DECRYPT_ERROR /* 1051 */
|
|
|| n == SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION /* 1060 */
|
|
|| n == SSL_R_TLSV1_ALERT_PROTOCOL_VERSION /* 1070 */
|
|
|| n == SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY /* 1071 */
|
|
|| n == SSL_R_TLSV1_ALERT_INTERNAL_ERROR /* 1080 */
|
|
|| n == SSL_R_TLSV1_ALERT_USER_CANCELLED /* 1090 */
|
|
|| n == SSL_R_TLSV1_ALERT_NO_RENEGOTIATION) { /* 1100 */
|
|
level = EASY_LOG_INFO;
|
|
}
|
|
}
|
|
easy_error_log("easy_ssl_connection_error: %s, sslerr=%d,err=%d,n=%d", easy_connection_str(c), sslerr, err, n);
|
|
|
|
easy_ssl_error(level, text);
|
|
}
|
|
|
|
static void easy_ssl_connection_handshake_handler(easy_connection_t* c)
|
|
{
|
|
if (c->sc->handshaked) {
|
|
ev_set_cb(&c->read_watcher, easy_connection_on_readable);
|
|
ev_set_cb(&c->write_watcher, easy_connection_on_writable);
|
|
}
|
|
}
|
|
|
|
static void easy_ssl_handshake_handler(struct ev_loop* loop, ev_io* w, int revents)
|
|
{
|
|
easy_connection_t* c;
|
|
int rc;
|
|
|
|
c = w->data;
|
|
easy_debug_log("easy_ssl_handshake_handler: %s", easy_connection_str(c));
|
|
rc = easy_ssl_handshake(c);
|
|
|
|
if (rc == EASY_AGAIN) {
|
|
return;
|
|
}
|
|
|
|
c->sc->handler(c);
|
|
|
|
if (rc == EASY_ERROR)
|
|
EASY_CONNECTION_DESTROY(c, "handshake_handler");
|
|
}
|
|
|
|
static ssize_t easy_ssl_read(easy_connection_t* c, char* buf, size_t size, int* pending)
|
|
{
|
|
ssize_t n, bytes;
|
|
|
|
if (c->sc->last == EASY_ERROR) {
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if (c->sc->last == EASY_ABORT) {
|
|
return 0;
|
|
}
|
|
|
|
easy_ssl_clear_error();
|
|
|
|
bytes = 0;
|
|
// easy_info_log("easy_ssl_read %s, %d", easy_connection_str(c), size);
|
|
|
|
for (;;) {
|
|
n = SSL_read(c->sc->connection, buf, size);
|
|
|
|
if (n > 0) {
|
|
bytes += n;
|
|
}
|
|
|
|
c->sc->last = easy_ssl_handle_recv(c, n);
|
|
|
|
if (c->sc->last == EASY_OK) {
|
|
size -= n;
|
|
|
|
if (size == 0) {
|
|
*pending = SSL_pending(c->sc->connection);
|
|
return bytes;
|
|
}
|
|
|
|
buf += n;
|
|
continue;
|
|
}
|
|
|
|
if (bytes) {
|
|
return bytes;
|
|
}
|
|
|
|
if (c->sc->last == EASY_ABORT) {
|
|
return 0;
|
|
} else if (c->sc->last == EASY_ERROR || c->sc->last == EASY_AGAIN) {
|
|
return c->sc->last;
|
|
}
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
|
|
static int easy_ssl_handle_recv(easy_connection_t* c, ssize_t n)
|
|
{
|
|
int sslerr;
|
|
int err;
|
|
|
|
if (c->sc->renegotiation) {
|
|
easy_error_log("SSL renegotiation disabled");
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if (n > 0) {
|
|
return EASY_OK;
|
|
}
|
|
|
|
sslerr = SSL_get_error(c->sc->connection, n);
|
|
err = (sslerr == SSL_ERROR_SYSCALL) ? errno : 0;
|
|
easy_debug_log("SSL_get_error: %d %s errno=%d", sslerr, easy_connection_str(c), errno);
|
|
|
|
if (sslerr == SSL_ERROR_WANT_READ) {
|
|
return EASY_AGAIN;
|
|
}
|
|
|
|
if (sslerr == SSL_ERROR_WANT_WRITE) {
|
|
easy_error_log("peer started SSL renegotiation");
|
|
|
|
ev_set_cb(&c->read_watcher, easy_ssl_handshake_handler);
|
|
ev_set_cb(&c->write_watcher, easy_ssl_handshake_handler);
|
|
ev_io_start(c->loop, &c->write_watcher);
|
|
return EASY_AGAIN;
|
|
}
|
|
|
|
if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
|
|
easy_debug_log("peer shutdown SSL cleanly");
|
|
return EASY_ABORT;
|
|
}
|
|
|
|
easy_ssl_connection_error(c, sslerr, err, "SSL_read() failed");
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
static ssize_t easy_ssl_write(easy_connection_t* c, easy_list_t* l)
|
|
{
|
|
easy_buf_t *b, *b1;
|
|
ssize_t bytes, ret, size;
|
|
int sslerr;
|
|
|
|
// foreach
|
|
bytes = 0;
|
|
easy_list_for_each_entry_safe(b, b1, l, node)
|
|
{
|
|
size = b->last - b->pos;
|
|
ret = SSL_write(c->sc->connection, b->pos, size);
|
|
|
|
if (ret <= 0) {
|
|
sslerr = SSL_get_error(c->sc->connection, ret);
|
|
|
|
if (sslerr == SSL_ERROR_WANT_WRITE || sslerr == SSL_ERROR_WANT_READ) {
|
|
return bytes;
|
|
} else {
|
|
return EASY_ERROR;
|
|
}
|
|
}
|
|
|
|
b->pos += ret;
|
|
bytes += ret;
|
|
|
|
if (ret < size)
|
|
break;
|
|
|
|
easy_buf_destroy(b);
|
|
}
|
|
return bytes;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// load ssl config file
|
|
easy_ssl_t* easy_ssl_config_load(char* filename)
|
|
{
|
|
FILE* fp = NULL;
|
|
easy_pool_t* pool = NULL;
|
|
easy_ssl_ctx_t* ss = NULL;
|
|
easy_ssl_t* ssl;
|
|
char buffer[1024], *p, *end, *value;
|
|
int status = 0;
|
|
int line = 0;
|
|
|
|
if ((fp = fopen(filename, "rb")) == NULL) {
|
|
easy_error_log("%s not open.", filename);
|
|
return NULL;
|
|
}
|
|
|
|
if ((pool = easy_pool_create(1024)) == NULL) {
|
|
goto error_exit;
|
|
}
|
|
|
|
if ((ssl = (easy_ssl_t*)easy_pool_calloc(pool, sizeof(easy_ssl_t))) == NULL) {
|
|
goto error_exit;
|
|
}
|
|
|
|
ssl->pool = pool;
|
|
ssl->server_map = easy_hash_create(pool, 128, offsetof(easy_ssl_ctx_server_t, node));
|
|
ssl->client_map = easy_hash_create(pool, 128, offsetof(easy_ssl_ctx_server_t, node));
|
|
easy_list_init(&ssl->server_list);
|
|
|
|
while (fgets(buffer, 1024, fp)) {
|
|
line++;
|
|
p = buffer;
|
|
|
|
while (*p && *p <= ' ') {
|
|
p++;
|
|
continue;
|
|
}
|
|
|
|
if (*p == '\0' || *p == '#')
|
|
continue;
|
|
|
|
// status
|
|
if (status == 0) {
|
|
end = strchr(p, '{');
|
|
|
|
if (end) {
|
|
*end = '\0';
|
|
status = 1;
|
|
ss = easy_pool_calloc(pool, sizeof(easy_ssl_ctx_t));
|
|
|
|
if (ss == NULL) {
|
|
goto error_exit;
|
|
}
|
|
|
|
ss->pool = pool;
|
|
ss->conf.session_timeout = 300;
|
|
ss->conf.verify_depth = 1;
|
|
ss->conf.file = filename;
|
|
ss->conf.line = line;
|
|
ss->type = (strncmp(p, "client", 6) == 0 ? 1 : 0);
|
|
}
|
|
} else {
|
|
end = strchr(p, '}');
|
|
|
|
if (end) {
|
|
*end = '\0';
|
|
status = 0;
|
|
|
|
if (easy_ssl_server_create(ssl, ss) == EASY_ERROR) {
|
|
goto error_exit;
|
|
}
|
|
}
|
|
|
|
end = strrchr(p, ';');
|
|
|
|
if (!end) {
|
|
if (status == 0)
|
|
continue;
|
|
|
|
easy_error_log("Line %d at %s Error", line, filename);
|
|
goto error_exit;
|
|
}
|
|
|
|
*end = '\0';
|
|
value = strchr(p, ' ');
|
|
|
|
if (!value) {
|
|
easy_error_log("Line %d at %s Error", line, filename);
|
|
goto error_exit;
|
|
}
|
|
|
|
*value++ = '\0';
|
|
|
|
while (*value && *value <= ' ') {
|
|
value++;
|
|
continue;
|
|
}
|
|
|
|
if (easy_ssl_parse_set_value(ss, p, value) == EASY_ERROR) {
|
|
easy_error_log("key: %s Line %d at %s Error", p, line, filename);
|
|
goto error_exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (status != 0) {
|
|
easy_error_log("Line %d at %s Error", line, filename);
|
|
goto error_exit;
|
|
}
|
|
|
|
// client default
|
|
if (ssl->client_ctx == NULL) {
|
|
ss = easy_pool_calloc(pool, sizeof(easy_ssl_ctx_t));
|
|
|
|
if (ss == NULL) {
|
|
goto error_exit;
|
|
}
|
|
|
|
ss->pool = pool;
|
|
ss->type = 1;
|
|
|
|
if (easy_ssl_server_create(ssl, ss) == EASY_ERROR) {
|
|
goto error_exit;
|
|
}
|
|
|
|
ssl->client_ctx = ss;
|
|
}
|
|
|
|
fclose(fp);
|
|
return ssl;
|
|
error_exit:
|
|
|
|
if (fp)
|
|
fclose(fp);
|
|
|
|
if (pool)
|
|
easy_pool_destroy(pool);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
easy_ssl_ctx_t* easy_ssl_ctx_load(easy_pool_t* pool, const char* ssl_ca, const char* ssl_cert, const char* ssl_key,
|
|
const int is_from_file, const int is_babassl, const int is_server)
|
|
{
|
|
/*
|
|
//debug for bkmi
|
|
char ssl_ca2[2048] = {0};
|
|
char ssl_key2[2048] = {0};
|
|
char ssl_cert2[4096] = {0};
|
|
long lSize = 0;
|
|
FILE *fp_ca = fopen("wallet/ca.pem", "r");;
|
|
FILE *fp_key = fopen("wallet/server-key.pem", "r");;
|
|
FILE *fp_cert = fopen("wallet/server-cert.pem", "r");;
|
|
|
|
#define REAL_ALL(FP, BUFF) \
|
|
fseek(FP,0,SEEK_END);\
|
|
lSize = ftell(FP);\
|
|
rewind(FP); \
|
|
fread(BUFF,sizeof(char),lSize,FP);\
|
|
|
|
REAL_ALL(fp_ca, ssl_ca2);
|
|
REAL_ALL(fp_key, ssl_key2);
|
|
REAL_ALL(fp_cert, ssl_cert2);
|
|
*/
|
|
|
|
easy_ssl_ctx_t* ss = NULL;
|
|
if (!ssl_ca || 0 == strlen(ssl_ca)) {
|
|
easy_info_log("no ssl_certificate");
|
|
goto error_exit;
|
|
}
|
|
|
|
if (!ssl_cert || 0 == strlen(ssl_cert)) {
|
|
easy_info_log("no ssl_certificate_key");
|
|
goto error_exit;
|
|
}
|
|
|
|
if (!ssl_key || 0 == strlen(ssl_key)) {
|
|
easy_info_log("no ssl_client_certificate");
|
|
goto error_exit;
|
|
}
|
|
|
|
if ((ss = (easy_ssl_ctx_t*)easy_pool_calloc(pool, sizeof(easy_ssl_ctx_t))) == NULL) {
|
|
easy_error_log("easy_pool_calloc easy_ssl_ctx_t failed, size=%u", sizeof(easy_ssl_ctx_t));
|
|
goto error_exit;
|
|
}
|
|
|
|
ss->pool = pool;
|
|
ss->type = (is_server ? EASY_TYPE_SERVER : EASY_TYPE_CLIENT);
|
|
ss->conf.session_timeout = 300;
|
|
ss->conf.session_cache = EASY_SSL_SCACHE_OFF;
|
|
ss->conf.protocols = tls_protocols;
|
|
|
|
if (easy_ssl_init() != EASY_OK) {
|
|
easy_error_log("easy_ssl_init failed");
|
|
goto error_exit;
|
|
}
|
|
|
|
if (easy_ssl_ctx_create_for_mysql(ss, is_babassl) != EASY_OK) {
|
|
easy_error_log("easy_ssl_ctx_create_for_mysql failed");
|
|
goto error_exit;
|
|
}
|
|
|
|
if (SSL_CTX_set_cipher_list(ss->ctx, (is_babassl ? baba_tls_ciphers_list : tls_ciphers_list)) <= 0) {
|
|
easy_error_log("SSL_CTX_set_cipher_list(%d, %V) failed", is_babassl, tls_ciphers_list);
|
|
goto error_exit;
|
|
}
|
|
|
|
if (is_from_file) {
|
|
if (easy_ssl_client_certificate_for_mysql(ss, ssl_ca, 1) != EASY_OK) {
|
|
easy_error_log("easy_ssl_client_certificate_for_mysql failed, client_certificate=%s", ssl_ca);
|
|
goto error_exit;
|
|
}
|
|
|
|
if (easy_ssl_certificate_for_mysql(ss, ssl_cert, ssl_key) != EASY_OK) {
|
|
easy_error_log("easy_ssl_certificate_for_mysql failed, certificate=%s, "
|
|
"certificate_key=%s",
|
|
ssl_cert,
|
|
ssl_key);
|
|
goto error_exit;
|
|
}
|
|
} else {
|
|
if (easy_ssl_client_certificate_for_mysql_memory(ss, ssl_ca) != EASY_OK) {
|
|
easy_error_log("easy_ssl_client_certificate_for_mysql_memory failed, client_certificate=%s", ssl_ca);
|
|
goto error_exit;
|
|
}
|
|
|
|
if (easy_ssl_certificate_for_mysql_memory(ss, ssl_cert, ssl_key) != EASY_OK) {
|
|
easy_error_log("easy_ssl_certificate_for_mysql_memory failed, certificate=%s, "
|
|
"certificate_key=%s",
|
|
ssl_cert,
|
|
ssl_key);
|
|
goto error_exit;
|
|
}
|
|
}
|
|
|
|
if (SSL_CTX_check_private_key(ss->ctx) <= 0) {
|
|
easy_error_log("SSL error: SSL_INITERR_NOMATCH, %s\n", ERR_error_string(ERR_get_error(), NULL));
|
|
goto error_exit;
|
|
}
|
|
|
|
if (easy_ssl_dhparam_mysql(ss) != EASY_OK) {
|
|
easy_error_log("SSL error: easy_ssl_dhparam");
|
|
goto error_exit;
|
|
}
|
|
|
|
if (easy_ssl_session_cache(ss, ss->conf.session_cache, ss->conf.session_timeout) != EASY_OK) {
|
|
easy_error_log("SSL error: easy_ssl_session_cache");
|
|
goto error_exit;
|
|
}
|
|
|
|
/* Set max number of cached sessions, returns the previous size */
|
|
// SSL_CTX_sess_set_cache_size(ss->ctx, 128);
|
|
|
|
return ss;
|
|
|
|
error_exit:
|
|
// fclose(fp_ca);
|
|
// fclose(fp_key);
|
|
// fclose(fp_cert);
|
|
return NULL;
|
|
}
|
|
|
|
int easy_ssl_ob_config_load(easy_io_t* eio, const char* ssl_ca, const char* ssl_cert, const char* ssl_key,
|
|
const int is_from_file, const int is_babassl, const int used_for_rpc)
|
|
{
|
|
int ret = EASY_OK;
|
|
easy_pool_t* pool = NULL;
|
|
easy_pool_t* ssl_pool = NULL;
|
|
easy_ssl_ctx_t* ctx_server = NULL;
|
|
easy_ssl_ctx_t* ctx_client = NULL;
|
|
if (eio == NULL) {
|
|
ret = EASY_ERROR;
|
|
easy_warn_log("easy_io is null failed");
|
|
} else if ((pool = easy_pool_create(1024)) == NULL) {
|
|
ret = EASY_ERROR;
|
|
easy_error_log("easy_pool_create failed");
|
|
} else if ((ctx_server = easy_ssl_ctx_load(pool, ssl_ca, ssl_cert, ssl_key, is_from_file, is_babassl, 1)) == NULL) {
|
|
ret = EASY_ERROR;
|
|
easy_error_log("easy_ssl_ctx_load easy_ssl_t failed");
|
|
} else if (used_for_rpc &&
|
|
(ctx_client = easy_ssl_ctx_load(pool, ssl_ca, ssl_cert, ssl_key, is_from_file, is_babassl, 0)) == NULL) {
|
|
ret = EASY_ERROR;
|
|
easy_error_log("easy_ssl_ctx_load easy_ssl_t failed");
|
|
} else if (eio->ssl == NULL) {
|
|
// first load
|
|
easy_ssl_t* tmp_ssl = NULL;
|
|
if ((ssl_pool = easy_pool_create(256)) == NULL) {
|
|
ret = EASY_ERROR;
|
|
easy_error_log("easy_pool_create failed");
|
|
} else if ((tmp_ssl = (easy_ssl_t*)easy_pool_calloc(ssl_pool, sizeof(easy_ssl_t))) == NULL) {
|
|
ret = EASY_ERROR;
|
|
easy_error_log("easy_pool_calloc easy_ssl_t failed, size=%u", sizeof(easy_ssl_t));
|
|
} else {
|
|
tmp_ssl->pool = pool;
|
|
tmp_ssl->server_map = easy_hash_create(pool, 128, offsetof(easy_ssl_ctx_server_t, node));
|
|
tmp_ssl->client_map = (used_for_rpc ? easy_hash_create(pool, 128, offsetof(easy_ssl_ctx_server_t, node)) : NULL);
|
|
tmp_ssl->server_ctx = ctx_server;
|
|
tmp_ssl->client_ctx = ctx_client;
|
|
|
|
easy_list_init(&tmp_ssl->server_list);
|
|
easy_list_add_tail(&ctx_server->list_node, &tmp_ssl->server_list);
|
|
if (used_for_rpc) {
|
|
easy_list_add_tail(&ctx_client->list_node, &tmp_ssl->server_list);
|
|
}
|
|
eio->ssl = tmp_ssl;
|
|
easy_info_log("ssl create succ %p\n", eio->ssl);
|
|
}
|
|
} else {
|
|
if (EASY_OK != easy_spinrwlock_wrlock(&eio->ssl_rwlock_)) {
|
|
ret = EASY_ERROR;
|
|
easy_error_log("easy_spinrwlock_wrlock failed, ref_cnt %ld, wait_write %ld\n",
|
|
eio->ssl_rwlock_.ref_cnt,
|
|
eio->ssl_rwlock_.wait_write);
|
|
} else {
|
|
easy_pool_t* old_pool = eio->ssl->pool;
|
|
eio->ssl->pool = pool;
|
|
pool = old_pool;
|
|
memset(&eio->ssl->server_list, 0, sizeof(eio->ssl->server_list));
|
|
easy_list_init(&eio->ssl->server_list);
|
|
|
|
SSL_CTX_free(eio->ssl->server_ctx->ctx);
|
|
eio->ssl->server_map = easy_hash_create(eio->ssl->pool, 128, offsetof(easy_ssl_ctx_server_t, node));
|
|
eio->ssl->server_ctx = ctx_server;
|
|
easy_list_add_tail(&ctx_server->list_node, &eio->ssl->server_list);
|
|
|
|
if (used_for_rpc) {
|
|
SSL_CTX_free(eio->ssl->client_ctx->ctx);
|
|
eio->ssl->client_map = easy_hash_create(eio->ssl->pool, 128, offsetof(easy_ssl_ctx_server_t, node));
|
|
eio->ssl->client_ctx = ctx_client;
|
|
easy_list_add_tail(&ctx_client->list_node, &eio->ssl->server_list);
|
|
}
|
|
|
|
if (EASY_OK != easy_spinrwlock_unlock(&eio->ssl_rwlock_)) {
|
|
ret = EASY_ERROR;
|
|
easy_error_log("easy_spinrwlock_unlock failed, ref_cnt %ld, wait_write %ld\n",
|
|
eio->ssl_rwlock_.ref_cnt,
|
|
eio->ssl_rwlock_.wait_write);
|
|
}
|
|
easy_info_log("ssl update succ %p\n", eio->ssl);
|
|
if (pool != NULL) {
|
|
easy_pool_destroy(pool);
|
|
pool = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ret != EASY_OK) {
|
|
if (pool != NULL) {
|
|
easy_pool_destroy(pool);
|
|
}
|
|
if (ssl_pool != NULL) {
|
|
easy_pool_destroy(ssl_pool);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int easy_ssl_ob_config_check(
|
|
const char* ssl_ca, const char* ssl_cert, const char* ssl_key, const int is_from_file, const int is_babassl)
|
|
{
|
|
int ret = EASY_OK;
|
|
easy_pool_t* pool = NULL;
|
|
easy_ssl_ctx_t* ctx_server = NULL;
|
|
easy_ssl_ctx_t* ctx_client = NULL;
|
|
if ((pool = easy_pool_create(1024)) == NULL) {
|
|
ret = EASY_ERROR;
|
|
easy_error_log("easy_pool_create failed");
|
|
} else if ((ctx_server = easy_ssl_ctx_load(pool, ssl_ca, ssl_cert, ssl_key, is_from_file, is_babassl, 1)) == NULL) {
|
|
ret = EASY_ERROR;
|
|
easy_error_log("easy_ssl_ctx_load easy_ssl_t failed");
|
|
} else if ((ctx_client = easy_ssl_ctx_load(pool, ssl_ca, ssl_cert, ssl_key, is_from_file, is_babassl, 0)) == NULL) {
|
|
ret = EASY_ERROR;
|
|
easy_error_log("easy_ssl_ctx_load easy_ssl_t failed");
|
|
}
|
|
|
|
if (pool != NULL) {
|
|
easy_pool_destroy(pool);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int easy_ssl_config_destroy(easy_ssl_t* ssl)
|
|
{
|
|
easy_ssl_ctx_t* ss;
|
|
|
|
if (ssl) {
|
|
easy_list_for_each_entry(ss, &ssl->server_list, list_node)
|
|
{
|
|
easy_debug_log("destroy ssl->ctx: %p", ss->ctx);
|
|
SSL_CTX_free(ss->ctx);
|
|
}
|
|
easy_pool_destroy(ssl->pool);
|
|
}
|
|
|
|
return EASY_OK;
|
|
}
|
|
|
|
static int easy_ssl_parse_set_value(easy_ssl_ctx_t* ss, char* key, char* value)
|
|
{
|
|
if (*key == '\0' || *value == '\0')
|
|
return EASY_ERROR;
|
|
|
|
if (strcmp(key, "ssl_certificate") == 0) {
|
|
ss->conf.certificate = easy_pool_strdup(ss->pool, value);
|
|
} else if (strcmp(key, "ssl_certificate_key") == 0) {
|
|
ss->conf.certificate_key = easy_pool_strdup(ss->pool, value);
|
|
} else if (strcmp(key, "ssl_dhparam") == 0) {
|
|
ss->conf.dhparam = easy_pool_strdup(ss->pool, value);
|
|
} else if (strcmp(key, "ssl_client_certificate") == 0) {
|
|
ss->conf.client_certificate = easy_pool_strdup(ss->pool, value);
|
|
} else if (strcmp(key, "ssl_crl") == 0) {
|
|
ss->conf.crl = easy_pool_strdup(ss->pool, value);
|
|
} else if (strcmp(key, "ssl_pass_phrase_dialog") == 0) {
|
|
ss->conf.pass_phrase_dialog = easy_pool_strdup(ss->pool, value);
|
|
} else if (strcmp(key, "ssl_ciphers") == 0) {
|
|
ss->conf.ciphers = easy_pool_strdup(ss->pool, value);
|
|
} else if (strcmp(key, "server_name") == 0) {
|
|
ss->conf.server_name = easy_pool_strdup(ss->pool, value);
|
|
} else if (strcmp(key, "ssl_prefer_server_ciphers") == 0) {
|
|
if (strcasecmp(value, "on") == 0) {
|
|
ss->conf.prefer_server_ciphers = 1;
|
|
} else if (strcasecmp(value, "off") == 0) {
|
|
ss->conf.prefer_server_ciphers = 0;
|
|
} else {
|
|
return EASY_ERROR;
|
|
}
|
|
} else if (strcmp(key, "ssl_verify") == 0) {
|
|
ss->conf.verify = strtol(value, (char**)NULL, 10);
|
|
} else if (strcmp(key, "ssl_verify_depth") == 0) {
|
|
ss->conf.verify_depth = strtol(value, (char**)NULL, 10);
|
|
} else if (strcmp(key, "ssl_session_timeout") == 0) {
|
|
ss->conf.session_timeout = strtol(value, (char**)NULL, 10);
|
|
} else if (strcmp(key, "ssl_session_cache") == 0) {
|
|
if (strcasecmp(value, "off") == 0) {
|
|
ss->conf.session_cache = EASY_SSL_SCACHE_OFF;
|
|
} else if (strcasecmp(value, "builtin") == 0) {
|
|
ss->conf.session_cache = EASY_SSL_SCACHE_BUILTIN;
|
|
} else {
|
|
return EASY_ERROR;
|
|
}
|
|
} else if (strcmp(key, "ssl_protocols") == 0) {
|
|
ss->conf.protocols = 0;
|
|
|
|
if (strstr(value, "SSLv2") == NULL) {
|
|
ss->conf.protocols |= SSL_OP_NO_SSLv2;
|
|
} else if (strstr(value, "SSLv3") == NULL) {
|
|
ss->conf.protocols |= SSL_OP_NO_SSLv3;
|
|
} else if (strstr(value, "TLSv1") == NULL) {
|
|
ss->conf.protocols |= SSL_OP_NO_TLSv1;
|
|
}
|
|
} else if (strcmp(key, "ssl_session_reuse") == 0) {
|
|
ss->conf.session_reuse = (strcasecmp(value, "on") == 0 ? 1 : 0);
|
|
} else {
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
return EASY_OK;
|
|
}
|
|
|
|
static int easy_ssl_ctx_server_cmp(const void* a, const void* b)
|
|
{
|
|
easy_ssl_ctx_server_t* cs = (easy_ssl_ctx_server_t*)b;
|
|
return strcmp(cs->server_name, (const char*)a);
|
|
}
|
|
|
|
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
|
int easy_ssl_servername(SSL* ssl_conn, int* ad, void* arg)
|
|
{
|
|
const char* servername;
|
|
size_t len;
|
|
char *p, host[128];
|
|
easy_ssl_ctx_server_t* cs;
|
|
easy_ssl_t* ssl = easy_baseth_self->eio->ssl;
|
|
|
|
servername = SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name);
|
|
|
|
if (ssl == NULL || servername == NULL) {
|
|
return SSL_TLSEXT_ERR_NOACK;
|
|
}
|
|
|
|
if ((len = strlen(servername)) == 0) {
|
|
return SSL_TLSEXT_ERR_NOACK;
|
|
}
|
|
|
|
if ((p = strchr(servername, ':')) != NULL) {
|
|
len = p - servername;
|
|
}
|
|
|
|
len = easy_min(127, len);
|
|
|
|
if (len <= 0) {
|
|
return SSL_TLSEXT_ERR_NOACK;
|
|
}
|
|
|
|
memcpy(host, servername, len);
|
|
host[len] = '\0';
|
|
uint64_t key = easy_hash_code(host, len, 3);
|
|
cs = (easy_ssl_ctx_server_t*)easy_hash_find_ex(ssl->server_map, key, easy_ssl_ctx_server_cmp, host);
|
|
|
|
if (cs == NULL) {
|
|
return SSL_TLSEXT_ERR_NOACK;
|
|
}
|
|
|
|
SSL_set_SSL_CTX(ssl_conn, cs->ss->ctx);
|
|
|
|
return SSL_TLSEXT_ERR_OK;
|
|
}
|
|
#endif
|
|
|
|
static int easy_ssl_server_create(easy_ssl_t* ssl, easy_ssl_ctx_t* ss)
|
|
{
|
|
|
|
if (ss->type) {
|
|
if (easy_ssl_ctx_create(ss) != EASY_OK) {
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if (ss->conf.certificate) {
|
|
char* key = ss->conf.certificate_key ? ss->conf.certificate_key : ss->conf.certificate;
|
|
|
|
if (easy_ssl_certificate(ss, ss->conf.certificate, key) != EASY_OK) {
|
|
return EASY_ERROR;
|
|
}
|
|
}
|
|
|
|
if (!ssl->client_ctx)
|
|
ssl->client_ctx = ss;
|
|
} else {
|
|
if (!ss->conf.certificate) {
|
|
easy_error_log("no \"ssl_certificate\" is defined in %s:%d", ss->conf.file, ss->conf.line);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if (!ss->conf.certificate_key) {
|
|
easy_error_log("no \"ssl_certificate_key\" is defined in %s:%d", ss->conf.file, ss->conf.line);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if (!ss->conf.server_name) {
|
|
easy_error_log("no \"server_name\" is defined in %s:%d", ss->conf.file, ss->conf.line);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if (easy_ssl_ctx_create(ss) != EASY_OK) {
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
|
|
|
if (SSL_CTX_set_tlsext_servername_callback(ss->ctx, easy_ssl_servername) == 0) {
|
|
easy_warn_log("SNI is not available");
|
|
}
|
|
|
|
#endif
|
|
|
|
if (easy_ssl_certificate(ss, ss->conf.certificate, ss->conf.certificate_key) != EASY_OK) {
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if (SSL_CTX_set_cipher_list(ss->ctx, (const char*)ss->conf.ciphers) == 0) {
|
|
easy_error_log("SSL_CTX_set_cipher_list(\"%V\") failed", ss->conf.ciphers);
|
|
}
|
|
|
|
if (ss->conf.verify) {
|
|
if (!ss->conf.client_certificate) {
|
|
easy_error_log("no ssl_client_certificate for ssl_client_verify");
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if (easy_ssl_client_certificate(ss, ss->conf.client_certificate, ss->conf.verify_depth) != EASY_OK) {
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if (easy_ssl_crl(ss, ss->conf.crl) != EASY_OK) {
|
|
return EASY_ERROR;
|
|
}
|
|
}
|
|
|
|
if (ss->conf.prefer_server_ciphers) {
|
|
SSL_CTX_set_options(ss->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
|
|
}
|
|
|
|
if (easy_ssl_generate_rsa512_key(ss) != EASY_OK) {
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if (easy_ssl_dhparam(ss, ss->conf.dhparam) != EASY_OK) {
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if (easy_ssl_session_cache(ss, ss->conf.session_cache, ss->conf.session_timeout) != EASY_OK) {
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
// add
|
|
if (ssl->server_ctx == NULL)
|
|
ssl->server_ctx = ss;
|
|
}
|
|
|
|
easy_ssl_ctx_server_t* cs;
|
|
char *p, *q;
|
|
uint64_t key;
|
|
|
|
p = ss->conf.server_name;
|
|
|
|
while (p && *p) {
|
|
if ((q = strchr(p, ' ')) != NULL)
|
|
*q = '\0';
|
|
|
|
key = easy_hash_code(p, strlen(p), 3);
|
|
|
|
if (ss->type) {
|
|
cs = (easy_ssl_ctx_server_t*)easy_hash_find_ex(ssl->client_map, key, easy_ssl_ctx_server_cmp, p);
|
|
} else {
|
|
cs = (easy_ssl_ctx_server_t*)easy_hash_find_ex(ssl->server_map, key, easy_ssl_ctx_server_cmp, p);
|
|
}
|
|
|
|
if (cs == NULL) {
|
|
cs = (easy_ssl_ctx_server_t*)easy_pool_calloc(ssl->pool, sizeof(easy_ssl_ctx_server_t));
|
|
cs->server_name = p;
|
|
cs->ss = ss;
|
|
|
|
if (ss->type) {
|
|
easy_hash_add(ssl->client_map, key, &cs->node);
|
|
} else {
|
|
easy_hash_add(ssl->server_map, key, &cs->node);
|
|
}
|
|
}
|
|
|
|
p = q;
|
|
}
|
|
|
|
easy_list_add_tail(&ss->list_node, &ssl->server_list);
|
|
|
|
return EASY_OK;
|
|
}
|
|
|
|
/**
|
|
* create ssl ctx
|
|
*/
|
|
static int easy_ssl_ctx_create(easy_ssl_ctx_t* ssl)
|
|
{
|
|
ssl->ctx = SSL_CTX_new(SSLv23_method());
|
|
easy_debug_log("create ssl->ctx: %p", ssl->ctx);
|
|
if (ssl->ctx == NULL) {
|
|
easy_error_log("SSL_CTX_new() failed");
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
/* client side options */
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_CHALLENGE_BUG);
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG);
|
|
|
|
/* server side options */
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
|
|
|
|
/* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING);
|
|
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG);
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG);
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG);
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE);
|
|
|
|
if (ssl->conf.protocols)
|
|
SSL_CTX_set_options(ssl->ctx, ssl->conf.protocols);
|
|
|
|
SSL_CTX_set_read_ahead(ssl->ctx, 1);
|
|
SSL_CTX_set_info_callback(ssl->ctx, easy_ssl_info_callback);
|
|
|
|
return EASY_OK;
|
|
}
|
|
|
|
static int easy_ssl_ctx_create_for_mysql(easy_ssl_ctx_t* ssl, int is_babassl)
|
|
{
|
|
(void)is_babassl;
|
|
ssl->ctx = SSL_CTX_new(SSLv23_method());
|
|
|
|
if (ssl->ctx == NULL) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "SSL_CTX_new() failed");
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
/* client side options */
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_CHALLENGE_BUG);
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG);
|
|
|
|
/* server side options */
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
|
|
|
|
/* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING);
|
|
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG);
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG);
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG);
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE);
|
|
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_COMPRESSION); /* OpenSSL >= 1.0 only */
|
|
SSL_CTX_set_options(ssl->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
|
|
|
|
if (ssl->conf.protocols)
|
|
SSL_CTX_set_options(ssl->ctx, ssl->conf.protocols);
|
|
|
|
// Explicitly load ECC ciphers, required on el7.
|
|
#if defined(SSL_CTX_set_ecdh_auto)
|
|
SSL_CTX_set_ecdh_auto(ssl->ctx, 1);
|
|
#else
|
|
EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_secp384r1);
|
|
if (!ecdh) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "EC_KEY_new_by_curve_name failed");
|
|
return EASY_ERROR;
|
|
}
|
|
SSL_CTX_set_tmp_ecdh(ssl->ctx, ecdh);
|
|
EC_KEY_free(ecdh);
|
|
#endif
|
|
|
|
SSL_CTX_set_read_ahead(ssl->ctx, 1);
|
|
SSL_CTX_set_info_callback(ssl->ctx, easy_ssl_info_callback);
|
|
|
|
return EASY_OK;
|
|
}
|
|
|
|
static int easy_ssl_certificate(easy_ssl_ctx_t* ssl, const char* cert, const char* key)
|
|
{
|
|
if (ssl->type) { // client
|
|
// cert --public key
|
|
if (SSL_CTX_use_certificate_file(ssl->ctx, cert, SSL_FILETYPE_PEM) <= 0) {
|
|
easy_error_log("SSL_CTX_use_certificate_file(\"%s\") failed", cert);
|
|
return EASY_ERROR;
|
|
}
|
|
} else {
|
|
if (SSL_CTX_use_certificate_chain_file(ssl->ctx, cert) <= 0) {
|
|
easy_error_log("SSL_CTX_use_certificate_chain_file(\"%s\") failed", cert);
|
|
return EASY_ERROR;
|
|
}
|
|
}
|
|
|
|
easy_ssl_pass_phrase_dialog_t dialog;
|
|
memset(&dialog, 0, sizeof(dialog));
|
|
dialog.type = ssl->conf.pass_phrase_dialog;
|
|
dialog.server_name = ssl->conf.server_name;
|
|
SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, &dialog);
|
|
SSL_CTX_set_default_passwd_cb(ssl->ctx, easy_ssl_pass_phrase_cb);
|
|
|
|
if (SSL_CTX_use_PrivateKey_file(ssl->ctx, key, SSL_FILETYPE_PEM) <= 0) {
|
|
easy_error_log("SSL_CTX_use_PrivateKey_file(\"%s\") failed", key);
|
|
return EASY_ERROR;
|
|
}
|
|
return EASY_OK;
|
|
}
|
|
|
|
static int easy_ssl_certificate_for_mysql(easy_ssl_ctx_t* ssl, const char* cert, const char* key)
|
|
{
|
|
if (SSL_CTX_use_certificate_chain_file(ssl->ctx, cert) <= 0) {
|
|
easy_error_log("SSL_CTX_use_certificate_chain_file(\"%s\") failed", cert);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
easy_ssl_pass_phrase_dialog_t dialog;
|
|
memset(&dialog, 0, sizeof(dialog));
|
|
dialog.type = ssl->conf.pass_phrase_dialog;
|
|
dialog.server_name = ssl->conf.server_name;
|
|
SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, &dialog);
|
|
SSL_CTX_set_default_passwd_cb(ssl->ctx, easy_ssl_pass_phrase_cb);
|
|
|
|
if (SSL_CTX_use_PrivateKey_file(ssl->ctx, key, SSL_FILETYPE_PEM) <= 0) {
|
|
easy_error_log("SSL_CTX_use_PrivateKey_file(\"%s\") failed", key);
|
|
return EASY_ERROR;
|
|
}
|
|
return EASY_OK;
|
|
}
|
|
|
|
static int easy_ssl_certificate_for_mysql_memory(easy_ssl_ctx_t* ssl, const char* cert, const char* key)
|
|
{
|
|
(void)cert;
|
|
// cert
|
|
BIO* cbio = BIO_new_mem_buf((void*)cert, -1);
|
|
int i;
|
|
|
|
STACK_OF(X509_INFO)* inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL);
|
|
int is_first = 1;
|
|
for (i = 0; i < sk_X509_INFO_num(inf); i++) {
|
|
X509_INFO* itmp = sk_X509_INFO_value(inf, i);
|
|
if (itmp->x509) {
|
|
if (is_first) {
|
|
is_first = 0;
|
|
if (SSL_CTX_use_certificate(ssl->ctx, itmp->x509) <= 0) {
|
|
easy_error_log("SSL_CTX_use_certificate(\"%s\") failed", cert);
|
|
sk_X509_INFO_pop_free(inf, X509_INFO_free); // cleanup
|
|
return EASY_ERROR;
|
|
} else {
|
|
/* Get ready to store intermediate certs, if any. */
|
|
// SSL_CTX_clear_chain_certs(ssl->ctx);
|
|
}
|
|
} else {
|
|
if (SSL_CTX_add_extra_chain_cert(ssl->ctx, itmp->x509) <= 0) {
|
|
easy_error_log("SSL_CTX_add_extra_chain_cert(\"%s\") failed", cert);
|
|
sk_X509_INFO_pop_free(inf, X509_INFO_free); // cleanup
|
|
return EASY_ERROR;
|
|
} else {
|
|
/*
|
|
* Above function doesn't increment cert reference count. NULL the info
|
|
* reference to it in order to prevent it from being freed during cleanup.
|
|
*/
|
|
itmp->x509 = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sk_X509_INFO_pop_free(inf, X509_INFO_free); // cleanup
|
|
|
|
RSA* rsa = NULL;
|
|
cbio = BIO_new_mem_buf((void*)key, -1);
|
|
if (NULL == (rsa = PEM_read_bio_RSAPrivateKey(cbio, NULL, 0, NULL))) {
|
|
easy_error_log("PEM_read_bio_RSAPrivateKey(\"%s\") failed", key);
|
|
return EASY_ERROR;
|
|
} else if (SSL_CTX_use_RSAPrivateKey(ssl->ctx, rsa) <= 0) {
|
|
easy_error_log("SSL_CTX_use_RSAPrivateKey(\"%s\") failed", key);
|
|
return EASY_ERROR;
|
|
}
|
|
return EASY_OK;
|
|
}
|
|
|
|
static int easy_ssl_generate_rsa512_key(easy_ssl_ctx_t* ssl)
|
|
{
|
|
int ret = 1;
|
|
RSA* key = NULL;
|
|
if (SSL_CTX_need_tmp_RSA(ssl->ctx) == 0) {
|
|
return EASY_OK;
|
|
}
|
|
BIGNUM* e = BN_new();
|
|
if (NULL == e) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "RSA_generate_key(512) BN new failed");
|
|
return EASY_ERROR;
|
|
}
|
|
ret = BN_set_word(e, RSA_F4);
|
|
if (ret != 1) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "RSA_generate_key(512) set word failed");
|
|
return EASY_ERROR;
|
|
}
|
|
ret = RSA_generate_key_ex(key, 512, e, NULL);
|
|
if (ret != 1) {
|
|
if (key) {
|
|
RSA_free(key);
|
|
BN_free(e);
|
|
}
|
|
easy_ssl_error(EASY_LOG_ERROR, "RSA_generate_key(512) failed");
|
|
return EASY_ERROR;
|
|
}
|
|
if (key) {
|
|
SSL_CTX_set_tmp_rsa(ssl->ctx, key);
|
|
|
|
RSA_free(key);
|
|
BN_free(e);
|
|
return EASY_OK;
|
|
}
|
|
|
|
easy_ssl_error(EASY_LOG_ERROR, "RSA_generate_key(512) failed");
|
|
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
static int easy_ssl_dhparam(easy_ssl_ctx_t* ssl, char* file)
|
|
{
|
|
DH* dh;
|
|
BIO* bio;
|
|
|
|
/*
|
|
* -----BEGIN DH PARAMETERS-----
|
|
* MIGHAoGBALu8LcrYRnSQfEP89YDpz9vZWKP1aLQtSwju1OsPs1BMbAMCducQgAxc
|
|
* y7qokiYUxb7spWWl/fHSh6K8BJvmd4Bg6RqSp1fjBI9osHb302zI8pul34HcLKcl
|
|
* 7OZicMyaUDXYzs7vnqAnSmOrHlj6/UmI0PZdFGdX2gcd8EXP4WubAgEC
|
|
* -----END DH PARAMETERS-----
|
|
*/
|
|
|
|
static unsigned char dh1024_p[] = {0xBB,
|
|
0xBC,
|
|
0x2D,
|
|
0xCA,
|
|
0xD8,
|
|
0x46,
|
|
0x74,
|
|
0x90,
|
|
0x7C,
|
|
0x43,
|
|
0xFC,
|
|
0xF5,
|
|
0x80,
|
|
0xE9,
|
|
0xCF,
|
|
0xDB,
|
|
0xD9,
|
|
0x58,
|
|
0xA3,
|
|
0xF5,
|
|
0x68,
|
|
0xB4,
|
|
0x2D,
|
|
0x4B,
|
|
0x08,
|
|
0xEE,
|
|
0xD4,
|
|
0xEB,
|
|
0x0F,
|
|
0xB3,
|
|
0x50,
|
|
0x4C,
|
|
0x6C,
|
|
0x03,
|
|
0x02,
|
|
0x76,
|
|
0xE7,
|
|
0x10,
|
|
0x80,
|
|
0x0C,
|
|
0x5C,
|
|
0xCB,
|
|
0xBA,
|
|
0xA8,
|
|
0x92,
|
|
0x26,
|
|
0x14,
|
|
0xC5,
|
|
0xBE,
|
|
0xEC,
|
|
0xA5,
|
|
0x65,
|
|
0xA5,
|
|
0xFD,
|
|
0xF1,
|
|
0xD2,
|
|
0x87,
|
|
0xA2,
|
|
0xBC,
|
|
0x04,
|
|
0x9B,
|
|
0xE6,
|
|
0x77,
|
|
0x80,
|
|
0x60,
|
|
0xE9,
|
|
0x1A,
|
|
0x92,
|
|
0xA7,
|
|
0x57,
|
|
0xE3,
|
|
0x04,
|
|
0x8F,
|
|
0x68,
|
|
0xB0,
|
|
0x76,
|
|
0xF7,
|
|
0xD3,
|
|
0x6C,
|
|
0xC8,
|
|
0xF2,
|
|
0x9B,
|
|
0xA5,
|
|
0xDF,
|
|
0x81,
|
|
0xDC,
|
|
0x2C,
|
|
0xA7,
|
|
0x25,
|
|
0xEC,
|
|
0xE6,
|
|
0x62,
|
|
0x70,
|
|
0xCC,
|
|
0x9A,
|
|
0x50,
|
|
0x35,
|
|
0xD8,
|
|
0xCE,
|
|
0xCE,
|
|
0xEF,
|
|
0x9E,
|
|
0xA0,
|
|
0x27,
|
|
0x4A,
|
|
0x63,
|
|
0xAB,
|
|
0x1E,
|
|
0x58,
|
|
0xFA,
|
|
0xFD,
|
|
0x49,
|
|
0x88,
|
|
0xD0,
|
|
0xF6,
|
|
0x5D,
|
|
0x14,
|
|
0x67,
|
|
0x57,
|
|
0xDA,
|
|
0x07,
|
|
0x1D,
|
|
0xF0,
|
|
0x45,
|
|
0xCF,
|
|
0xE1,
|
|
0x6B,
|
|
0x9B};
|
|
|
|
static unsigned char dh1024_g[] = {0x02};
|
|
|
|
if (!file) {
|
|
|
|
dh = DH_new();
|
|
|
|
if (dh == NULL) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "DH_new() failed");
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
|
|
dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
|
|
|
|
if (dh->p == NULL || dh->g == NULL) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "BN_bin2bn() failed");
|
|
DH_free(dh);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
SSL_CTX_set_tmp_dh(ssl->ctx, dh);
|
|
|
|
DH_free(dh);
|
|
|
|
return EASY_OK;
|
|
}
|
|
|
|
bio = BIO_new_file(file, "r");
|
|
|
|
if (bio == NULL) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "BIO_new_file(\"%s\") failed", file);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
|
|
|
|
if (dh == NULL) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "PEM_read_bio_DHparams(\"%s\") failed", file);
|
|
BIO_free(bio);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
SSL_CTX_set_tmp_dh(ssl->ctx, dh);
|
|
|
|
DH_free(dh);
|
|
BIO_free(bio);
|
|
|
|
return EASY_OK;
|
|
}
|
|
|
|
static int easy_ssl_dhparam_mysql(easy_ssl_ctx_t* ssl)
|
|
{
|
|
DH* dh;
|
|
|
|
/*
|
|
Diffie-Hellman key.
|
|
Generated using: >openssl dhparam -5 -C 2048
|
|
|
|
-----BEGIN DH PARAMETERS-----
|
|
MIIBCAKCAQEAil36wGZ2TmH6ysA3V1xtP4MKofXx5n88xq/aiybmGnReZMviCPEJ
|
|
46+7VCktl/RZ5iaDH1XNG1dVQmznt9pu2G3usU+k1/VB4bQL4ZgW4u0Wzxh9PyXD
|
|
glm99I9Xyj4Z5PVE4MyAsxCRGA1kWQpD9/zKAegUBPLNqSo886Uqg9hmn8ksyU9E
|
|
BV5eAEciCuawh6V0O+Sj/C3cSfLhgA0GcXp3OqlmcDu6jS5gWjn3LdP1U0duVxMB
|
|
h/neTSCSvtce4CAMYMjKNVh9P1nu+2d9ZH2Od2xhRIqMTfAS1KTqF3VmSWzPFCjG
|
|
mjxx/bg6bOOjpgZapvB6ABWlWmRmAAWFtwIBBQ==
|
|
-----END DH PARAMETERS-----
|
|
*/
|
|
static unsigned char dh2048_p[] = {
|
|
0x8A,
|
|
0x5D,
|
|
0xFA,
|
|
0xC0,
|
|
0x66,
|
|
0x76,
|
|
0x4E,
|
|
0x61,
|
|
0xFA,
|
|
0xCA,
|
|
0xC0,
|
|
0x37,
|
|
0x57,
|
|
0x5C,
|
|
0x6D,
|
|
0x3F,
|
|
0x83,
|
|
0x0A,
|
|
0xA1,
|
|
0xF5,
|
|
0xF1,
|
|
0xE6,
|
|
0x7F,
|
|
0x3C,
|
|
0xC6,
|
|
0xAF,
|
|
0xDA,
|
|
0x8B,
|
|
0x26,
|
|
0xE6,
|
|
0x1A,
|
|
0x74,
|
|
0x5E,
|
|
0x64,
|
|
0xCB,
|
|
0xE2,
|
|
0x08,
|
|
0xF1,
|
|
0x09,
|
|
0xE3,
|
|
0xAF,
|
|
0xBB,
|
|
0x54,
|
|
0x29,
|
|
0x2D,
|
|
0x97,
|
|
0xF4,
|
|
0x59,
|
|
0xE6,
|
|
0x26,
|
|
0x83,
|
|
0x1F,
|
|
0x55,
|
|
0xCD,
|
|
0x1B,
|
|
0x57,
|
|
0x55,
|
|
0x42,
|
|
0x6C,
|
|
0xE7,
|
|
0xB7,
|
|
0xDA,
|
|
0x6E,
|
|
0xD8,
|
|
0x6D,
|
|
0xEE,
|
|
0xB1,
|
|
0x4F,
|
|
0xA4,
|
|
0xD7,
|
|
0xF5,
|
|
0x41,
|
|
0xE1,
|
|
0xB4,
|
|
0x0B,
|
|
0xE1,
|
|
0x98,
|
|
0x16,
|
|
0xE2,
|
|
0xED,
|
|
0x16,
|
|
0xCF,
|
|
0x18,
|
|
0x7D,
|
|
0x3F,
|
|
0x25,
|
|
0xC3,
|
|
0x82,
|
|
0x59,
|
|
0xBD,
|
|
0xF4,
|
|
0x8F,
|
|
0x57,
|
|
0xCA,
|
|
0x3E,
|
|
0x19,
|
|
0xE4,
|
|
0xF5,
|
|
0x44,
|
|
0xE0,
|
|
0xCC,
|
|
0x80,
|
|
0xB3,
|
|
0x10,
|
|
0x91,
|
|
0x18,
|
|
0x0D,
|
|
0x64,
|
|
0x59,
|
|
0x0A,
|
|
0x43,
|
|
0xF7,
|
|
0xFC,
|
|
0xCA,
|
|
0x01,
|
|
0xE8,
|
|
0x14,
|
|
0x04,
|
|
0xF2,
|
|
0xCD,
|
|
0xA9,
|
|
0x2A,
|
|
0x3C,
|
|
0xF3,
|
|
0xA5,
|
|
0x2A,
|
|
0x83,
|
|
0xD8,
|
|
0x66,
|
|
0x9F,
|
|
0xC9,
|
|
0x2C,
|
|
0xC9,
|
|
0x4F,
|
|
0x44,
|
|
0x05,
|
|
0x5E,
|
|
0x5E,
|
|
0x00,
|
|
0x47,
|
|
0x22,
|
|
0x0A,
|
|
0xE6,
|
|
0xB0,
|
|
0x87,
|
|
0xA5,
|
|
0x74,
|
|
0x3B,
|
|
0xE4,
|
|
0xA3,
|
|
0xFC,
|
|
0x2D,
|
|
0xDC,
|
|
0x49,
|
|
0xF2,
|
|
0xE1,
|
|
0x80,
|
|
0x0D,
|
|
0x06,
|
|
0x71,
|
|
0x7A,
|
|
0x77,
|
|
0x3A,
|
|
0xA9,
|
|
0x66,
|
|
0x70,
|
|
0x3B,
|
|
0xBA,
|
|
0x8D,
|
|
0x2E,
|
|
0x60,
|
|
0x5A,
|
|
0x39,
|
|
0xF7,
|
|
0x2D,
|
|
0xD3,
|
|
0xF5,
|
|
0x53,
|
|
0x47,
|
|
0x6E,
|
|
0x57,
|
|
0x13,
|
|
0x01,
|
|
0x87,
|
|
0xF9,
|
|
0xDE,
|
|
0x4D,
|
|
0x20,
|
|
0x92,
|
|
0xBE,
|
|
0xD7,
|
|
0x1E,
|
|
0xE0,
|
|
0x20,
|
|
0x0C,
|
|
0x60,
|
|
0xC8,
|
|
0xCA,
|
|
0x35,
|
|
0x58,
|
|
0x7D,
|
|
0x3F,
|
|
0x59,
|
|
0xEE,
|
|
0xFB,
|
|
0x67,
|
|
0x7D,
|
|
0x64,
|
|
0x7D,
|
|
0x8E,
|
|
0x77,
|
|
0x6C,
|
|
0x61,
|
|
0x44,
|
|
0x8A,
|
|
0x8C,
|
|
0x4D,
|
|
0xF0,
|
|
0x12,
|
|
0xD4,
|
|
0xA4,
|
|
0xEA,
|
|
0x17,
|
|
0x75,
|
|
0x66,
|
|
0x49,
|
|
0x6C,
|
|
0xCF,
|
|
0x14,
|
|
0x28,
|
|
0xC6,
|
|
0x9A,
|
|
0x3C,
|
|
0x71,
|
|
0xFD,
|
|
0xB8,
|
|
0x3A,
|
|
0x6C,
|
|
0xE3,
|
|
0xA3,
|
|
0xA6,
|
|
0x06,
|
|
0x5A,
|
|
0xA6,
|
|
0xF0,
|
|
0x7A,
|
|
0x00,
|
|
0x15,
|
|
0xA5,
|
|
0x5A,
|
|
0x64,
|
|
0x66,
|
|
0x00,
|
|
0x05,
|
|
0x85,
|
|
0xB7,
|
|
};
|
|
|
|
static unsigned char dh2048_g[] = {
|
|
0x05,
|
|
};
|
|
|
|
dh = DH_new();
|
|
|
|
if (dh == NULL) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "DH_new() failed");
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
BIGNUM* p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
|
|
BIGNUM* g = BN_bin2bn(dh2048_g, sizeof(dh2048_g), NULL);
|
|
|
|
if (!p || !g
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
|| !DH_set0_pqg(dh, p, NULL, g)
|
|
#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
|
|
) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "BN_bin2bn() failed");
|
|
DH_free(dh);
|
|
return EASY_ERROR;
|
|
}
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
dh->p = p;
|
|
dh->g = g;
|
|
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
|
|
|
|
if (SSL_CTX_set_tmp_dh(ssl->ctx, dh) == 0) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "SSL_CTX_set_tmp_dh failed");
|
|
DH_free(dh);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
DH_free(dh);
|
|
return EASY_OK;
|
|
}
|
|
|
|
static int easy_ssl_session_cache(easy_ssl_ctx_t* ssl, int session_cache, int timeout)
|
|
{
|
|
if (session_cache == EASY_SSL_SCACHE_OFF) {
|
|
SSL_CTX_set_session_cache_mode(ssl->ctx, SSL_SESS_CACHE_OFF);
|
|
} else {
|
|
// SSL_CTX_set_session_id_context(ssl->ctx, sess_ctx->data, sess_ctx->len);
|
|
SSL_CTX_set_session_cache_mode(ssl->ctx, SSL_SESS_CACHE_SERVER);
|
|
SSL_CTX_set_timeout(ssl->ctx, (long)timeout);
|
|
}
|
|
|
|
return EASY_OK;
|
|
}
|
|
|
|
static int easy_ssl_verify_callback(int ok, X509_STORE_CTX* x509_store)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static int easy_ssl_client_certificate(easy_ssl_ctx_t* ssl, char* cert, int depth)
|
|
{
|
|
STACK_OF(X509_NAME) * list;
|
|
|
|
SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, easy_ssl_verify_callback);
|
|
|
|
SSL_CTX_set_verify_depth(ssl->ctx, depth);
|
|
|
|
if (!cert) {
|
|
return EASY_OK;
|
|
}
|
|
// ca file
|
|
if (SSL_CTX_load_verify_locations(ssl->ctx, cert, NULL) == 0) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "SSL_CTX_load_verify_locations(\"%s\") failed", cert);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if ((list = SSL_load_client_CA_file(cert)) == NULL) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "SSL_load_client_CA_file(\"%s\") failed", cert);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
ERR_clear_error();
|
|
|
|
SSL_CTX_set_client_CA_list(ssl->ctx, list);
|
|
|
|
return EASY_OK;
|
|
}
|
|
|
|
static int easy_ssl_client_certificate_for_mysql(easy_ssl_ctx_t* ssl, const char* cert, int depth)
|
|
{
|
|
(void)(depth);
|
|
STACK_OF(X509_NAME) * list;
|
|
|
|
SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL);
|
|
|
|
// ca file
|
|
if (SSL_CTX_load_verify_locations(ssl->ctx, cert, NULL) == 0) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "SSL_CTX_load_verify_locations(\"%s\") failed", cert);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if ((list = SSL_load_client_CA_file(cert)) == NULL) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "SSL_load_client_CA_file(\"%s\") failed", cert);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
ERR_clear_error();
|
|
|
|
SSL_CTX_set_client_CA_list(ssl->ctx, list);
|
|
return EASY_OK;
|
|
}
|
|
|
|
static int easy_ssl_client_certificate_for_mysql_memory(easy_ssl_ctx_t* ssl, const char* cert)
|
|
{
|
|
SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL);
|
|
|
|
BIO* cbio = NULL;
|
|
if (NULL == (cbio = BIO_new_mem_buf((void*)cert, -1))) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "BIO_new_mem_buf(\"%s\") failed", cert);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
X509* cert_x509 = NULL;
|
|
if (NULL == (cert_x509 = PEM_read_bio_X509(cbio, NULL, 0, NULL))) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "PEM_read_bio_X509(\"%s\") failed", cert);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
X509_STORE* x509_store = NULL;
|
|
if (NULL == (x509_store = X509_STORE_new())) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "X509_STORE_new(\"%s\") failed", cert);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if (0 == X509_STORE_add_cert(x509_store, cert_x509)) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "X509_STORE_add_cert failed (\"%s\")", ERR_error_string(ERR_get_error(), NULL));
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
SSL_CTX_set_cert_store(ssl->ctx, x509_store);
|
|
return EASY_OK;
|
|
}
|
|
|
|
static int easy_ssl_crl(easy_ssl_ctx_t* ssl, char* crl)
|
|
{
|
|
X509_STORE* store;
|
|
X509_LOOKUP* lookup;
|
|
|
|
if (!crl) {
|
|
return EASY_OK;
|
|
}
|
|
|
|
store = SSL_CTX_get_cert_store(ssl->ctx);
|
|
|
|
if (store == NULL) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "SSL_CTX_get_cert_store() failed");
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
|
|
|
|
if (lookup == NULL) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "X509_STORE_add_lookup() failed");
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
if (X509_LOOKUP_load_file(lookup, crl, X509_FILETYPE_PEM) == 0) {
|
|
easy_ssl_error(EASY_LOG_ERROR, "X509_LOOKUP_load_file(\"%s\") failed", crl);
|
|
return EASY_ERROR;
|
|
}
|
|
|
|
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
|
|
|
|
return EASY_OK;
|
|
}
|
|
|
|
static void easy_ssl_client_handshake_handler(easy_connection_t* c)
|
|
{
|
|
SSL_SESSION *old_ssl_session, *ssl_session;
|
|
|
|
if (c->sc->handshaked) {
|
|
ev_set_cb(&c->read_watcher, easy_connection_on_readable);
|
|
ev_set_cb(&c->write_watcher, easy_connection_on_writable);
|
|
|
|
if (c->sc->session_reuse) {
|
|
ssl_session = SSL_get1_session(c->sc->connection);
|
|
|
|
if (ssl_session == NULL) {
|
|
return;
|
|
}
|
|
|
|
old_ssl_session = c->client->ssl_session;
|
|
c->client->ssl_session = ssl_session;
|
|
|
|
if (old_ssl_session) {
|
|
SSL_SESSION_free(old_ssl_session);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int easy_ssl_pass_phrase_cb(char* buf, int size, int rwflag, void* conf)
|
|
{
|
|
easy_ssl_pass_phrase_dialog_t* dialog;
|
|
int len = -1;
|
|
size_t str_len = 0;
|
|
|
|
dialog = (easy_ssl_pass_phrase_dialog_t*)conf;
|
|
buf[0] = '\0';
|
|
|
|
if (dialog->type == NULL || strncmp(dialog->type, "builtin", 7) == 0) {
|
|
easy_error_log("Server %s", dialog->server_name);
|
|
|
|
while ((len = strlen(buf)) == 0) {
|
|
fprintf(stderr, "Enter pass phrase:");
|
|
|
|
if ((len = EVP_read_pw_string(buf, size, "", 0)) != 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
} else if (strncmp(dialog->type, "exec:", 5) == 0) {
|
|
FILE* fp;
|
|
char *p, cmd[256];
|
|
|
|
snprintf(cmd, 256, "%s '%s'", dialog->type + 5, dialog->server_name);
|
|
|
|
if ((fp = popen(cmd, "r")) == NULL)
|
|
return -1;
|
|
|
|
if (fgets(buf, size, fp)) {
|
|
str_len = strlen(buf);
|
|
if (str_len >= 2 * 1024 * 1024) {
|
|
/*
|
|
* check the length of string to avoid INTEGER_OVERFLOW.
|
|
*/
|
|
easy_error_log("buf is too long, buf(%d).", str_len);
|
|
} else {
|
|
p = buf + str_len;
|
|
|
|
while (p > buf && *(p - 1) == '\n')
|
|
p--;
|
|
|
|
*p = '\0';
|
|
len = p - buf;
|
|
}
|
|
}
|
|
|
|
pclose(fp);
|
|
} else if (strncmp(dialog->type, "text:", 5) == 0) {
|
|
len = lnprintf(buf, size, "%s", dialog->type + 5);
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
int easy_ssl_client_authenticate(easy_ssl_t* ssl, SSL* conn, const void* host, int len)
|
|
{
|
|
uint64_t key = easy_hash_code(host, len, 3);
|
|
easy_ssl_ctx_server_t* cs =
|
|
(easy_ssl_ctx_server_t*)easy_hash_find_ex(ssl->server_map, key, easy_ssl_ctx_server_cmp, host);
|
|
|
|
if (cs && cs->ss->conf.verify) {
|
|
long rc = SSL_get_verify_result(conn);
|
|
|
|
if (rc != X509_V_OK) {
|
|
easy_error_log("client SSL certificate verify error: (%l:%s)", rc, X509_verify_cert_error_string(rc));
|
|
return 0;
|
|
}
|
|
|
|
if (cs->ss->conf.verify == 1) {
|
|
X509* cert = SSL_get_peer_certificate(conn);
|
|
|
|
if (cert == NULL) {
|
|
easy_error_log("client sent no required SSL certificate");
|
|
return 0;
|
|
}
|
|
|
|
X509_free(cert);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|