Merge branch 'v2.x' into v2.1.2-cluster

pull/3305/head
René Cannaò 5 years ago
commit 48562faaf1

@ -1,92 +1,31 @@
#ifndef CLASS_MYSQL_LDAP_AUTHENTICATION_H
#define CLASS_MYSQL_LDAP_AUTHENTICATION_H
/*
#include "proxysql.h"
#include "cpp.h"
#ifndef LDAP_ACCOUNT_DETAILS_T
#define LDAP_ACCOUNT_DETAILS_T
typedef struct _ldap_account_details_t {
char *username;
char *password;
void *sha1_pass;
bool use_ssl;
int default_hostgroup;
char *default_schema;
bool schema_locked;
bool transaction_persistent;
// bool fast_forward;
// int max_connections;
// int num_connections_used;
// bool __frontend; // this is used only during the dump
// bool __backend; // this is used only during the dump
// bool __active;
unsigned long long inserted_at;
char *ad_group;
} ldap_account_details_t;
typedef std::map<uint64_t, ldap_account_details_t *> umap_auth;
#endif // LDAP_ACCOUNT_DETAILS_T
#ifdef DEBUG
#define DEB "_DEBUG"
#else
#define DEB ""
#endif // DEBUG
#define MYSQL_LDAP_AUTHENTICATION_VERSION "1.0.0000" DEB
class PtrArray;
#ifndef CREDS_GROUPS_T
#define CREDS_GROUPS_T
typedef struct _creds_group_t {
pthread_rwlock_t lock;
umap_auth bt_map;
PtrArray *cred_array;
} creds_group_t;
#endif // CREDS_GROUPS_T
*/
class MySQL_LDAP_Authentication {
/*
private:
// creds_group_t creds_backends;
creds_group_t creds_frontends;
bool _reset(enum cred_username_type usertype);
// uint64_t _get_runtime_checksum(enum cred_username_type usertype);
*/
public:
MySQL_LDAP_Authentication() {};
virtual ~MySQL_LDAP_Authentication() {};
virtual bool add(char *username, char *backend_username, char *password, enum cred_username_type usertype, bool use_ssl, int default_hostgroup, char *default_schema, bool schema_locked, bool transaction_persistent, bool fast_forward, int max_connections) {return false;};
virtual bool del(char *username, enum cred_username_type usertype, bool set_lock=true) {return false;};
virtual bool reset() {return false;};
virtual void print_version() {};
virtual char * lookup(void *ldap_ctx, char *username, char *pass, enum cred_username_type usertype, bool *use_ssl, int *default_hostgroup, char **default_schema, bool *schema_locked, bool *transaction_persistent, bool *fast_forward, int *max_connections, void **sha1_pass, char **backend_username) {return NULL;};
//virtual int dump_all_users(account_details_t ***, bool _complete=true) {return 0;};
virtual int increase_frontend_user_connections(char *username, int *mc=NULL) {return 0;};
public:
virtual char * lookup(char *username, char *pass,
enum cred_username_type usertype, bool *use_ssl, int *default_hostgroup,
char **default_schema, bool *schema_locked, bool *transaction_persistent,
bool *fast_forward, int *max_connections, void **sha1_pass, char **attributes,
char **backend_username) {return NULL;};
virtual int increase_frontend_user_connections(char *username, int *max_connections = NULL) { return 0; };
virtual void decrease_frontend_user_connections(char *username) {};
virtual void set_all_inactive(enum cred_username_type usertype) {};
virtual void remove_inactives(enum cred_username_type usertype) {};
virtual bool set_SHA1(char *username, enum cred_username_type usertype, void *sha_pass) {return false;};
// unsigned int memory_usage();
// uint64_t get_runtime_checksum();
virtual void * ldap_ctx_init() {return NULL;};
virtual void ldap_ctx_free(void *) {};
virtual char **get_variables_list() {return NULL;}
virtual bool has_variable(const char *name) {return false;};
virtual void wrlock() {};
virtual void wrunlock() {};
virtual char **get_variables_list() {return NULL;}
virtual bool has_variable(const char *name) {return false;};
virtual char * get_variable(char *name) {return NULL;};
virtual bool set_variable(char *name, char *value) {return false;};
virtual int password_matches(char *u, char *pass) {return 0;}; // 0 = not match , 1 = matches , 2 = not present
virtual void load_mysql_ldap_mapping(SQLite3_result *result) {};
virtual SQLite3_result * dump_table_mysql_ldap_mapping() { return NULL; };
virtual uint64_t get_ldap_mapping_runtime_checksum() { return 0; };
virtual SQLite3_result * SQL3_getStats() { return NULL; }
virtual void print_version() {};
};
typedef MySQL_LDAP_Authentication * create_MySQL_LDAP_Authentication_t();

@ -249,8 +249,8 @@ class MySQL_Session
Session_Regex **match_regexes;
void *ldap_ctx;
ProxySQL_Node_Address * proxysql_node_address; // this is used ONLY for Admin, and only if the other party is another proxysql instance part of a cluster
bool use_ldap_auth;
// this variable is relevant only if status == SETTING_VARIABLE
enum variable_name changing_variable_idx;

@ -69,6 +69,8 @@ class ProxySQL_GlobalVariables {
char * sqlite3_plugin;
char * web_interface_plugin;
char * ldap_auth_plugin;
SSL * get_SSL_ctx();
void get_SSL_pem_mem(char **key, char **cert);
std::shared_ptr<prometheus::Registry> prometheus_registry { nullptr };
struct {
unsigned long long start_time;
@ -93,7 +95,12 @@ class ProxySQL_GlobalVariables {
char *pidfile;
bool restart_on_error;
int restart_delay;
std::mutex ssl_mutex;
SSL_CTX *ssl_ctx;
SSL_CTX *tmp_ssl_ctx;
// these two buffers are used for the web interface
char * ssl_key_pem_mem;
char * ssl_cert_pem_mem;
bool sqlite3_server;
#ifdef PROXYSQLCLICKHOUSE
bool clickhouse_server;

@ -2154,7 +2154,7 @@ void * monitor_replication_lag_thread(void *arg) {
int l = strlen(percona_heartbeat_table);
if (l) {
use_percona_heartbeat = true;
char *base_query = (char *)"SELECT MIN(ROUND(TIMESTAMPDIFF(MICROSECOND, ts, SYSDATE(6))/1000000)) AS Seconds_Behind_Master FROM %s";
char *base_query = (char *)"SELECT MAX(ROUND(TIMESTAMPDIFF(MICROSECOND, ts, SYSDATE(6))/1000000)) AS Seconds_Behind_Master FROM %s";
char *replication_query = (char *)malloc(strlen(base_query)+l);
sprintf(replication_query,base_query,percona_heartbeat_table);
mmsd->async_exit_status=mysql_query_start(&mmsd->interr,mmsd->mysql,replication_query);

@ -1501,26 +1501,26 @@ bool MySQL_Protocol::process_pkt_handshake_response(unsigned char *pkt, unsigned
#ifdef DEBUG
if (dump_pkt) { __dump_pkt(__func__,pkt,len); }
#endif
bool ret=false;
bool ret = false;
unsigned int charset;
uint32_t capabilities = 0;
uint32_t max_pkt;
uint32_t pass_len;
unsigned char *user=NULL;
char *db=NULL;
unsigned char *user = NULL;
char *db = NULL;
char *db_tmp = NULL;
unsigned char *pass = NULL;
MySQL_Connection *myconn = NULL;
char *password=NULL;
bool use_ssl=false;
bool _ret_use_ssl=false;
char *password = NULL;
bool use_ssl = false;
bool _ret_use_ssl = false;
unsigned char *auth_plugin = NULL;
int auth_plugin_id = 0;
char reply[SHA_DIGEST_LENGTH+1];
reply[SHA_DIGEST_LENGTH]='\0';
int default_hostgroup=-1;
char *default_schema=NULL;
char *default_schema = NULL;
char *attributes = NULL;
bool schema_locked;
bool transaction_persistent = true;
@ -1811,7 +1811,7 @@ __do_auth:
(*myds)->sess->session_fast_forward=fast_forward;
(*myds)->sess->user_max_connections=max_connections;
}
if (password==NULL) {
if (password == NULL) {
// this is a workaround for bug #603
if (
((*myds)->sess->session_type == PROXYSQL_SESSION_ADMIN)
@ -1854,8 +1854,10 @@ __do_auth:
}
#endif // debug
char *backend_username = NULL;
(*myds)->sess->ldap_ctx = GloMyLdapAuth->ldap_ctx_init();
password = GloMyLdapAuth->lookup((*myds)->sess->ldap_ctx, (char *)user, (char *)pass, USERNAME_FRONTEND, &_ret_use_ssl, &default_hostgroup, &default_schema, &schema_locked, &transaction_persistent, &fast_forward, &max_connections, &sha1_pass, &backend_username);
(*myds)->sess->use_ldap_auth = true;
password = GloMyLdapAuth->lookup((char *) user, (char *) pass, USERNAME_FRONTEND,
&_ret_use_ssl, &default_hostgroup, &default_schema, &schema_locked,
&transaction_persistent, &fast_forward, &max_connections, &sha1_pass, &attributes, &backend_username);
if (password) {
#ifdef DEBUG
char *tmp_pass=strdup(password);
@ -1868,7 +1870,7 @@ __do_auth:
#endif // debug
(*myds)->sess->default_hostgroup=default_hostgroup;
(*myds)->sess->default_schema=default_schema; // just the pointer is passed
(*myds)->sess->user_attributes = attributes; // just the pointer is passed , but for now not available in LDAP
(*myds)->sess->user_attributes = attributes; // just the pointer is passed, LDAP returns empty string
#ifdef DEBUG
debug_spiffe_id(user,attributes, __LINE__, __func__);
#endif
@ -1876,7 +1878,7 @@ __do_auth:
(*myds)->sess->transaction_persistent=transaction_persistent;
(*myds)->sess->session_fast_forward=fast_forward;
(*myds)->sess->user_max_connections=max_connections;
if (strncmp(password,(char *)pass,strlen(password))==0) {
if (strcmp(password, (char *) pass) == 0) {
if (backend_username) {
free(password);
password=NULL;
@ -1935,8 +1937,8 @@ __do_auth:
ret=true;
}
} else { // mysql_clear_password
if (strncmp(password,(char *)pass,strlen(password))==0) {
ret=true;
if (strcmp(password, (char *) pass) == 0) {
ret = true;
}
}
} else {

@ -504,8 +504,8 @@ MySQL_Session::MySQL_Session() {
last_insert_id=0; // #1093
last_HG_affected_rows = -1; // #1421 : advanced support for LAST_INSERT_ID()
ldap_ctx = NULL;
proxysql_node_address = NULL;
use_ldap_auth = false;
}
void MySQL_Session::init() {
@ -589,6 +589,7 @@ MySQL_Session::~MySQL_Session() {
}
if (user_attributes) {
free(user_attributes);
user_attributes = NULL;
}
proxy_debug(PROXY_DEBUG_NET,1,"Thread=%p, Session=%p -- Shutdown Session %p\n" , this->thread, this, this);
delete command_counters;
@ -602,10 +603,6 @@ MySQL_Session::~MySQL_Session() {
__sync_sub_and_fetch(&GloMTH->status_variables.mirror_sessions_current,1);
GloMTH->status_variables.p_gauge_array[p_th_gauge::mirror_concurrency]->Decrement();
}
if (ldap_ctx) {
GloMyLdapAuth->ldap_ctx_free(ldap_ctx);
ldap_ctx = NULL;
}
if (proxysql_node_address) {
delete proxysql_node_address;
proxysql_node_address = NULL;
@ -2038,7 +2035,7 @@ bool MySQL_Session::handler_again___status_SETTING_LDAP_USER_VARIABLE(int *_rc)
enum session_status st=status;
if (
(GloMyLdapAuth==NULL) || (ldap_ctx==NULL)
(GloMyLdapAuth==NULL) || (use_ldap_auth==false)
||
(client_myds==NULL || client_myds->myconn==NULL || client_myds->myconn->userinfo==NULL)
) { // nothing to do
@ -4380,7 +4377,7 @@ handler_again:
if (handler_again___verify_init_connect()) {
goto handler_again;
}
if (ldap_ctx) {
if (use_ldap_auth) {
if (handler_again___verify_ldap_user_variable()) {
goto handler_again;
}
@ -4835,7 +4832,7 @@ void MySQL_Session::handler___status_CONNECTING_CLIENT___STATE_SERVER_HANDSHAKE(
client_myds->DSS=STATE_SSL_INIT;
client_myds->rbio_ssl = BIO_new(BIO_s_mem());
client_myds->wbio_ssl = BIO_new(BIO_s_mem());
client_myds->ssl=SSL_new(GloVars.global.ssl_ctx);
client_myds->ssl = GloVars.get_SSL_ctx();
SSL_set_fd(client_myds->ssl, client_myds->fd);
SSL_set_accept_state(client_myds->ssl);
SSL_set_bio(client_myds->ssl, client_myds->rbio_ssl, client_myds->wbio_ssl);
@ -4902,10 +4899,10 @@ void MySQL_Session::handler___status_CONNECTING_CLIENT___STATE_SERVER_HANDSHAKE(
//#endif // TEST_AURORA || TEST_GALERA || TEST_GROUPREP
case PROXYSQL_SESSION_MYSQL:
proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION,8,"Session=%p , DS=%p , session_type=PROXYSQL_SESSION_MYSQL\n", this, client_myds);
if (ldap_ctx==NULL) {
free_users=GloMyAuth->increase_frontend_user_connections(client_myds->myconn->userinfo->username, &used_users);
if (use_ldap_auth == false) {
free_users = GloMyAuth->increase_frontend_user_connections(client_myds->myconn->userinfo->username, &used_users);
} else {
free_users=GloMyLdapAuth->increase_frontend_user_connections(client_myds->myconn->userinfo->username, &used_users);
free_users = GloMyLdapAuth->increase_frontend_user_connections(client_myds->myconn->userinfo->fe_username, &used_users);
}
break;
#ifdef PROXYSQLCLICKHOUSE
@ -6186,10 +6183,10 @@ void MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C
reset();
init();
if (client_authenticated) {
if (ldap_ctx==NULL) {
if (use_ldap_auth == false) {
GloMyAuth->decrease_frontend_user_connections(client_myds->myconn->userinfo->username);
} else {
GloMyLdapAuth->decrease_frontend_user_connections(client_myds->myconn->userinfo->username);
GloMyLdapAuth->decrease_frontend_user_connections(client_myds->myconn->userinfo->fe_username);
}
}
client_authenticated=false;
@ -6929,7 +6926,7 @@ bool MySQL_Session::handle_command_query_kill(PtrSize_t *pkt) {
void MySQL_Session::add_ldap_comment_to_pkt(PtrSize_t *_pkt) {
if (GloMyLdapAuth==NULL)
return;
if (ldap_ctx==NULL)
if (use_ldap_auth == false)
return;
if (client_myds==NULL || client_myds->myconn==NULL || client_myds->myconn->userinfo==NULL)
return;

@ -84,6 +84,7 @@ char * proxysql_version = NULL;
MARIADB_CHARSET_INFO * proxysql_find_charset_name(const char *name);
/*
static long
get_file_size (const char *filename) {
FILE *fp;
@ -121,7 +122,7 @@ static char * load_file (const char *filename) {
fclose (fp);
return buffer;
}
*/
static int round_intv_to_time_interval(int& intv) {
if (intv > 300) {
@ -299,6 +300,8 @@ extern SQLite3_Server *GloSQLite3Server;
extern char * binary_sha1;
extern int ProxySQL_create_or_load_TLS(bool bootstrap, std::string& msg);
#define PANIC(msg) { perror(msg); exit(EXIT_FAILURE); }
pthread_mutex_t sock_mutex = PTHREAD_MUTEX_INITIALIZER;
@ -1603,6 +1606,19 @@ bool admin_handler_command_proxysql(char *query_no_space, unsigned int query_no_
return false;
}
if (strcasecmp("PROXYSQL RELOAD TLS",query_no_space) == 0) {
proxy_info("Received %s command\n", query_no_space);
ProxySQL_Admin *SPA=(ProxySQL_Admin *)pa;
std::string s;
int rc = ProxySQL_create_or_load_TLS(false, s);
if (rc == 0) {
SPA->send_MySQL_OK(&sess->client_myds->myprot, s.length() ? (char *)s.c_str() : NULL);
} else {
SPA->send_MySQL_ERR(&sess->client_myds->myprot, s.length() ? (char *)s.c_str() : (char *)"RELOAD TLS failed");
}
return false;
}
#ifndef NOJEM
if (query_no_space_length==strlen("PROXYSQL MEMPROFILE START") && !strncasecmp("PROXYSQL MEMPROFILE START",query_no_space, query_no_space_length)) {
bool en=true;
@ -6175,8 +6191,7 @@ void ProxySQL_Admin::flush_admin_variables___database_to_runtime(SQLite3DB *db,
if (GloVars.web_interface_plugin == NULL) {
char *key_pem;
char *cert_pem;
key_pem = load_file(ssl_key_fp);
cert_pem = load_file(ssl_cert_fp);
GloVars.get_SSL_pem_mem(&key_pem, &cert_pem);
Admin_HTTP_Server = MHD_start_daemon(MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | MHD_USE_SSL,
variables.web_port,
NULL, NULL, http_handler, NULL,
@ -6239,8 +6254,7 @@ void ProxySQL_Admin::flush_admin_variables___database_to_runtime(SQLite3DB *db,
Admin_HTTP_Server = NULL;
char *key_pem;
char *cert_pem;
key_pem = load_file(ssl_key_fp);
cert_pem = load_file(ssl_cert_fp);
GloVars.get_SSL_pem_mem(&key_pem, &cert_pem);
Admin_HTTP_Server = MHD_start_daemon(MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | MHD_USE_SSL,
variables.web_port,
NULL, NULL, http_handler, NULL,

@ -167,26 +167,43 @@ enum sslstatus MySQL_Data_Stream::do_ssl_handshake() {
int n = SSL_do_handshake(ssl);
if (n == 1) {
//proxy_info("SSL handshake completed\n");
long rc = SSL_get_verify_result(ssl);
if (rc != X509_V_OK && rc != X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN && rc != X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) {
proxy_error("Disconnecting %s:%d: X509 client SSL certificate verify error: (%d:%s)\n" , addr.addr, addr.port, rc, X509_verify_cert_error_string(rc));
return SSLSTATUS_FAIL;
} else {
X509 *cert;
cert = SSL_get_peer_certificate(ssl);
if (cert) {
ASN1_STRING *str;
GENERAL_NAME *sanName;
STACK_OF(GENERAL_NAME) *san_names = NULL;
san_names = (stack_st_GENERAL_NAME *)X509_get_ext_d2i((X509 *) cert, NID_subject_alt_name, NULL, NULL);
if (san_names) {
sanName = sk_GENERAL_NAME_value(san_names, 0);
str = sanName->d.dNSName;
proxy_info("%s\n" , str->data);
x509_subject_alt_name = strdup((const char*)str->data);
X509 *cert;
cert = SSL_get_peer_certificate(ssl);
if (cert) {
GENERAL_NAMES *alt_names = (stack_st_GENERAL_NAME *)X509_get_ext_d2i((X509*)cert, NID_subject_alt_name, 0, 0);
int alt_name_count = sk_GENERAL_NAME_num(alt_names);
// Iterate all the SAN names, looking for SPIFFE identifier
for (int i = 0; i < alt_name_count; i++) {
GENERAL_NAME *san = sk_GENERAL_NAME_value(alt_names, i);
// We only care about URI names
if (san->type == GEN_URI) {
if (san->d.uniformResourceIdentifier->data) {
const char* resource_data =
reinterpret_cast<const char*>(san->d.uniformResourceIdentifier->data);
const char* spiffe_loc = strstr(resource_data, "spiffe");
// First name starting with 'spiffe' is considered the match.
if (spiffe_loc == resource_data) {
x509_subject_alt_name = strdup(resource_data);
}
}
}
} else {
proxy_error("X509 error: no required certificate sent by client\n");
}
} else {
// we currently disable this annoying error
// in future we can configure this as per user level, specifying if the certificate is mandatory or not
// see issue #3424
//proxy_error("X509 error: no required certificate sent by client\n");
}
// In case the supplied certificate has a 'SAN'-'URI' identifier
// starting with 'spiffe', client certificate verification is performed.
if (x509_subject_alt_name != NULL) {
long rc = SSL_get_verify_result(ssl);
if (rc != X509_V_OK) {
proxy_error("Disconnecting %s:%d: X509 client SSL certificate verify error: (%d:%s)\n" , addr.addr, addr.port, rc, X509_verify_cert_error_string(rc));
return SSLSTATUS_FAIL;
}
}
}
@ -349,6 +366,14 @@ MySQL_Data_Stream::~MySQL_Data_Stream() {
}
if ( (myconn) && (myds_type==MYDS_FRONTEND) ) { delete myconn; myconn=NULL; }
if (encrypted) {
if (ssl) {
// NOTE: SSL standard requires a final 'close_notify' alert on socket
// shutdown. But for avoiding any kind of locking IO waiting for the
// other part, we perform a 'quiet' shutdown. For more context see
// MYSQL #29579.
SSL_set_quiet_shutdown(ssl, 1);
SSL_shutdown(ssl);
}
if (ssl) SSL_free(ssl);
/*
SSL_free() should also take care of these
@ -428,7 +453,12 @@ void MySQL_Data_Stream::shut_hard() {
proxy_debug(PROXY_DEBUG_NET, 4, "Shutdown hard fd=%d. Session=%p, DataStream=%p\n", fd, sess, this);
set_net_failure();
if (encrypted) {
// NOTE: SSL standard requires a final 'close_notify' alert on socket
// shutdown. But for avoiding any kind of locking IO waiting for the
// other part, we perform a 'quiet' shutdown. For more context see
// MYSQL #29579.
SSL_set_quiet_shutdown(ssl, 1);
SSL_shutdown(ssl);
}
if (fd >= 0) {
shutdown(fd, SHUT_RDWR);

@ -153,7 +153,7 @@ ODIR= obj
EXECUTABLE=proxysql
_OBJ = main.o proxysql_global.o SQLite3_Server.o
_OBJ = main.o proxysql_global.o SQLite3_Server.o proxy_tls.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.cpp

@ -58,10 +58,8 @@ void * __mysql_ldap_auth;
volatile create_Web_Interface_t * create_Web_Interface = NULL;
void * __web_interface;
// absolute path of ssl files
char *ssl_key_fp = NULL;
char *ssl_cert_fp = NULL;
char *ssl_ca_fp = NULL;
extern int ProxySQL_create_or_load_TLS(bool bootstrap, std::string& msg);
char *binary_sha1 = NULL;
@ -70,29 +68,6 @@ char *binary_sha1 = NULL;
#undef dlerror
#endif
struct dh_st {
int pad;
int version;
BIGNUM *p;
BIGNUM *g;
long length;
BIGNUM *pub_key;
BIGNUM *priv_key;
int flags;
BN_MONT_CTX *method_mont_p;
BIGNUM *q;
BIGNUM *j;
unsigned char *seed;
int seedlen;
BIGNUM *counter;
int references;
CRYPTO_EX_DATA ex_data;
const DH_METHOD *meth;
ENGINE *engine;
CRYPTO_RWLOCK *lock;
};
static pthread_mutex_t *lockarray;
#include <openssl/crypto.h>
@ -107,69 +82,6 @@ static void * waitpid_thread(void *arg) {
}
/*
generated with: $ openssl dhparam -5 -C 2048
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEAtS5UPzxesyj7QtLe6hRGE1Cv4TnDbSzKTmy0izFabdn0wR1QVmij
S8YSb1jE+O7IGImtk84Wg4y141PAHkCMTEeCMKH5tOD0WfiVyuQDTp4Vbt0vOReM
hK7tgLHLC1P3v0nxFCcce3U6IXmXBQ9IkNMFcXSRIAdBOjPkFPfbZ648qSgcoX+z
gfEP9WAXeeNGk62rDb3R0mguA9HcQ4NyKk6ETBVsZD4bTAcSIBaX05ISV7qY2eLj
9HFYBXYX4cxBfMyiqGrCj2IMg8aRKmf7rTvwBQXT0cWmu+kpnlpXIjx6vdpBmeKd
hSypLEcUVIvzc6rtfWlYKT35wQ+AGKNADwIBBQ==
-----END DH PARAMETERS-----
*/
int callback_ssl_verify_peer(int ok, X509_STORE_CTX* ctx) {
// for now only return 1
return 1;
}
#ifndef HEADER_DH_H
#include <openssl/dh.h>
#endif
DH *get_dh2048()
{
static unsigned char dh2048_p[]={
0xB5,0x2E,0x54,0x3F,0x3C,0x5E,0xB3,0x28,0xFB,0x42,0xD2,0xDE,
0xEA,0x14,0x46,0x13,0x50,0xAF,0xE1,0x39,0xC3,0x6D,0x2C,0xCA,
0x4E,0x6C,0xB4,0x8B,0x31,0x5A,0x6D,0xD9,0xF4,0xC1,0x1D,0x50,
0x56,0x68,0xA3,0x4B,0xC6,0x12,0x6F,0x58,0xC4,0xF8,0xEE,0xC8,
0x18,0x89,0xAD,0x93,0xCE,0x16,0x83,0x8C,0xB5,0xE3,0x53,0xC0,
0x1E,0x40,0x8C,0x4C,0x47,0x82,0x30,0xA1,0xF9,0xB4,0xE0,0xF4,
0x59,0xF8,0x95,0xCA,0xE4,0x03,0x4E,0x9E,0x15,0x6E,0xDD,0x2F,
0x39,0x17,0x8C,0x84,0xAE,0xED,0x80,0xB1,0xCB,0x0B,0x53,0xF7,
0xBF,0x49,0xF1,0x14,0x27,0x1C,0x7B,0x75,0x3A,0x21,0x79,0x97,
0x05,0x0F,0x48,0x90,0xD3,0x05,0x71,0x74,0x91,0x20,0x07,0x41,
0x3A,0x33,0xE4,0x14,0xF7,0xDB,0x67,0xAE,0x3C,0xA9,0x28,0x1C,
0xA1,0x7F,0xB3,0x81,0xF1,0x0F,0xF5,0x60,0x17,0x79,0xE3,0x46,
0x93,0xAD,0xAB,0x0D,0xBD,0xD1,0xD2,0x68,0x2E,0x03,0xD1,0xDC,
0x43,0x83,0x72,0x2A,0x4E,0x84,0x4C,0x15,0x6C,0x64,0x3E,0x1B,
0x4C,0x07,0x12,0x20,0x16,0x97,0xD3,0x92,0x12,0x57,0xBA,0x98,
0xD9,0xE2,0xE3,0xF4,0x71,0x58,0x05,0x76,0x17,0xE1,0xCC,0x41,
0x7C,0xCC,0xA2,0xA8,0x6A,0xC2,0x8F,0x62,0x0C,0x83,0xC6,0x91,
0x2A,0x67,0xFB,0xAD,0x3B,0xF0,0x05,0x05,0xD3,0xD1,0xC5,0xA6,
0xBB,0xE9,0x29,0x9E,0x5A,0x57,0x22,0x3C,0x7A,0xBD,0xDA,0x41,
0x99,0xE2,0x9D,0x85,0x2C,0xA9,0x2C,0x47,0x14,0x54,0x8B,0xF3,
0x73,0xAA,0xED,0x7D,0x69,0x58,0x29,0x3D,0xF9,0xC1,0x0F,0x80,
0x18,0xA3,0x40,0x0F,
};
static unsigned char dh2048_g[]={
0x05,
};
DH *dh;
if ((dh=DH_new()) == NULL) return(NULL);
dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL);
dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL);
if ((dh->p == NULL) || (dh->g == NULL))
{ DH_free(dh); return(NULL); }
return(dh);
}
struct MemoryStruct {
char *memory;
@ -347,255 +259,9 @@ static void init_locks(void) {
//CRYPTO_set_locking_callback((void (*)(int, int, const char *, int))lock_callback);
}
X509 * generate_x509(EVP_PKEY *pkey, const unsigned char *cn, uint32_t serial, int days, X509 *ca_x509, EVP_PKEY *ca_pkey) {
int rc;
X509 * x = NULL;
X509_NAME * name= NULL;
X509_EXTENSION* ext = NULL;
X509V3_CTX v3_ctx;
if ((x = X509_new()) == NULL) {
proxy_error("Unable to run X509_new()\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
X509_set_version(x, 2);
ASN1_INTEGER_set(X509_get_serialNumber(x), serial);
X509_gmtime_adj(X509_get_notBefore(x), 0);
X509_gmtime_adj(X509_get_notAfter(x), (long)60 * 60 * 24 * days);
rc = X509_set_pubkey(x, pkey);
if (rc==0){
proxy_error("Unable to set pubkey: %s\n", ERR_error_string(ERR_get_error(),NULL));
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
name = X509_get_subject_name(x);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, cn, -1, -1, 0);
if (ca_x509) {
rc = X509_set_issuer_name(x, X509_get_subject_name(ca_x509));
} else {
rc = X509_set_issuer_name(x, name);
}
if (rc==0) {
proxy_error("Unable to set issuer: %s\n", ERR_error_string(ERR_get_error(),NULL));
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
// set the context
X509V3_set_ctx(&v3_ctx, ca_x509 ? ca_x509 : x, x, NULL, NULL, 0);
ext = X509V3_EXT_conf_nid(
NULL, &v3_ctx, NID_basic_constraints, ca_x509 ? "critical, CA:FALSE" : "critical, CA:TRUE");
if (ext) {
X509_add_ext(x, ext, -1);
X509_EXTENSION_free(ext);
} else {
proxy_error("Unable to set certificate extensions: %s\n", ERR_error_string(ERR_get_error(),NULL));
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
if (ca_pkey) {
rc = X509_sign(x, ca_pkey, EVP_sha256());
} else {
rc = X509_sign(x, pkey, EVP_sha256());
}
if (rc==0) {
proxy_error("Unable to X509 sign: %s\n", ERR_error_string(ERR_get_error(),NULL));
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
return x;
}
void write_x509(const char *filen, X509 *x) {
BIO * x509file = NULL;
x509file = BIO_new_file(filen, "w" );
if (!x509file ) {
proxy_error("Error on BIO_new_file\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
if (!PEM_write_bio_X509( x509file, x)) {
proxy_error("Error on PEM_write_bio_X509 for %s\n", filen);
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
BIO_free_all( x509file );
}
void write_rsa_key(const char *filen, RSA *rsa) {
BIO* pOut = BIO_new_file(filen, "w");
if (!pOut) {
proxy_error("Error on BIO_new_file\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
if (!PEM_write_bio_RSAPrivateKey( pOut, rsa, NULL, NULL, 0, NULL, NULL)) {
proxy_error("Error on PEM_write_bio_RSAPrivateKey for %s\n", filen);
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
BIO_free_all( pOut );
}
EVP_PKEY * rsa_key_read(const char *filen) {
EVP_PKEY * pkey = NULL;
RSA * rsa = NULL;
BIO * pIn = BIO_new_file(filen,"r");
if (!pIn) {
proxy_error("Error on BIO_new_file\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
rsa= PEM_read_bio_RSAPrivateKey( pIn , NULL, NULL, NULL);
if (rsa==NULL) {
proxy_error("Error on PEM_read_bio_RSAPrivateKey for %s\n", filen);
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
pkey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pkey, rsa);
BIO_free(pIn);
return pkey;
}
X509 * read_x509(const char *filen) {
X509 * x = NULL;
BIO * x509file = NULL;
x509file = BIO_new_file(filen, "r" );
if (!x509file ) {
proxy_error("Error on BIO_new_file\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
x = PEM_read_bio_X509( x509file, NULL, NULL, NULL);
if (x == NULL) {
proxy_error("Error on PEM_read_bio_X509 for %s\n", filen);
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
BIO_free_all( x509file );
return x;
}
int ssl_mkit(X509 **x509ca, X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days) {
X509 *x1;
X509 *x2;
EVP_PKEY *pk;
RSA *rsa;
DH *dh;
//X509_NAME *name = NULL;
// relative path to datadir of ssl files
const char * ssl_key_rp = (const char *)"proxysql-key.pem";
const char * ssl_cert_rp = (const char *)"proxysql-cert.pem";
const char * ssl_ca_rp = (const char *)"proxysql-ca.pem";
/*
// absolute path of ssl files
char *ssl_key_fp = NULL;
char *ssl_cert_fp = NULL;
char *ssl_ca_fp = NULL;
*/
// how many files exists ?
int nfiles = 0;
bool ssl_key_exists = true;
bool ssl_cert_exists = true;
bool ssl_ca_exists = true;
// check if files exists
ssl_key_fp = (char *)malloc(strlen(GloVars.datadir)+strlen(ssl_key_rp)+8);
sprintf(ssl_key_fp,"%s/%s",GloVars.datadir,ssl_key_rp);
if (access(ssl_key_fp, R_OK)) {
ssl_key_exists = false;
//free(ssl_key);
//ssl_key = NULL;
}
ssl_cert_fp = (char *)malloc(strlen(GloVars.datadir)+strlen(ssl_cert_rp)+8);
sprintf(ssl_cert_fp,"%s/%s",GloVars.datadir,ssl_cert_rp);
if (access(ssl_cert_fp, R_OK)) {
ssl_cert_exists = false;
//free(ssl_cert);
//ssl_cert = NULL;
}
ssl_ca_fp = (char *)malloc(strlen(GloVars.datadir)+strlen(ssl_ca_rp)+8);
sprintf(ssl_ca_fp,"%s/%s",GloVars.datadir,ssl_ca_rp);
if (access(ssl_ca_fp, R_OK)) {
ssl_ca_exists = false;
//free(ssl_ca);
//ssl_ca = NULL;
}
nfiles += (ssl_key_exists ? 1 : 0);
nfiles += (ssl_cert_exists ? 1 : 0);
nfiles += (ssl_ca_exists ? 1 : 0);
if ((nfiles != 0 && nfiles != 3)) {
proxy_error("Only some SSL files are present. Either all files are present, or none. Exiting.\n");
proxy_error("%s : %s\n" , ssl_key_rp, (ssl_key_exists ? (char *)"YES" : (char *)"NO"));
proxy_error("%s : %s\n" , ssl_cert_rp, (ssl_cert_exists ? (char *)"YES" : (char *)"NO"));
proxy_error("%s : %s\n" , ssl_ca_rp, (ssl_ca_exists ? (char *)"YES" : (char *)"NO"));
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
if (nfiles == 0) {
proxy_info("No SSL keys/certificates found in datadir (%s). Generating new keys/certificates.\n", GloVars.datadir);
if ((pkeyp == NULL) || (*pkeyp == NULL)) {
if ((pk = EVP_PKEY_new()) == NULL) {
proxy_error("Unable to run EVP_PKEY_new()\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
} else
pk = *pkeyp;
rsa = RSA_new();
if (!rsa) {
proxy_error("Unable to run RSA_new()\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
BIGNUM *e= BN_new();
if (!e) {
proxy_error("Unable to run BN_new()\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
if (!BN_set_word(e, RSA_F4) || !RSA_generate_key_ex(rsa, bits, e, NULL)) {
RSA_free(rsa);
BN_free(e);
proxy_error("Unable to run BN_new()\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
BN_free(e);
write_rsa_key(ssl_key_fp, rsa);
if (!EVP_PKEY_assign_RSA(pk, rsa)) {
proxy_error("Unable to run EVP_PKEY_assign_RSA()\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
time_t t = time(NULL);
x1 = generate_x509(pk, (const unsigned char *)"ProxySQL_Auto_Generated_CA_Certificate", t, 3650, NULL, NULL);
write_x509(ssl_ca_fp, x1);
x2 = generate_x509(pk, (const unsigned char *)"ProxySQL_Auto_Generated_Server_Certificate", t, 3650, x1, pk);
write_x509(ssl_cert_fp, x2);
rsa = NULL;
} else {
proxy_info("SSL keys/certificates found in datadir (%s): loading them.\n", GloVars.datadir);
pk = rsa_key_read(ssl_key_fp);
x1 = read_x509(ssl_ca_fp);
x2 = read_x509(ssl_cert_fp);
}
*x509ca = x1;
*x509p = x2;
*pkeyp = pk;
dh = get_dh2048();
if (SSL_CTX_set_tmp_dh(GloVars.global.ssl_ctx, dh) == 0) {
proxy_error("Error in SSL while initializing DH: %s . Shutting down.\n",ERR_error_string(ERR_get_error(), NULL));
exit(EXIT_SUCCESS); // EXIT_SUCCESS to avoid a restart loop
}
return 1;
}
void ProxySQL_Main_init_SSL_module() {
int rc = SSL_library_init();
if (rc==0) {
@ -630,51 +296,14 @@ void ProxySQL_Main_init_SSL_module() {
char buf[130];
for(int i = 0; i < num; i++){
const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(ciphers, i);
fprintf(stderr,"%s: %s\n", SSL_CIPHER_get_name(cipher), SSL_CIPHER_description(cipher, buf, 128));
fprintf(stderr,"%s: %s", SSL_CIPHER_get_name(cipher), SSL_CIPHER_description(cipher, buf, 128));
}
}
fprintf(stderr,"\n");
}
#endif
BIO *bio_err;
X509 *x509 = NULL;
X509 *x509ca = NULL;
EVP_PKEY *pkey = NULL;
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF);
bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
if (ssl_mkit(&x509ca, &x509, &pkey, 2048, 0, 730) == 0) {
proxy_error("Unable to initialize SSL. Shutting down...\n");
exit(EXIT_SUCCESS); // we exit gracefully to not be restarted
}
if ( SSL_CTX_use_certificate(GloVars.global.ssl_ctx, x509) <= 0 ) {
ERR_print_errors_fp(stderr);
proxy_error("Unable to use SSL certificate. Shutting down...\n");
exit(EXIT_SUCCESS); // we exit gracefully to not be restarted
}
if ( SSL_CTX_add_extra_chain_cert(GloVars.global.ssl_ctx, x509ca) <= 0 ) {
ERR_print_errors_fp(stderr);
proxy_error("Unable to use SSL CA chain. Shutting down...\n");
exit(EXIT_SUCCESS); // we exit gracefully to not be restarted
}
if ( SSL_CTX_use_PrivateKey(GloVars.global.ssl_ctx, pkey) <= 0 ) {
ERR_print_errors_fp(stderr);
proxy_error("Unable to use SSL key. Shutting down...\n");
exit(EXIT_SUCCESS); // we exit gracefully to not be restarted
}
if ( !SSL_CTX_check_private_key(GloVars.global.ssl_ctx) ) {
proxy_error("Private key does not match the public certificate\n");
exit(EXIT_SUCCESS); // we exit gracefully to not be restarted
}
SSL_CTX_set_verify(GloVars.global.ssl_ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, callback_ssl_verify_peer);
X509_free(x509);
EVP_PKEY_free(pkey);
BIO_free(bio_err);
std::string msg = "";
ProxySQL_create_or_load_TLS(true, msg);
}

@ -0,0 +1,574 @@
//#include <iostream>
//#include <thread>
#include "proxysql.h"
//#include <sys/types.h>
//#include <sys/stat.h>
#include "cpp.h"
//#include "ProxySQL_Statistics.hpp"
//#include "MySQL_PreparedStatement.h"
//#include "ProxySQL_Cluster.hpp"
//#include "MySQL_Logger.hpp"
//#include "SQLite3_Server.h"
//#include "query_processor.h"
//#include "MySQL_Authentication.hpp"
//#include "MySQL_LDAP_Authentication.hpp"
//#include "proxysql_restapi.h"
//#include "Web_Interface.hpp"
#include <openssl/x509v3.h>
static long
get_file_size (const char *filename) {
FILE *fp;
fp = fopen (filename, "rb");
if (fp) {
long size;
if ((0 != fseek (fp, 0, SEEK_END)) || (-1 == (size = ftell (fp))))
size = 0;
fclose (fp);
return size;
} else
return 0;
}
static char * load_file (const char *filename) {
FILE *fp;
char *buffer;
long size;
size = get_file_size (filename);
if (0 == size)
return NULL;
fp = fopen (filename, "rb");
if (! fp)
return NULL;
buffer = (char *)malloc (size + 1);
if (! buffer) {
fclose (fp);
return NULL;
}
buffer[size] = '\0';
if (size != (long)fread (buffer, 1, size, fp)) {
free (buffer);
buffer = NULL;
}
fclose (fp);
return buffer;
}
// absolute path of ssl files
static char *ssl_key_fp = NULL;
static char *ssl_cert_fp = NULL;
static char *ssl_ca_fp = NULL;
struct dh_st {
int pad;
int version;
BIGNUM *p;
BIGNUM *g;
long length;
BIGNUM *pub_key;
BIGNUM *priv_key;
int flags;
BN_MONT_CTX *method_mont_p;
BIGNUM *q;
BIGNUM *j;
unsigned char *seed;
int seedlen;
BIGNUM *counter;
int references;
CRYPTO_EX_DATA ex_data;
const DH_METHOD *meth;
ENGINE *engine;
CRYPTO_RWLOCK *lock;
};
int callback_ssl_verify_peer(int ok, X509_STORE_CTX* ctx) {
// for now only return 1
return 1;
}
/*
generated with: $ openssl dhparam -5 -C 2048
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEAtS5UPzxesyj7QtLe6hRGE1Cv4TnDbSzKTmy0izFabdn0wR1QVmij
S8YSb1jE+O7IGImtk84Wg4y141PAHkCMTEeCMKH5tOD0WfiVyuQDTp4Vbt0vOReM
hK7tgLHLC1P3v0nxFCcce3U6IXmXBQ9IkNMFcXSRIAdBOjPkFPfbZ648qSgcoX+z
gfEP9WAXeeNGk62rDb3R0mguA9HcQ4NyKk6ETBVsZD4bTAcSIBaX05ISV7qY2eLj
9HFYBXYX4cxBfMyiqGrCj2IMg8aRKmf7rTvwBQXT0cWmu+kpnlpXIjx6vdpBmeKd
hSypLEcUVIvzc6rtfWlYKT35wQ+AGKNADwIBBQ==
-----END DH PARAMETERS-----
*/
#ifndef HEADER_DH_H
#include <openssl/dh.h>
#endif
DH *get_dh2048()
{
static unsigned char dh2048_p[]={
0xB5,0x2E,0x54,0x3F,0x3C,0x5E,0xB3,0x28,0xFB,0x42,0xD2,0xDE,
0xEA,0x14,0x46,0x13,0x50,0xAF,0xE1,0x39,0xC3,0x6D,0x2C,0xCA,
0x4E,0x6C,0xB4,0x8B,0x31,0x5A,0x6D,0xD9,0xF4,0xC1,0x1D,0x50,
0x56,0x68,0xA3,0x4B,0xC6,0x12,0x6F,0x58,0xC4,0xF8,0xEE,0xC8,
0x18,0x89,0xAD,0x93,0xCE,0x16,0x83,0x8C,0xB5,0xE3,0x53,0xC0,
0x1E,0x40,0x8C,0x4C,0x47,0x82,0x30,0xA1,0xF9,0xB4,0xE0,0xF4,
0x59,0xF8,0x95,0xCA,0xE4,0x03,0x4E,0x9E,0x15,0x6E,0xDD,0x2F,
0x39,0x17,0x8C,0x84,0xAE,0xED,0x80,0xB1,0xCB,0x0B,0x53,0xF7,
0xBF,0x49,0xF1,0x14,0x27,0x1C,0x7B,0x75,0x3A,0x21,0x79,0x97,
0x05,0x0F,0x48,0x90,0xD3,0x05,0x71,0x74,0x91,0x20,0x07,0x41,
0x3A,0x33,0xE4,0x14,0xF7,0xDB,0x67,0xAE,0x3C,0xA9,0x28,0x1C,
0xA1,0x7F,0xB3,0x81,0xF1,0x0F,0xF5,0x60,0x17,0x79,0xE3,0x46,
0x93,0xAD,0xAB,0x0D,0xBD,0xD1,0xD2,0x68,0x2E,0x03,0xD1,0xDC,
0x43,0x83,0x72,0x2A,0x4E,0x84,0x4C,0x15,0x6C,0x64,0x3E,0x1B,
0x4C,0x07,0x12,0x20,0x16,0x97,0xD3,0x92,0x12,0x57,0xBA,0x98,
0xD9,0xE2,0xE3,0xF4,0x71,0x58,0x05,0x76,0x17,0xE1,0xCC,0x41,
0x7C,0xCC,0xA2,0xA8,0x6A,0xC2,0x8F,0x62,0x0C,0x83,0xC6,0x91,
0x2A,0x67,0xFB,0xAD,0x3B,0xF0,0x05,0x05,0xD3,0xD1,0xC5,0xA6,
0xBB,0xE9,0x29,0x9E,0x5A,0x57,0x22,0x3C,0x7A,0xBD,0xDA,0x41,
0x99,0xE2,0x9D,0x85,0x2C,0xA9,0x2C,0x47,0x14,0x54,0x8B,0xF3,
0x73,0xAA,0xED,0x7D,0x69,0x58,0x29,0x3D,0xF9,0xC1,0x0F,0x80,
0x18,0xA3,0x40,0x0F,
};
static unsigned char dh2048_g[]={
0x05,
};
DH *dh;
if ((dh=DH_new()) == NULL) return(NULL);
dh->p=BN_bin2bn(dh2048_p,sizeof(dh2048_p),NULL);
dh->g=BN_bin2bn(dh2048_g,sizeof(dh2048_g),NULL);
if ((dh->p == NULL) || (dh->g == NULL))
{ DH_free(dh); return(NULL); }
return(dh);
}
X509 * generate_x509(EVP_PKEY *pkey, const unsigned char *cn, uint32_t serial, int days, X509 *ca_x509, EVP_PKEY *ca_pkey) {
int rc;
X509 * x = NULL;
X509_NAME * name= NULL;
X509_EXTENSION* ext = NULL;
X509V3_CTX v3_ctx;
if ((x = X509_new()) == NULL) {
proxy_error("Unable to run X509_new()\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
X509_set_version(x, 2);
ASN1_INTEGER_set(X509_get_serialNumber(x), serial);
X509_gmtime_adj(X509_get_notBefore(x), 0);
X509_gmtime_adj(X509_get_notAfter(x), (long)60 * 60 * 24 * days);
rc = X509_set_pubkey(x, pkey);
if (rc==0){
proxy_error("Unable to set pubkey: %s\n", ERR_error_string(ERR_get_error(),NULL));
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
name = X509_get_subject_name(x);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, cn, -1, -1, 0);
if (ca_x509) {
rc = X509_set_issuer_name(x, X509_get_subject_name(ca_x509));
} else {
rc = X509_set_issuer_name(x, name);
}
if (rc==0) {
proxy_error("Unable to set issuer: %s\n", ERR_error_string(ERR_get_error(),NULL));
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
// set the context
X509V3_set_ctx(&v3_ctx, ca_x509 ? ca_x509 : x, x, NULL, NULL, 0);
ext = X509V3_EXT_conf_nid(
NULL, &v3_ctx, NID_basic_constraints, ca_x509 ? "critical, CA:FALSE" : "critical, CA:TRUE");
if (ext) {
X509_add_ext(x, ext, -1);
X509_EXTENSION_free(ext);
} else {
proxy_error("Unable to set certificate extensions: %s\n", ERR_error_string(ERR_get_error(),NULL));
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
if (ca_pkey) {
rc = X509_sign(x, ca_pkey, EVP_sha256());
} else {
rc = X509_sign(x, pkey, EVP_sha256());
}
if (rc==0) {
proxy_error("Unable to X509 sign: %s\n", ERR_error_string(ERR_get_error(),NULL));
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
return x;
}
void write_x509(const char *filen, X509 *x) {
BIO * x509file = NULL;
x509file = BIO_new_file(filen, "w" );
if (!x509file ) {
proxy_error("Error on BIO_new_file\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
if (!PEM_write_bio_X509( x509file, x)) {
proxy_error("Error on PEM_write_bio_X509 for %s\n", filen);
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
BIO_free_all( x509file );
}
void write_rsa_key(const char *filen, RSA *rsa) {
BIO* pOut = BIO_new_file(filen, "w");
if (!pOut) {
proxy_error("Error on BIO_new_file\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
if (!PEM_write_bio_RSAPrivateKey( pOut, rsa, NULL, NULL, 0, NULL, NULL)) {
proxy_error("Error on PEM_write_bio_RSAPrivateKey for %s\n", filen);
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
BIO_free_all( pOut );
}
EVP_PKEY * proxy_key_read(const char *filen, bool bootstrap, std::string& msg) {
EVP_PKEY * pkey = NULL;
BIO * pIn = BIO_new_file(filen,"r");
if (!pIn) {
proxy_error("Error on BIO_new_file() while reading %s\n", filen);
if (bootstrap == true) {
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
} else {
msg = "Error on BIO_new_file() while reading " + std::string(filen);
return pkey;
}
}
pkey = PEM_read_bio_PrivateKey( pIn , NULL, NULL, NULL);
if (pkey == NULL) {
proxy_error("Error on PEM_read_bio_PrivateKey for %s\n", filen);
if (bootstrap == true) {
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
} else {
msg = "Error on PEM_read_bio_PrivateKey() for " + std::string(filen);
BIO_free(pIn);
return pkey;
}
}
BIO_free(pIn);
return pkey;
}
X509 * proxy_read_x509(const char *filen, bool bootstrap, std::string& msg) {
X509 * x = NULL;
BIO * x509file = NULL;
x509file = BIO_new_file(filen, "r" );
if (!x509file ) {
proxy_error("Error on BIO_new_file() while reading %s\n", filen);
if (bootstrap == true) {
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
} else {
msg = "Error on BIO_new_file() while reading " + std::string(filen);
return x;
}
}
x = PEM_read_bio_X509( x509file, NULL, NULL, NULL);
if (x == NULL) {
proxy_error("Error on PEM_read_bio_X509 for %s\n", filen);
if (bootstrap == true) {
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
} else {
msg = "Error on PEM_read_bio_X509() for " + std::string(filen);
BIO_free_all(x509file);
return x;
}
}
BIO_free_all( x509file );
return x;
}
// return 0 un success
int ssl_mkit(X509 **x509ca, X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days, bool bootstrap, std::string& msg) {
X509 *x1;
X509 *x2;
EVP_PKEY *pk;
RSA *rsa;
DH *dh;
//X509_NAME *name = NULL;
// relative path to datadir of ssl files
const char * ssl_key_rp = (const char *)"proxysql-key.pem";
const char * ssl_cert_rp = (const char *)"proxysql-cert.pem";
const char * ssl_ca_rp = (const char *)"proxysql-ca.pem";
// how many files exists ?
int nfiles = 0;
bool ssl_key_exists = true;
bool ssl_cert_exists = true;
bool ssl_ca_exists = true;
// check if files exists
if (bootstrap == true) {
ssl_key_fp = (char *)malloc(strlen(GloVars.datadir)+strlen(ssl_key_rp)+8);
sprintf(ssl_key_fp,"%s/%s",GloVars.datadir,ssl_key_rp);
}
if (access(ssl_key_fp, R_OK)) {
ssl_key_exists = false;
}
if (bootstrap == true) {
ssl_cert_fp = (char *)malloc(strlen(GloVars.datadir)+strlen(ssl_cert_rp)+8);
sprintf(ssl_cert_fp,"%s/%s",GloVars.datadir,ssl_cert_rp);
}
if (access(ssl_cert_fp, R_OK)) {
ssl_cert_exists = false;
}
if (bootstrap == true) {
ssl_ca_fp = (char *)malloc(strlen(GloVars.datadir)+strlen(ssl_ca_rp)+8);
sprintf(ssl_ca_fp,"%s/%s",GloVars.datadir,ssl_ca_rp);
}
if (access(ssl_ca_fp, R_OK)) {
ssl_ca_exists = false;
}
nfiles += (ssl_key_exists ? 1 : 0);
nfiles += (ssl_cert_exists ? 1 : 0);
nfiles += (ssl_ca_exists ? 1 : 0);
if (
(bootstrap == true && (nfiles != 0 && nfiles != 3))
||
(bootstrap == false && (nfiles != 3))
) {
if (bootstrap == true) {
proxy_error("Only some SSL files are present. Either all files are present, or none. Exiting.\n");
} else {
proxy_error("Aborting PROXYSQL RELOAD TLS because not all SSL files are present\n");
}
proxy_error("%s : %s\n" , ssl_key_rp, (ssl_key_exists ? (char *)"YES" : (char *)"NO"));
proxy_error("%s : %s\n" , ssl_cert_rp, (ssl_cert_exists ? (char *)"YES" : (char *)"NO"));
proxy_error("%s : %s\n" , ssl_ca_rp, (ssl_ca_exists ? (char *)"YES" : (char *)"NO"));
if (bootstrap == true) {
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
} else {
msg = "RELOAD TLS failed: " + std::to_string(nfiles) + " TLS files are present. Expected: 3";
return 1;
}
}
if (bootstrap == true && nfiles == 0) {
proxy_info("No SSL keys/certificates found in datadir (%s). Generating new keys/certificates.\n", GloVars.datadir);
if ((pkeyp == NULL) || (*pkeyp == NULL)) {
if ((pk = EVP_PKEY_new()) == NULL) {
proxy_error("Unable to run EVP_PKEY_new()\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
} else
pk = *pkeyp;
rsa = RSA_new();
if (!rsa) {
proxy_error("Unable to run RSA_new()\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
BIGNUM *e= BN_new();
if (!e) {
proxy_error("Unable to run BN_new()\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
if (!BN_set_word(e, RSA_F4) || !RSA_generate_key_ex(rsa, bits, e, NULL)) {
RSA_free(rsa);
BN_free(e);
proxy_error("Unable to run BN_new()\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
BN_free(e);
write_rsa_key(ssl_key_fp, rsa);
if (!EVP_PKEY_assign_RSA(pk, rsa)) {
proxy_error("Unable to run EVP_PKEY_assign_RSA()\n");
exit(EXIT_SUCCESS); // we exit gracefully to avoid being restarted
}
time_t t = time(NULL);
x1 = generate_x509(pk, (const unsigned char *)"ProxySQL_Auto_Generated_CA_Certificate", t, 3650, NULL, NULL);
write_x509(ssl_ca_fp, x1);
x2 = generate_x509(pk, (const unsigned char *)"ProxySQL_Auto_Generated_Server_Certificate", t, 3650, x1, pk);
write_x509(ssl_cert_fp, x2);
rsa = NULL;
} else {
proxy_info("SSL keys/certificates found in datadir (%s): loading them.\n", GloVars.datadir);
if (bootstrap == true) {
// during bootstrap we just call the reads
// if the read fails during bootstrap, proxysql immediately exists
pk = proxy_key_read(ssl_key_fp, bootstrap, msg);
x1 = proxy_read_x509(ssl_ca_fp, bootstrap, msg);
x2 = proxy_read_x509(ssl_cert_fp, bootstrap, msg);
} else {
pk = proxy_key_read(ssl_key_fp, bootstrap, msg);
if (pk) {
x1 = proxy_read_x509(ssl_ca_fp, bootstrap, msg);
if (x1) {
x2 = proxy_read_x509(ssl_cert_fp, bootstrap, msg);
}
}
// note that this is only relevant during PROXYSQL RELOAD TLS
if (pk == NULL || x1 == NULL || x2 == NULL) {
return 1;
}
}
}
*x509ca = x1;
*x509p = x2;
*pkeyp = pk;
dh = get_dh2048();
if (bootstrap == true) {
if (SSL_CTX_set_tmp_dh(GloVars.global.ssl_ctx, dh) == 0) {
proxy_error("Error in SSL while initializing DH: %s . Shutting down.\n",ERR_error_string(ERR_get_error(), NULL));
exit(EXIT_SUCCESS); // EXIT_SUCCESS to avoid a restart loop
}
} else {
SSL_METHOD *ssl_method;
ssl_method = (SSL_METHOD *)TLS_server_method();
GloVars.global.tmp_ssl_ctx = SSL_CTX_new(ssl_method);
if (SSL_CTX_set_tmp_dh(GloVars.global.tmp_ssl_ctx, dh) == 0) {
proxy_error("Aborting PROXYSQL RELOAD TLS. Error in SSL while initializing DH: %s\n",ERR_error_string(ERR_get_error(), NULL));
msg = "RELOAD TLS failed: Error initializing DH. ";
msg += ERR_error_string(ERR_get_error(), NULL);
return 1;
}
}
return 0;
}
int ProxySQL_create_or_load_TLS(bool bootstrap, std::string& msg) {
BIO *bio_err;
X509 *x509 = NULL;
X509 *x509ca = NULL;
EVP_PKEY *pkey = NULL;
int ret = 0;
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF);
bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
if (bootstrap == true) {
// this is legacy code, when keys are loaded only during bootstrap
if (ssl_mkit(&x509ca, &x509, &pkey, 2048, 0, 730, true, msg) != 0) {
proxy_error("Unable to initialize SSL. Shutting down...\n");
exit(EXIT_SUCCESS); // we exit gracefully to not be restarted
}
if ( SSL_CTX_use_certificate(GloVars.global.ssl_ctx, x509) <= 0 ) {
ERR_print_errors_fp(stderr);
proxy_error("Unable to use SSL certificate. Shutting down...\n");
exit(EXIT_SUCCESS); // we exit gracefully to not be restarted
}
if ( SSL_CTX_add_extra_chain_cert(GloVars.global.ssl_ctx, x509ca) <= 0 ) {
ERR_print_errors_fp(stderr);
proxy_error("Unable to use SSL CA chain. Shutting down...\n");
exit(EXIT_SUCCESS); // we exit gracefully to not be restarted
}
if ( SSL_CTX_use_PrivateKey(GloVars.global.ssl_ctx, pkey) <= 0 ) {
ERR_print_errors_fp(stderr);
proxy_error("Unable to use SSL key. Shutting down...\n");
exit(EXIT_SUCCESS); // we exit gracefully to not be restarted
}
if ( !SSL_CTX_check_private_key(GloVars.global.ssl_ctx) ) {
proxy_error("Private key does not match the public certificate\n");
exit(EXIT_SUCCESS); // we exit gracefully to not be restarted
}
GloVars.global.ssl_key_pem_mem = load_file(ssl_key_fp);
GloVars.global.ssl_cert_pem_mem = load_file(ssl_cert_fp);
// We set the locations for the certificates to be used for
// verifications purposes.
if (!SSL_CTX_load_verify_locations(GloVars.global.ssl_ctx, ssl_ca_fp, ssl_ca_fp)) {
proxy_error("Unable to load CA certificates location for verification. Shutting down\n");
exit(EXIT_SUCCESS); // we exit gracefully to not be restarted
}
} else {
// here we use global.tmp_ssl_ctx instead of global.ssl_ctx
// because we will try to swap at the end
if (ssl_mkit(&x509ca, &x509, &pkey, 2048, 0, 730, false, msg) == 0) { // 0 on success
if (SSL_CTX_use_certificate(GloVars.global.tmp_ssl_ctx, x509) == 1) { // 1 on success
if (SSL_CTX_add_extra_chain_cert(GloVars.global.tmp_ssl_ctx, x509ca) == 1) { // 1 on success
if (SSL_CTX_use_PrivateKey(GloVars.global.tmp_ssl_ctx, pkey) == 1) { // 1 on success
if (SSL_CTX_check_private_key(GloVars.global.tmp_ssl_ctx) == 1) { // 1 on success
if (SSL_CTX_load_verify_locations(GloVars.global.tmp_ssl_ctx, ssl_ca_fp, ssl_ca_fp) == 1) { // 1 on success
// take the mutex
std::lock_guard<std::mutex> lock(GloVars.global.ssl_mutex);
// note: we don't free the current SSL context, perhaps used by some connections
// swap the SSL context
GloVars.global.ssl_ctx = GloVars.global.tmp_ssl_ctx;
GloVars.global.tmp_ssl_ctx = NULL;
free(GloVars.global.ssl_key_pem_mem);
free(GloVars.global.ssl_cert_pem_mem);
GloVars.global.ssl_key_pem_mem = load_file(ssl_key_fp);
GloVars.global.ssl_cert_pem_mem = load_file(ssl_cert_fp);
} else {
proxy_error("Failed to load location of CA certificates for verification\n");
msg = "Unable to load CA certificates location for verification";
ret = 1;
}
} else {
proxy_error("Private key does not match the public certificate\n");
msg = "Private key does not match the public certificate";
ret = 1;
}
} else {
ERR_print_errors_fp(stderr);
proxy_error("Unable to use SSL key\n");
msg = "Unable to use SSL key";
ret = 1;
}
} else {
ERR_print_errors_fp(stderr);
proxy_error("Unable to use SSL CA chain\n");
msg = "Unable to use SSL CA chain";
ret = 1;
}
} else {
ERR_print_errors_fp(stderr);
proxy_error("Unable to use SSL certificate\n");
msg = "Unable to use SSL certificate";
ret = 1;
}
} else {
proxy_error("Unable to initialize SSL\n");
if (msg.length() == 0) {
msg = "Unable to initialize SSL";
}
ret = 1;
}
}
if (ret == 0) {
SSL_CTX_set_verify(GloVars.global.ssl_ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, callback_ssl_verify_peer);
}
X509_free(x509);
EVP_PKEY_free(pkey);
BIO_free(bio_err);
return ret;
}

@ -3,3 +3,16 @@
//#include "proxysql_glovars.hpp"
#include "cpp.h"
//ProxySQL_GlobalVariables GloVars;
SSL * ProxySQL_GlobalVariables::get_SSL_ctx() {
// take the mutex
std::lock_guard<std::mutex> lock(global.ssl_mutex);
return SSL_new(GloVars.global.ssl_ctx);
}
void ProxySQL_GlobalVariables::get_SSL_pem_mem(char **key, char **cert) {
// take the mutex
std::lock_guard<std::mutex> lock(global.ssl_mutex);
*key = strdup(global.ssl_key_pem_mem);
*cert = strdup(global.ssl_cert_pem_mem);
}

Loading…
Cancel
Save