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 check_config_objects(CONFIG_CONTEXT *context);
|
||||
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_get_ifaddr(unsigned char *output);
|
||||
@ -195,6 +195,14 @@ static char *server_params[] =
|
||||
"monitorpw",
|
||||
"persistpoolmax",
|
||||
"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
|
||||
};
|
||||
|
||||
@ -1036,16 +1044,17 @@ handle_global_item(const char *name, const char *value)
|
||||
/**
|
||||
* Form an SSL structure from listener section parameters
|
||||
*
|
||||
* @param name The item name
|
||||
* @param value The item value
|
||||
* @return 0 on error
|
||||
* @param obj The configuration object for the item being created
|
||||
* @param require_cert Whether a certificate and key are required
|
||||
* @param *error_count An error count which may be incremented
|
||||
* @return SSL_LISTENER structure or NULL
|
||||
*/
|
||||
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;
|
||||
int local_errors = 0;
|
||||
SSL_LISTENER *new_ssl;
|
||||
int error_count = 0;
|
||||
|
||||
ssl = config_get_value(obj->parameters, "ssl");
|
||||
if (ssl && !strcmp(ssl, "required"))
|
||||
@ -1068,7 +1077,7 @@ make_ssl_structure (CONFIG_CONTEXT *obj)
|
||||
{
|
||||
MXS_ERROR("Unknown parameter value for 'ssl_version' for"
|
||||
" 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"
|
||||
" for service '%s': %s", obj->object, ssl_cert_verify_depth);
|
||||
new_ssl->ssl_cert_verify_depth = 0;
|
||||
error_count++;
|
||||
local_errors++;
|
||||
}
|
||||
}
|
||||
|
||||
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'."
|
||||
"Please provide the path to the server certificate by adding "
|
||||
"the ssl_cert=<path> parameter", obj->object);
|
||||
@ -1096,16 +1105,16 @@ make_ssl_structure (CONFIG_CONTEXT *obj)
|
||||
|
||||
if (new_ssl->ssl_ca_cert == NULL)
|
||||
{
|
||||
error_count++;
|
||||
local_errors++;
|
||||
MXS_ERROR("CA Certificate missing for service '%s'."
|
||||
"Please provide the path to the certificate authority "
|
||||
"certificate by adding the ssl_ca_cert=<path> parameter",
|
||||
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'. "
|
||||
"Please provide the path to the server certificate key by "
|
||||
"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",
|
||||
obj->object,
|
||||
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",
|
||||
obj->object,
|
||||
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",
|
||||
obj->object,
|
||||
new_ssl->ssl_key);
|
||||
error_count++;
|
||||
local_errors++;
|
||||
}
|
||||
|
||||
if (error_count == 0)
|
||||
if (0 == local_errors)
|
||||
{
|
||||
return new_ssl;
|
||||
}
|
||||
*error_count += local_errors;
|
||||
free(new_ssl);
|
||||
}
|
||||
return NULL;
|
||||
@ -2325,6 +2335,7 @@ int create_new_service(CONFIG_CONTEXT *obj)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
char *ssl = config_get_value(obj->parameters, "ssl");
|
||||
if (ssl)
|
||||
{
|
||||
@ -2368,6 +2379,7 @@ int create_new_service(CONFIG_CONTEXT *obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/** Parameters for rwsplit router only */
|
||||
if (strcmp(router, "readwritesplit"))
|
||||
@ -2503,6 +2515,8 @@ int create_new_server(CONFIG_CONTEXT *obj)
|
||||
|
||||
CONFIG_PARAMETER *params = obj->parameters;
|
||||
|
||||
server->server_ssl = make_ssl_structure(obj, false, &error_count);
|
||||
|
||||
while (params)
|
||||
{
|
||||
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);
|
||||
if (service)
|
||||
{
|
||||
SSL_LISTENER *ssl_info = make_ssl_structure(obj);
|
||||
SSL_LISTENER *ssl_info = make_ssl_structure(obj, true, &error_count);
|
||||
if (socket)
|
||||
{
|
||||
if (serviceHasProtocol(service, protocol, 0))
|
||||
|
@ -279,6 +279,7 @@ dcb_clone(DCB *orig)
|
||||
clonedcb->flags |= DCBF_CLONE;
|
||||
clonedcb->state = orig->state;
|
||||
clonedcb->data = orig->data;
|
||||
clonedcb->listen_ssl = orig->listen_ssl;
|
||||
if (orig->remote)
|
||||
{
|
||||
clonedcb->remote = strdup(orig->remote);
|
||||
@ -2828,12 +2829,12 @@ dcb_count_by_usage(DCB_USAGE usage)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
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.");
|
||||
return -1;
|
||||
|
@ -93,17 +93,25 @@ listener_set_ssl_version(SSL_LISTENER *ssl_listener, char* version)
|
||||
void
|
||||
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)
|
||||
{
|
||||
|
@ -69,9 +69,6 @@
|
||||
#include <gwdirs.h>
|
||||
#include <math.h>
|
||||
|
||||
static RSA *rsa_512 = NULL;
|
||||
static RSA *rsa_1024 = NULL;
|
||||
|
||||
/** To be used with configuration type checks */
|
||||
typedef struct typelib_st
|
||||
{
|
||||
@ -234,6 +231,8 @@ serviceStartPort(SERVICE *service, SERV_LISTENER *port)
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
port->listener->listen_ssl = port->ssl;
|
||||
|
||||
if (port->ssl)
|
||||
{
|
||||
listener_init_SSL(port->ssl);
|
||||
@ -474,24 +473,15 @@ serviceStart(SERVICE *service)
|
||||
|
||||
if (check_service_permissions(service))
|
||||
{
|
||||
if (service->ssl_mode == SSL_DISABLED ||
|
||||
(service->ssl_mode != SSL_DISABLED && serviceInitSSL(service) == 0))
|
||||
if ((service->router_instance = service->router->createInstance(
|
||||
service,service->routerOptions)))
|
||||
{
|
||||
if ((service->router_instance = service->router->createInstance(
|
||||
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;
|
||||
}
|
||||
listeners += serviceStartAllPorts(service);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
*/
|
||||
@ -2080,170 +2070,6 @@ serviceGetList()
|
||||
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
|
||||
* @param data Service to restart
|
||||
|
Reference in New Issue
Block a user