Migrate SSL functionality out of service and into listener. Develop config handling accordingly, including making provision for SSL parameters in servers for future use in implementing SSL to backend servers. Some elements still to be tidied mainly in mysql_client.c - but that will be part of detaching the SSL authentication from the MySQL protocol.
This commit is contained in:
@ -91,7 +91,7 @@ static void global_defaults();
|
|||||||
static void feedback_defaults();
|
static void feedback_defaults();
|
||||||
static void check_config_objects(CONFIG_CONTEXT *context);
|
static void check_config_objects(CONFIG_CONTEXT *context);
|
||||||
static int maxscale_getline(char** dest, int* size, FILE* file);
|
static int maxscale_getline(char** dest, int* size, FILE* file);
|
||||||
static SSL_LISTENER *make_ssl_structure(CONFIG_CONTEXT *obj);
|
static SSL_LISTENER *make_ssl_structure(CONFIG_CONTEXT *obj, bool require_cert, int *error_count);
|
||||||
|
|
||||||
int config_truth_value(char *str);
|
int config_truth_value(char *str);
|
||||||
int config_get_ifaddr(unsigned char *output);
|
int config_get_ifaddr(unsigned char *output);
|
||||||
@ -195,6 +195,14 @@ static char *server_params[] =
|
|||||||
"monitorpw",
|
"monitorpw",
|
||||||
"persistpoolmax",
|
"persistpoolmax",
|
||||||
"persistmaxtime",
|
"persistmaxtime",
|
||||||
|
/* The following, or something similar, will be needed for backend SSL
|
||||||
|
"ssl_cert",
|
||||||
|
"ssl_ca_cert",
|
||||||
|
"ssl",
|
||||||
|
"ssl_key",
|
||||||
|
"ssl_version",
|
||||||
|
"ssl_cert_verify_depth",
|
||||||
|
*/
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1036,16 +1044,17 @@ handle_global_item(const char *name, const char *value)
|
|||||||
/**
|
/**
|
||||||
* Form an SSL structure from listener section parameters
|
* Form an SSL structure from listener section parameters
|
||||||
*
|
*
|
||||||
* @param name The item name
|
* @param obj The configuration object for the item being created
|
||||||
* @param value The item value
|
* @param require_cert Whether a certificate and key are required
|
||||||
* @return 0 on error
|
* @param *error_count An error count which may be incremented
|
||||||
|
* @return SSL_LISTENER structure or NULL
|
||||||
*/
|
*/
|
||||||
static SSL_LISTENER *
|
static SSL_LISTENER *
|
||||||
make_ssl_structure (CONFIG_CONTEXT *obj)
|
make_ssl_structure (CONFIG_CONTEXT *obj, bool require_cert, int *error_count)
|
||||||
{
|
{
|
||||||
char *ssl, *ssl_version, *ssl_cert, *ssl_key, *ssl_ca_cert, *ssl_cert_verify_depth;
|
char *ssl, *ssl_version, *ssl_cert, *ssl_key, *ssl_ca_cert, *ssl_cert_verify_depth;
|
||||||
|
int local_errors = 0;
|
||||||
SSL_LISTENER *new_ssl;
|
SSL_LISTENER *new_ssl;
|
||||||
int error_count = 0;
|
|
||||||
|
|
||||||
ssl = config_get_value(obj->parameters, "ssl");
|
ssl = config_get_value(obj->parameters, "ssl");
|
||||||
if (ssl && !strcmp(ssl, "required"))
|
if (ssl && !strcmp(ssl, "required"))
|
||||||
@ -1068,7 +1077,7 @@ make_ssl_structure (CONFIG_CONTEXT *obj)
|
|||||||
{
|
{
|
||||||
MXS_ERROR("Unknown parameter value for 'ssl_version' for"
|
MXS_ERROR("Unknown parameter value for 'ssl_version' for"
|
||||||
" service '%s': %s", obj->object, ssl_version);
|
" service '%s': %s", obj->object, ssl_version);
|
||||||
error_count++;
|
local_errors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1080,15 +1089,15 @@ make_ssl_structure (CONFIG_CONTEXT *obj)
|
|||||||
MXS_ERROR("Invalid parameter value for 'ssl_cert_verify_depth"
|
MXS_ERROR("Invalid parameter value for 'ssl_cert_verify_depth"
|
||||||
" for service '%s': %s", obj->object, ssl_cert_verify_depth);
|
" for service '%s': %s", obj->object, ssl_cert_verify_depth);
|
||||||
new_ssl->ssl_cert_verify_depth = 0;
|
new_ssl->ssl_cert_verify_depth = 0;
|
||||||
error_count++;
|
local_errors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
listener_set_certificates(new_ssl, ssl_cert, ssl_key, ssl_ca_cert);
|
listener_set_certificates(new_ssl, ssl_cert, ssl_key, ssl_ca_cert);
|
||||||
|
|
||||||
if (new_ssl->ssl_cert == NULL)
|
if (require_cert && new_ssl->ssl_cert == NULL)
|
||||||
{
|
{
|
||||||
error_count++;
|
local_errors++;
|
||||||
MXS_ERROR("Server certificate missing for service '%s'."
|
MXS_ERROR("Server certificate missing for service '%s'."
|
||||||
"Please provide the path to the server certificate by adding "
|
"Please provide the path to the server certificate by adding "
|
||||||
"the ssl_cert=<path> parameter", obj->object);
|
"the ssl_cert=<path> parameter", obj->object);
|
||||||
@ -1096,16 +1105,16 @@ make_ssl_structure (CONFIG_CONTEXT *obj)
|
|||||||
|
|
||||||
if (new_ssl->ssl_ca_cert == NULL)
|
if (new_ssl->ssl_ca_cert == NULL)
|
||||||
{
|
{
|
||||||
error_count++;
|
local_errors++;
|
||||||
MXS_ERROR("CA Certificate missing for service '%s'."
|
MXS_ERROR("CA Certificate missing for service '%s'."
|
||||||
"Please provide the path to the certificate authority "
|
"Please provide the path to the certificate authority "
|
||||||
"certificate by adding the ssl_ca_cert=<path> parameter",
|
"certificate by adding the ssl_ca_cert=<path> parameter",
|
||||||
obj->object);
|
obj->object);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_ssl->ssl_key == NULL)
|
if (require_cert && new_ssl->ssl_key == NULL)
|
||||||
{
|
{
|
||||||
error_count++;
|
local_errors++;
|
||||||
MXS_ERROR("Server private key missing for service '%s'. "
|
MXS_ERROR("Server private key missing for service '%s'. "
|
||||||
"Please provide the path to the server certificate key by "
|
"Please provide the path to the server certificate key by "
|
||||||
"adding the ssl_key=<path> parameter",
|
"adding the ssl_key=<path> parameter",
|
||||||
@ -1117,29 +1126,30 @@ make_ssl_structure (CONFIG_CONTEXT *obj)
|
|||||||
MXS_ERROR("Certificate authority file for service '%s' not found: %s",
|
MXS_ERROR("Certificate authority file for service '%s' not found: %s",
|
||||||
obj->object,
|
obj->object,
|
||||||
new_ssl->ssl_ca_cert);
|
new_ssl->ssl_ca_cert);
|
||||||
error_count++;
|
local_errors++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (access(new_ssl->ssl_cert, F_OK) != 0)
|
if (require_cert && access(new_ssl->ssl_cert, F_OK) != 0)
|
||||||
{
|
{
|
||||||
MXS_ERROR("Server certificate file for service '%s' not found: %s",
|
MXS_ERROR("Server certificate file for service '%s' not found: %s",
|
||||||
obj->object,
|
obj->object,
|
||||||
new_ssl->ssl_cert);
|
new_ssl->ssl_cert);
|
||||||
error_count++;
|
local_errors++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (access(new_ssl->ssl_key, F_OK) != 0)
|
if (require_cert && access(new_ssl->ssl_key, F_OK) != 0)
|
||||||
{
|
{
|
||||||
MXS_ERROR("Server private key file for service '%s' not found: %s",
|
MXS_ERROR("Server private key file for service '%s' not found: %s",
|
||||||
obj->object,
|
obj->object,
|
||||||
new_ssl->ssl_key);
|
new_ssl->ssl_key);
|
||||||
error_count++;
|
local_errors++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error_count == 0)
|
if (0 == local_errors)
|
||||||
{
|
{
|
||||||
return new_ssl;
|
return new_ssl;
|
||||||
}
|
}
|
||||||
|
*error_count += local_errors;
|
||||||
free(new_ssl);
|
free(new_ssl);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -2325,6 +2335,7 @@ int create_new_service(CONFIG_CONTEXT *obj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
char *ssl = config_get_value(obj->parameters, "ssl");
|
char *ssl = config_get_value(obj->parameters, "ssl");
|
||||||
if (ssl)
|
if (ssl)
|
||||||
{
|
{
|
||||||
@ -2368,6 +2379,7 @@ int create_new_service(CONFIG_CONTEXT *obj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/** Parameters for rwsplit router only */
|
/** Parameters for rwsplit router only */
|
||||||
if (strcmp(router, "readwritesplit"))
|
if (strcmp(router, "readwritesplit"))
|
||||||
@ -2503,6 +2515,8 @@ int create_new_server(CONFIG_CONTEXT *obj)
|
|||||||
|
|
||||||
CONFIG_PARAMETER *params = obj->parameters;
|
CONFIG_PARAMETER *params = obj->parameters;
|
||||||
|
|
||||||
|
server->server_ssl = make_ssl_structure(obj, false, &error_count);
|
||||||
|
|
||||||
while (params)
|
while (params)
|
||||||
{
|
{
|
||||||
if (!is_normal_server_parameter(params->name))
|
if (!is_normal_server_parameter(params->name))
|
||||||
@ -2729,7 +2743,7 @@ int create_new_listener(CONFIG_CONTEXT *obj, bool startnow)
|
|||||||
SERVICE *service = service_find(service_name);
|
SERVICE *service = service_find(service_name);
|
||||||
if (service)
|
if (service)
|
||||||
{
|
{
|
||||||
SSL_LISTENER *ssl_info = make_ssl_structure(obj);
|
SSL_LISTENER *ssl_info = make_ssl_structure(obj, true, &error_count);
|
||||||
if (socket)
|
if (socket)
|
||||||
{
|
{
|
||||||
if (serviceHasProtocol(service, protocol, 0))
|
if (serviceHasProtocol(service, protocol, 0))
|
||||||
|
@ -279,6 +279,7 @@ dcb_clone(DCB *orig)
|
|||||||
clonedcb->flags |= DCBF_CLONE;
|
clonedcb->flags |= DCBF_CLONE;
|
||||||
clonedcb->state = orig->state;
|
clonedcb->state = orig->state;
|
||||||
clonedcb->data = orig->data;
|
clonedcb->data = orig->data;
|
||||||
|
clonedcb->listen_ssl = orig->listen_ssl;
|
||||||
if (orig->remote)
|
if (orig->remote)
|
||||||
{
|
{
|
||||||
clonedcb->remote = strdup(orig->remote);
|
clonedcb->remote = strdup(orig->remote);
|
||||||
@ -2828,12 +2829,12 @@ dcb_count_by_usage(DCB_USAGE usage)
|
|||||||
*/
|
*/
|
||||||
int dcb_create_SSL(DCB* dcb)
|
int dcb_create_SSL(DCB* dcb)
|
||||||
{
|
{
|
||||||
if (serviceInitSSL(dcb->service) != 0)
|
if (NULL == dcb->listen_ssl || listener_init_SSL(dcb->listen_ssl) != 0)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((dcb->ssl = SSL_new(dcb->service->ctx)) == NULL)
|
if ((dcb->ssl = SSL_new(dcb->listen_ssl->ctx)) == NULL)
|
||||||
{
|
{
|
||||||
MXS_ERROR("Failed to initialize SSL for connection.");
|
MXS_ERROR("Failed to initialize SSL for connection.");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -93,17 +93,25 @@ listener_set_ssl_version(SSL_LISTENER *ssl_listener, char* version)
|
|||||||
void
|
void
|
||||||
listener_set_certificates(SSL_LISTENER *ssl_listener, char* cert, char* key, char* ca_cert)
|
listener_set_certificates(SSL_LISTENER *ssl_listener, char* cert, char* key, char* ca_cert)
|
||||||
{
|
{
|
||||||
if (ssl_listener->ssl_cert)
|
if (NULL != cert)
|
||||||
{
|
{
|
||||||
free(ssl_listener->ssl_cert);
|
if (ssl_listener->ssl_cert)
|
||||||
|
{
|
||||||
|
free(ssl_listener->ssl_cert);
|
||||||
|
}
|
||||||
|
ssl_listener->ssl_cert = strdup(cert);
|
||||||
}
|
}
|
||||||
ssl_listener->ssl_cert = strdup(cert);
|
else ssl_listener->ssl_cert = NULL;
|
||||||
|
|
||||||
if (ssl_listener->ssl_key)
|
if (NULL != key)
|
||||||
{
|
{
|
||||||
free(ssl_listener->ssl_key);
|
if (ssl_listener->ssl_key)
|
||||||
|
{
|
||||||
|
free(ssl_listener->ssl_key);
|
||||||
|
}
|
||||||
|
ssl_listener->ssl_key = strdup(key);
|
||||||
}
|
}
|
||||||
ssl_listener->ssl_key = strdup(key);
|
else ssl_listener->ssl_key = NULL;
|
||||||
|
|
||||||
if (ssl_listener->ssl_ca_cert)
|
if (ssl_listener->ssl_ca_cert)
|
||||||
{
|
{
|
||||||
|
@ -69,9 +69,6 @@
|
|||||||
#include <gwdirs.h>
|
#include <gwdirs.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
static RSA *rsa_512 = NULL;
|
|
||||||
static RSA *rsa_1024 = NULL;
|
|
||||||
|
|
||||||
/** To be used with configuration type checks */
|
/** To be used with configuration type checks */
|
||||||
typedef struct typelib_st
|
typedef struct typelib_st
|
||||||
{
|
{
|
||||||
@ -234,6 +231,8 @@ serviceStartPort(SERVICE *service, SERV_LISTENER *port)
|
|||||||
goto retblock;
|
goto retblock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
port->listener->listen_ssl = port->ssl;
|
||||||
|
|
||||||
if (port->ssl)
|
if (port->ssl)
|
||||||
{
|
{
|
||||||
listener_init_SSL(port->ssl);
|
listener_init_SSL(port->ssl);
|
||||||
@ -474,24 +473,15 @@ serviceStart(SERVICE *service)
|
|||||||
|
|
||||||
if (check_service_permissions(service))
|
if (check_service_permissions(service))
|
||||||
{
|
{
|
||||||
if (service->ssl_mode == SSL_DISABLED ||
|
if ((service->router_instance = service->router->createInstance(
|
||||||
(service->ssl_mode != SSL_DISABLED && serviceInitSSL(service) == 0))
|
service,service->routerOptions)))
|
||||||
{
|
{
|
||||||
if ((service->router_instance = service->router->createInstance(
|
listeners += serviceStartAllPorts(service);
|
||||||
service,service->routerOptions)))
|
|
||||||
{
|
|
||||||
listeners += serviceStartAllPorts(service);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MXS_ERROR("%s: Failed to create router instance for service. Service not started.",
|
|
||||||
service->name);
|
|
||||||
service->state = SERVICE_STATE_FAILED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MXS_ERROR("%s: SSL initialization failed. Service not started.", service->name);
|
MXS_ERROR("%s: Failed to create router instance for service. Service not started.",
|
||||||
|
service->name);
|
||||||
service->state = SERVICE_STATE_FAILED;
|
service->state = SERVICE_STATE_FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2052,7 +2042,7 @@ serviceRowCallback(RESULTSET *set, void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a resultset that has the current set of services in it
|
* Return a result set that has the current set of services in it
|
||||||
*
|
*
|
||||||
* @return A Result set
|
* @return A Result set
|
||||||
*/
|
*/
|
||||||
@ -2080,170 +2070,6 @@ serviceGetList()
|
|||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The RSA ket generation callback function for OpenSSL.
|
|
||||||
* @param s SSL structure
|
|
||||||
* @param is_export Not used
|
|
||||||
* @param keylength Length of the key
|
|
||||||
* @return Pointer to RSA structure
|
|
||||||
*/
|
|
||||||
RSA *tmp_rsa_callback(SSL *s, int is_export, int keylength)
|
|
||||||
{
|
|
||||||
RSA *rsa_tmp=NULL;
|
|
||||||
|
|
||||||
switch (keylength) {
|
|
||||||
case 512:
|
|
||||||
if (rsa_512)
|
|
||||||
{
|
|
||||||
rsa_tmp = rsa_512;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* generate on the fly, should not happen in this example */
|
|
||||||
rsa_tmp = RSA_generate_key(keylength,RSA_F4,NULL,NULL);
|
|
||||||
rsa_512 = rsa_tmp; /* Remember for later reuse */
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1024:
|
|
||||||
if (rsa_1024)
|
|
||||||
{
|
|
||||||
rsa_tmp=rsa_1024;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* Generating a key on the fly is very costly, so use what is there */
|
|
||||||
if (rsa_1024)
|
|
||||||
{
|
|
||||||
rsa_tmp=rsa_1024;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rsa_tmp=rsa_512; /* Use at least a shorter key */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(rsa_tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the service's SSL context. This sets up the generated RSA
|
|
||||||
* encryption keys, chooses the server encryption level and configures the server
|
|
||||||
* certificate, private key and certificate authority file.
|
|
||||||
* @param service Service to initialize
|
|
||||||
* @return 0 on success, -1 on error
|
|
||||||
*/
|
|
||||||
int serviceInitSSL(SERVICE* service)
|
|
||||||
{
|
|
||||||
DH* dh;
|
|
||||||
RSA* rsa;
|
|
||||||
|
|
||||||
/* Pending removal in favour of processing in listener. */
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!service->ssl_init_done)
|
|
||||||
{
|
|
||||||
switch(service->ssl_method_type)
|
|
||||||
{
|
|
||||||
case SERVICE_SSLV3:
|
|
||||||
service->method = (SSL_METHOD*)SSLv3_server_method();
|
|
||||||
break;
|
|
||||||
case SERVICE_TLS10:
|
|
||||||
service->method = (SSL_METHOD*)TLSv1_server_method();
|
|
||||||
break;
|
|
||||||
#ifdef OPENSSL_1_0
|
|
||||||
case SERVICE_TLS11:
|
|
||||||
service->method = (SSL_METHOD*)TLSv1_1_server_method();
|
|
||||||
break;
|
|
||||||
case SERVICE_TLS12:
|
|
||||||
service->method = (SSL_METHOD*)TLSv1_2_server_method();
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
/** Rest of these use the maximum available SSL/TLS methods */
|
|
||||||
case SERVICE_SSL_MAX:
|
|
||||||
service->method = (SSL_METHOD*)SSLv23_server_method();
|
|
||||||
break;
|
|
||||||
case SERVICE_TLS_MAX:
|
|
||||||
service->method = (SSL_METHOD*)SSLv23_server_method();
|
|
||||||
break;
|
|
||||||
case SERVICE_SSL_TLS_MAX:
|
|
||||||
service->method = (SSL_METHOD*)SSLv23_server_method();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
service->method = (SSL_METHOD*)SSLv23_server_method();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((service->ctx = SSL_CTX_new(service->method)) == NULL)
|
|
||||||
{
|
|
||||||
MXS_ERROR("SSL context initialization failed.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Enable all OpenSSL bug fixes */
|
|
||||||
SSL_CTX_set_options(service->ctx,SSL_OP_ALL);
|
|
||||||
|
|
||||||
/** Generate the 512-bit and 1024-bit RSA keys */
|
|
||||||
if (rsa_512 == NULL)
|
|
||||||
{
|
|
||||||
rsa_512 = RSA_generate_key(512,RSA_F4,NULL,NULL);
|
|
||||||
if (rsa_512 == NULL)
|
|
||||||
{
|
|
||||||
MXS_ERROR("512-bit RSA key generation failed.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rsa_1024 == NULL)
|
|
||||||
{
|
|
||||||
rsa_1024 = RSA_generate_key(1024,RSA_F4,NULL,NULL);
|
|
||||||
if (rsa_1024 == NULL)
|
|
||||||
{
|
|
||||||
MXS_ERROR("1024-bit RSA key generation failed.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rsa_512 != NULL && rsa_1024 != NULL)
|
|
||||||
{
|
|
||||||
SSL_CTX_set_tmp_rsa_callback(service->ctx,tmp_rsa_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Load the server sertificate */
|
|
||||||
if (SSL_CTX_use_certificate_file(service->ctx, service->ssl_cert, SSL_FILETYPE_PEM) <= 0)
|
|
||||||
{
|
|
||||||
MXS_ERROR("Failed to set server SSL certificate.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load the private-key corresponding to the server certificate */
|
|
||||||
if (SSL_CTX_use_PrivateKey_file(service->ctx, service->ssl_key, SSL_FILETYPE_PEM) <= 0)
|
|
||||||
{
|
|
||||||
MXS_ERROR("Failed to set server SSL key.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if the server certificate and private-key matches */
|
|
||||||
if (!SSL_CTX_check_private_key(service->ctx))
|
|
||||||
{
|
|
||||||
MXS_ERROR("Server SSL certificate and key do not match.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load the RSA CA certificate into the SSL_CTX structure */
|
|
||||||
if (!SSL_CTX_load_verify_locations(service->ctx, service->ssl_ca_cert, NULL))
|
|
||||||
{
|
|
||||||
MXS_ERROR("Failed to set Certificate Authority file.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set to require peer (client) certificate verification */
|
|
||||||
SSL_CTX_set_verify(service->ctx,SSL_VERIFY_PEER,NULL);
|
|
||||||
|
|
||||||
/* Set the verification depth */
|
|
||||||
SSL_CTX_set_verify_depth(service->ctx,service->ssl_cert_verify_depth);
|
|
||||||
service->ssl_init_done = true;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Function called by the housekeeper thread to retry starting of a service
|
* Function called by the housekeeper thread to retry starting of a service
|
||||||
* @param data Service to restart
|
* @param data Service to restart
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <spinlock.h>
|
#include <spinlock.h>
|
||||||
#include <buffer.h>
|
#include <buffer.h>
|
||||||
#include <gw_protocol.h>
|
#include <gw_protocol.h>
|
||||||
|
#include <gw_ssl.h>
|
||||||
#include <modinfo.h>
|
#include <modinfo.h>
|
||||||
#include <gwbitmask.h>
|
#include <gwbitmask.h>
|
||||||
#include <skygw_utils.h>
|
#include <skygw_utils.h>
|
||||||
@ -201,6 +202,7 @@ typedef struct dcb
|
|||||||
char *protoname; /**< Name of the protocol */
|
char *protoname; /**< Name of the protocol */
|
||||||
void *protocol; /**< The protocol specific state */
|
void *protocol; /**< The protocol specific state */
|
||||||
struct session *session; /**< The owning session */
|
struct session *session; /**< The owning session */
|
||||||
|
SSL_LISTENER *listen_ssl; /**< For a client DCB, the SSL descriptor, if any */
|
||||||
GWPROTOCOL func; /**< The functions for this descriptor */
|
GWPROTOCOL func; /**< The functions for this descriptor */
|
||||||
|
|
||||||
int writeqlen; /**< Current number of byes in the write queue */
|
int writeqlen; /**< Current number of byes in the write queue */
|
||||||
|
@ -33,38 +33,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gw_protocol.h>
|
#include <gw_protocol.h>
|
||||||
|
#include <gw_ssl.h>
|
||||||
#include <dcb.h>
|
#include <dcb.h>
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
SERVICE_SSLV3,
|
|
||||||
SERVICE_TLS10,
|
|
||||||
#ifdef OPENSSL_1_0
|
|
||||||
SERVICE_TLS11,
|
|
||||||
SERVICE_TLS12,
|
|
||||||
#endif
|
|
||||||
SERVICE_SSL_MAX,
|
|
||||||
SERVICE_TLS_MAX,
|
|
||||||
SERVICE_SSL_TLS_MAX
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ssl_listener structure is used to aggregate the SSL configuration items
|
|
||||||
* and data for a particular listener
|
|
||||||
*/
|
|
||||||
typedef struct ssl_listener
|
|
||||||
{
|
|
||||||
SSL_CTX *ctx;
|
|
||||||
SSL_METHOD *method; /*< SSLv3 or TLS1.0/1.1/1.2 methods
|
|
||||||
* see: https://www.openssl.org/docs/ssl/SSL_CTX_new.html */
|
|
||||||
int ssl_cert_verify_depth; /*< SSL certificate verification depth */
|
|
||||||
int ssl_method_type; /*< Which of the SSLv3 or TLS1.0/1.1/1.2 methods to use */
|
|
||||||
char *ssl_cert; /*< SSL certificate */
|
|
||||||
char *ssl_key; /*< SSL private key */
|
|
||||||
char *ssl_ca_cert; /*< SSL CA certificate */
|
|
||||||
bool ssl_init_done; /*< If SSL has already been initialized for this service */
|
|
||||||
} SSL_LISTENER;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The servlistener structure is used to link a service to the protocols that
|
* The servlistener structure is used to link a service to the protocols that
|
||||||
* are used to support that service. It defines the name of the protocol module
|
* are used to support that service. It defines the name of the protocol module
|
||||||
|
@ -89,6 +89,7 @@ typedef struct server {
|
|||||||
char *name; /**< Server name/IP address*/
|
char *name; /**< Server name/IP address*/
|
||||||
unsigned short port; /**< Port to listen on */
|
unsigned short port; /**< Port to listen on */
|
||||||
char *protocol; /**< Protocol module to use */
|
char *protocol; /**< Protocol module to use */
|
||||||
|
SSL_LISTENER *server_ssl; /**< SSL data structure for server, if any */
|
||||||
unsigned int status; /**< Status flag bitmap for the server */
|
unsigned int status; /**< Status flag bitmap for the server */
|
||||||
char *monuser; /**< User name to use to monitor the db */
|
char *monuser; /**< User name to use to monitor the db */
|
||||||
char *monpw; /**< Password to use to monitor the db */
|
char *monpw; /**< Password to use to monitor the db */
|
||||||
|
@ -207,7 +207,6 @@ extern int serviceSetUser(SERVICE *, char *, char *);
|
|||||||
extern int serviceGetUser(SERVICE *, char **, char **);
|
extern int serviceGetUser(SERVICE *, char **, char **);
|
||||||
extern bool serviceSetFilters(SERVICE *, char *);
|
extern bool serviceSetFilters(SERVICE *, char *);
|
||||||
extern int serviceSetSSL(SERVICE *service, char* action);
|
extern int serviceSetSSL(SERVICE *service, char* action);
|
||||||
extern int serviceInitSSL(SERVICE* service);
|
|
||||||
extern int serviceSetSSLVersion(SERVICE *service, char* version);
|
extern int serviceSetSSLVersion(SERVICE *service, char* version);
|
||||||
extern int serviceSetSSLVerifyDepth(SERVICE* service, int depth);
|
extern int serviceSetSSLVerifyDepth(SERVICE* service, int depth);
|
||||||
extern void serviceSetCertificates(SERVICE *service, char* cert,char* key, char* ca_cert);
|
extern void serviceSetCertificates(SERVICE *service, char* cert,char* key, char* ca_cert);
|
||||||
|
@ -357,6 +357,7 @@ static int httpd_accept(DCB *dcb)
|
|||||||
|
|
||||||
if ((client = dcb_alloc(DCB_ROLE_REQUEST_HANDLER)))
|
if ((client = dcb_alloc(DCB_ROLE_REQUEST_HANDLER)))
|
||||||
{
|
{
|
||||||
|
client->listen_ssl = dcb->listen_ssl;
|
||||||
client->fd = so;
|
client->fd = so;
|
||||||
client->remote = strdup(inet_ntoa(addr.sin_addr));
|
client->remote = strdup(inet_ntoa(addr.sin_addr));
|
||||||
memcpy(&client->func, &MyObject, sizeof(GWPROTOCOL));
|
memcpy(&client->func, &MyObject, sizeof(GWPROTOCOL));
|
||||||
|
@ -268,6 +268,7 @@ static int maxscaled_accept(DCB *dcb)
|
|||||||
close(so);
|
close(so);
|
||||||
return n_connect;
|
return n_connect;
|
||||||
}
|
}
|
||||||
|
client_dcb->listen_ssl = dcb->listen_ssl;
|
||||||
client_dcb->fd = so;
|
client_dcb->fd = so;
|
||||||
client_dcb->remote = strdup(inet_ntoa(addr.sin_addr));
|
client_dcb->remote = strdup(inet_ntoa(addr.sin_addr));
|
||||||
memcpy(&client_dcb->func, &MyObject, sizeof(GWPROTOCOL));
|
memcpy(&client_dcb->func, &MyObject, sizeof(GWPROTOCOL));
|
||||||
|
@ -335,7 +335,8 @@ int MySQLSendHandshake(DCB* dcb)
|
|||||||
|
|
||||||
mysql_server_capabilities_one[0] &= ~GW_MYSQL_CAPABILITIES_COMPRESS;
|
mysql_server_capabilities_one[0] &= ~GW_MYSQL_CAPABILITIES_COMPRESS;
|
||||||
|
|
||||||
if (dcb->service->ssl_mode != SSL_DISABLED)
|
/* if (dcb->service->ssl_mode != SSL_DISABLED) */
|
||||||
|
if (NULL != dcb->listen_ssl)
|
||||||
{
|
{
|
||||||
mysql_server_capabilities_one[1] |= GW_MYSQL_CAPABILITIES_SSL >> 8;
|
mysql_server_capabilities_one[1] |= GW_MYSQL_CAPABILITIES_SSL >> 8;
|
||||||
}
|
}
|
||||||
@ -489,7 +490,8 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF **buf)
|
|||||||
ssl = protocol->client_capabilities & GW_MYSQL_CAPABILITIES_SSL;
|
ssl = protocol->client_capabilities & GW_MYSQL_CAPABILITIES_SSL;
|
||||||
|
|
||||||
/** Client didn't requested SSL when SSL mode was required*/
|
/** Client didn't requested SSL when SSL mode was required*/
|
||||||
if (!ssl && protocol->owner_dcb->service->ssl_mode == SSL_REQUIRED)
|
/* if (!ssl && protocol->owner_dcb->service->ssl_mode == SSL_REQUIRED) */
|
||||||
|
if (!ssl && NULL != protocol->owner_dcb->listen_ssl)
|
||||||
{
|
{
|
||||||
MXS_INFO("User %s@%s connected to service '%s' without SSL when SSL was required.",
|
MXS_INFO("User %s@%s connected to service '%s' without SSL when SSL was required.",
|
||||||
protocol->owner_dcb->user,
|
protocol->owner_dcb->user,
|
||||||
@ -507,7 +509,8 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF **buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Do the SSL Handshake */
|
/** Do the SSL Handshake */
|
||||||
if (ssl && protocol->owner_dcb->service->ssl_mode != SSL_DISABLED)
|
/* if (ssl && protocol->owner_dcb->service->ssl_mode != SSL_DISABLED) */
|
||||||
|
if (ssl && NULL != protocol->owner_dcb->listen_ssl)
|
||||||
{
|
{
|
||||||
protocol->protocol_auth_state = MYSQL_AUTH_SSL_REQ;
|
protocol->protocol_auth_state = MYSQL_AUTH_SSL_REQ;
|
||||||
|
|
||||||
@ -520,7 +523,8 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF **buf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (dcb->service->ssl_mode == SSL_ENABLED)
|
/* else if (dcb->service->ssl_mode == SSL_ENABLED) */
|
||||||
|
else if (NULL != dcb->listen_ssl)
|
||||||
{
|
{
|
||||||
/** This is a non-SSL connection to a SSL enabled service.
|
/** This is a non-SSL connection to a SSL enabled service.
|
||||||
* We have only read enough of the packet to know that the client
|
* We have only read enough of the packet to know that the client
|
||||||
@ -712,7 +716,8 @@ int gw_read_client_event(DCB* dcb)
|
|||||||
/** SSL handshake is done, communication is now encrypted with SSL */
|
/** SSL handshake is done, communication is now encrypted with SSL */
|
||||||
rc = dcb_read_SSL(dcb, &read_buffer);
|
rc = dcb_read_SSL(dcb, &read_buffer);
|
||||||
}
|
}
|
||||||
else if (dcb->service->ssl_mode != SSL_DISABLED &&
|
/* else if (dcb->service->ssl_mode != SSL_DISABLED && */
|
||||||
|
else if (dcb->listen_ssl != NULL &&
|
||||||
protocol->protocol_auth_state == MYSQL_AUTH_SENT)
|
protocol->protocol_auth_state == MYSQL_AUTH_SENT)
|
||||||
{
|
{
|
||||||
/** The service allows both SSL and non-SSL connections.
|
/** The service allows both SSL and non-SSL connections.
|
||||||
@ -1586,6 +1591,7 @@ int gw_MySQLAccept(DCB *listener)
|
|||||||
goto return_rc;
|
goto return_rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client_dcb->listen_ssl = listener->listen_ssl;
|
||||||
client_dcb->service = listener->session->service;
|
client_dcb->service = listener->session->service;
|
||||||
client_dcb->session = session_set_dummy(client_dcb);
|
client_dcb->session = session_set_dummy(client_dcb);
|
||||||
client_dcb->fd = c_sock;
|
client_dcb->fd = c_sock;
|
||||||
|
@ -297,6 +297,7 @@ static int telnetd_accept(DCB *dcb)
|
|||||||
close(so);
|
close(so);
|
||||||
return n_connect;
|
return n_connect;
|
||||||
}
|
}
|
||||||
|
client_dcb->listen_ssl = dcb->listen_ssl;
|
||||||
client_dcb->fd = so;
|
client_dcb->fd = so;
|
||||||
client_dcb->remote = strdup(inet_ntoa(addr.sin_addr));
|
client_dcb->remote = strdup(inet_ntoa(addr.sin_addr));
|
||||||
memcpy(&client_dcb->func, &MyObject, sizeof(GWPROTOCOL));
|
memcpy(&client_dcb->func, &MyObject, sizeof(GWPROTOCOL));
|
||||||
|
Reference in New Issue
Block a user