diff --git a/doc/VAULT.md b/doc/VAULT.md index cd20f02c..1cd01d9a 100644 --- a/doc/VAULT.md +++ b/doc/VAULT.md @@ -41,6 +41,10 @@ The available keys and their accepted values are reported in the table below. | log_connections | `off` | Bool | No | Log connects | | log_disconnections | `off` | Bool | No | Log disconnects | | hugepage | `try` | String | No | Huge page support (`off`, `try`, `on`) | +| tls | `off` | Bool | No | Enable Transport Layer Security (TLS) | +| tls_cert_file | | String | No | Certificate file for TLS. This file must be owned by either the user running pgagroal or root. | +| tls_key_file | | String | No | Private key file for TLS. This file must be owned by either the user running pgagroal or root. Additionally permissions must be at least `0640` when owned by root or `0600` otherwise. | +| tls_ca_file | | String | No | Certificate Authority (CA) file for TLS. This file must be owned by either the user running pgagroal or root. | ## [main] diff --git a/doc/man/pgagroal_vault.conf.5.rst b/doc/man/pgagroal_vault.conf.5.rst index a8f3ee06..c0fa67c9 100644 --- a/doc/man/pgagroal_vault.conf.5.rst +++ b/doc/man/pgagroal_vault.conf.5.rst @@ -89,6 +89,18 @@ authentication_timeout hugepage Huge page support. Default is try +tls + Enable Transport Layer Security (TLS). Default is false. Changes require restart in the server section. + +tls_cert_file + Certificate file for TLS. Changes require restart in the server section. + +tls_key_file + Private key file for TLS. Changes require restart in the server section. + +tls_ca_file + Certificate Authority (CA) file for TLS. Changes require restart in the server section. + The options for the main section are host diff --git a/doc/manual/user-12-vault.md b/doc/manual/user-12-vault.md index bccae807..c2490a16 100644 --- a/doc/manual/user-12-vault.md +++ b/doc/manual/user-12-vault.md @@ -43,6 +43,10 @@ The available keys and their accepted values are reported in the table below. | log_disconnections | `off` | Bool | No | Log disconnects | | authentication_timeout | 5 | Int | No | The number of seconds the process will wait for valid credentials | | hugepage | `try` | String | No | Huge page support (`off`, `try`, `on`) | +| tls | `off` | Bool | No | Enable Transport Layer Security (TLS) | +| tls_cert_file | | String | No | Certificate file for TLS. This file must be owned by either the user running pgagroal or root. | +| tls_key_file | | String | No | Private key file for TLS. This file must be owned by either the user running pgagroal or root. Additionally permissions must be at least `0640` when owned by root or `0600` otherwise. | +| tls_ca_file | | String | No | Certificate Authority (CA) file for TLS. This file must be owned by either the user running pgagroal or root. | ## [main] diff --git a/doc/tutorial/06_tls.md b/doc/tutorial/06_tls.md new file mode 100644 index 00000000..2b9f1a2a --- /dev/null +++ b/doc/tutorial/06_tls.md @@ -0,0 +1,122 @@ +## Creating Certificates + +This tutorial will show you how to create self-signed certificate for the server, valid for 365 days, use the following OpenSSL command, replacing `dbhost.yourdomain.com` with the server's host name, here `localhost`: + +``` +openssl req -new -x509 -days 365 -nodes -text -out server.crt \ + -keyout server.key -subj "/CN=dbhost.yourdomain.com" +``` + +then do - + +``` +chmod og-rwx server.key +``` + +because the server will reject the file if its permissions are more liberal than this. For more details on how to create your server private key and certificate, refer to the OpenSSL documentation. + +For the purpose of this tutorial we will assume the client certificate and key same as the server certificate and server key and therefore, these equations always holds - + +`` = `` \ +`` = `` \ +`` = `` \ +`` = `` + +## TLS in `pgagroal` + +This tutorial will show you how to enable tls between `client` and [**pgagroal**](https://github.com/agroal/pgagroal). + +### Preface + +This tutorial assumes that you have already an installation of PostgreSQL 12 (or higher) and [**pgagroal**](https://github.com/agroal/pgagroal). + +In particular, this tutorial refers to the configuration done in [Install pgagroal](https://github.com/pgagroal/pgagroal/blob/master/doc/tutorial/01_install.md). + +### Modify the `pgagroal` configuration + +It is now time to modify the [pgagroal] section of configration file `/etc/pgagroal/pgagroal_vault.conf`, with your editor of choice by adding the following lines in the [pgagroal] section. + +``` +tls = on +tls_cert_file = +tls_key_file = +``` + +#### Only Server Authentication + +If you wish to do only server authentication the aforementioned configuration suffice. + +**Client Request** + +``` +PGSSLMODE=verify-full PGSSLROOTCERT= psql -h localhost -p 2345 -U +``` + + +#### Full Client and Server Authentication + +TO enable server to request for client certificates add another configuration line below the tls + +``` +tls = on +tls_cert_file = +tls_key_file = +tls_ca_file = +``` + +**Client Request** + +``` +PGSSLMODE=verify-full PGSSLCERT= PGSSLKEY= PGSSLROOTCERT= psql -h localhost -p 2345 -U +``` + +## TLS in `pgagroal-vault` + +This tutorial will show you how to enable tls between [**pgagroal-vault**](https://github.com/agroal/pgagroal) and the client (`curl`). + +### Preface + +This tutorial assumes that you have already an installation of PostgreSQL 12 (or higher) and [**pgagroal**](https://github.com/agroal/pgagroal). + +This tutorial aslo assumes that you have a functional [**pgagroal-vault**](https://github.com/agroal/pgagroal) + +In particular, this tutorial refers to the configuration done in [Install pgagroal](https://github.com/pgagroal/pgagroal/blob/master/doc/tutorial/01_install.md) and the configuration done in [Setup pgagroal-vault](https://github.com/pgagroal/pgagroal/blob/master/doc/tutorial/07_vault.md). + +### Modify the `pgagroal-vault` configuration + +It is now time to modify the [pgagroal-vault] section of configration file `/etc/pgagroal/pgagroal_vault.conf`, with your editor of choice by adding the following lines in the [pgagroal-vault] section. + +``` +tls = on +tls_cert_file = +tls_key_file = +``` + +This will add TLS support to the server alongside the standard `http` endpoint, allowing clients to make requests to either the `https` or `http` endpoint. + +#### Only Server Authentication + +If you wish to do only server authentication the aforementioned configuration suffice. + +**Client Request** + +``` +curl --cacert -i https://localhost:2500/users/ +``` + +#### Full Client and Server Authentication + +TO enable server to request for client certificates add another configuration line below the tls + +``` +tls = on +tls_cert_file = +tls_key_file = +tls_ca_file = +``` + +**Client Request** + +``` +curl --cert --key --cacert -i https://localhost:2500/users/ +``` diff --git a/doc/tutorial/06_vault.md b/doc/tutorial/07_vault.md similarity index 100% rename from doc/tutorial/06_vault.md rename to doc/tutorial/07_vault.md diff --git a/src/include/pgagroal.h b/src/include/pgagroal.h index e738ae76..14d2b23d 100644 --- a/src/include/pgagroal.h +++ b/src/include/pgagroal.h @@ -463,6 +463,11 @@ struct configuration atomic_schar log_lock; /**< The logging lock */ char default_log_path[MISC_LENGTH]; /**< The default logging path */ + // TLS support + bool tls; /**< Is TLS enabled */ + char tls_cert_file[MISC_LENGTH]; /**< TLS certificate path */ + char tls_key_file[MISC_LENGTH]; /**< TLS key path */ + char tls_ca_file[MISC_LENGTH]; /**< TLS CA certificate path */ // Prometheus unsigned char hugepage; /**< Huge page support */ int metrics; /**< The metrics port */ @@ -508,11 +513,6 @@ struct main_configuration bool authquery; /**< Is authentication query enabled */ - bool tls; /**< Is TLS enabled */ - char tls_cert_file[MISC_LENGTH]; /**< TLS certificate path */ - char tls_key_file[MISC_LENGTH]; /**< TLS key path */ - char tls_ca_file[MISC_LENGTH]; /**< TLS CA certificate path */ - atomic_ushort active_connections; /**< The active number of connections */ int max_connections; /**< The maximum number of connections */ bool allow_unknown_users; /**< Allow unknown users */ diff --git a/src/include/security.h b/src/include/security.h index 06e8c3b2..1b897a9f 100644 --- a/src/include/security.h +++ b/src/include/security.h @@ -147,6 +147,16 @@ pgagroal_tls_valid(void); int pgagroal_generate_password(int password_length, char** password); +/** + * @brief Accept the SSL connection for the vault from client (curl) + * @param config the vault configuration + * @param client_fd the descriptor + * @param c_ssl the client SSL context + * @return 0 if success, otherwise 1 + */ +int +accept_ssl_vault(struct vault_configuration* config, int client_fd, SSL** c_ssl); + /** * @brief Initialize RNG * diff --git a/src/libpgagroal/configuration.c b/src/libpgagroal/configuration.c index 90450eab..1d507c23 100644 --- a/src/libpgagroal/configuration.c +++ b/src/libpgagroal/configuration.c @@ -127,7 +127,7 @@ pgagroal_init_configuration(void* shm) } config->failover = false; - config->tls = false; + config->common.tls = false; config->gracefully = false; config->pipeline = PIPELINE_AUTO; config->authquery = false; @@ -575,7 +575,7 @@ pgagroal_validate_configuration(void* shm, bool has_unix_socket, bool has_main_s if (config->pipeline == PIPELINE_AUTO) { - if (config->tls && (strlen(config->tls_cert_file) > 0 || strlen(config->tls_key_file) > 0)) + if (config->common.tls && (strlen(config->common.tls_cert_file) > 0 || strlen(config->common.tls_key_file) > 0)) { tls = true; } @@ -680,7 +680,7 @@ pgagroal_validate_configuration(void* shm, bool has_unix_socket, bool has_main_s } else if (config->pipeline == PIPELINE_PERFORMANCE) { - if (config->tls && (strlen(config->tls_cert_file) > 0 || strlen(config->tls_key_file) > 0)) + if (config->common.tls && (strlen(config->common.tls_cert_file) > 0 || strlen(config->common.tls_key_file) > 0)) { tls = true; } @@ -722,6 +722,7 @@ pgagroal_vault_init_configuration(void* shm) config = (struct vault_configuration*)shm; config->common.port = 0; + config->common.tls = false; config->vault_server.server.port = 0; config->vault_server.server.tls = false; @@ -2616,12 +2617,12 @@ transfer_configuration(struct main_configuration* config, struct main_configurat config->authquery = reload->authquery; - config->tls = reload->tls; - memcpy(config->tls_cert_file, reload->tls_cert_file, MISC_LENGTH); - memcpy(config->tls_key_file, reload->tls_key_file, MISC_LENGTH); - memcpy(config->tls_ca_file, reload->tls_ca_file, MISC_LENGTH); + config->common.tls = reload->common.tls; + memcpy(config->common.tls_cert_file, reload->common.tls_cert_file, MISC_LENGTH); + memcpy(config->common.tls_key_file, reload->common.tls_key_file, MISC_LENGTH); + memcpy(config->common.tls_ca_file, reload->common.tls_ca_file, MISC_LENGTH); - if (config->tls && (config->pipeline == PIPELINE_SESSION || config->pipeline == PIPELINE_TRANSACTION)) + if (config->common.tls && (config->pipeline == PIPELINE_SESSION || config->pipeline == PIPELINE_TRANSACTION)) { if (pgagroal_tls_valid()) { @@ -3589,7 +3590,7 @@ pgagroal_write_config_value(char* buffer, char* config_key, size_t buffer_size) } else if (!strncmp(key, "tls", MISC_LENGTH)) { - return to_bool(buffer, config->tls); + return to_bool(buffer, config->common.tls); } else if (!strncmp(key, "auth_query", MISC_LENGTH)) { @@ -3597,15 +3598,15 @@ pgagroal_write_config_value(char* buffer, char* config_key, size_t buffer_size) } else if (!strncmp(key, "tls_ca_file", MISC_LENGTH)) { - return to_string(buffer, config->tls_ca_file, buffer_size); + return to_string(buffer, config->common.tls_ca_file, buffer_size); } else if (!strncmp(key, "tls_cert_file", MISC_LENGTH)) { - return to_string(buffer, config->tls_cert_file, buffer_size); + return to_string(buffer, config->common.tls_cert_file, buffer_size); } else if (!strncmp(key, "tls_key_file", MISC_LENGTH)) { - return to_string(buffer, config->tls_key_file, buffer_size); + return to_string(buffer, config->common.tls_key_file, buffer_size); } else if (!strncmp(key, "blocking_timeout", MISC_LENGTH)) { @@ -4397,7 +4398,7 @@ pgagroal_apply_main_configuration(struct main_configuration* config, } else if (key_in_section("tls", section, key, true, &unknown)) { - if (as_bool(value, &config->tls)) + if (as_bool(value, &config->common.tls)) { unknown = true; } @@ -4416,7 +4417,7 @@ pgagroal_apply_main_configuration(struct main_configuration* config, { max = MISC_LENGTH - 1; } - memcpy(config->tls_ca_file, value, max); + memcpy(config->common.tls_ca_file, value, max); } else if (key_in_section("tls_ca_file", section, key, false, &unknown)) { @@ -4434,7 +4435,7 @@ pgagroal_apply_main_configuration(struct main_configuration* config, { max = MISC_LENGTH - 1; } - memcpy(config->tls_cert_file, value, max); + memcpy(config->common.tls_cert_file, value, max); } else if (key_in_section("tls_cert_file", section, key, false, &unknown)) { @@ -4452,7 +4453,7 @@ pgagroal_apply_main_configuration(struct main_configuration* config, { max = MISC_LENGTH - 1; } - memcpy(config->tls_key_file, value, max); + memcpy(config->common.tls_key_file, value, max); } else if (key_in_section("tls_key_file", section, key, false, &unknown)) { @@ -4779,60 +4780,60 @@ pgagroal_apply_vault_configuration(struct vault_configuration* config, } memcpy(&srv->user.username, value, max); } - else if (key_in_section("metrics", section, key, true, &unknown)) + else if (key_in_section("tls", section, key, true, &unknown)) { - if (as_int(value, &config->common.metrics)) + if (as_bool(value, &config->common.tls)) { unknown = true; } } - else if (key_in_section("metrics_cache_max_age", section, key, true, &unknown)) + else if (key_in_section("tls_ca_file", section, key, true, &unknown)) { - if (as_seconds(value, &config->common.metrics_cache_max_age, PGAGROAL_PROMETHEUS_CACHE_DISABLED)) + max = strlen(value); + if (max > MISC_LENGTH - 1) { - unknown = true; + max = MISC_LENGTH - 1; } + memcpy(config->common.tls_ca_file, value, max); } - else if (key_in_section("metrics_cache_max_size", section, key, true, &unknown)) + else if (key_in_section("tls_cert_file", section, key, true, &unknown)) { - if (as_bytes(value, &config->common.metrics_cache_max_size, PROMETHEUS_DEFAULT_CACHE_SIZE)) + max = strlen(value); + if (max > MISC_LENGTH - 1) { - unknown = true; + max = MISC_LENGTH - 1; } + memcpy(config->common.tls_cert_file, value, max); } - else if (key_in_section("tls", section, key, false, &unknown)) + else if (key_in_section("tls_key_file", section, key, true, &unknown)) { - if (as_bool(value, &srv->server.tls)) + max = strlen(value); + if (max > MISC_LENGTH - 1) { - unknown = true; + max = MISC_LENGTH - 1; } + memcpy(config->common.tls_key_file, value, max); } - else if (key_in_section("tls_ca_file", section, key, false, &unknown)) + else if (key_in_section("metrics", section, key, true, &unknown)) { - max = strlen(value); - if (max > MISC_LENGTH - 1) + if (as_int(value, &config->common.metrics)) { - max = MISC_LENGTH - 1; + unknown = true; } - memcpy(&srv->server.tls_ca_file, value, max); } - else if (key_in_section("tls_cert_file", section, key, false, &unknown)) + else if (key_in_section("metrics_cache_max_age", section, key, true, &unknown)) { - max = strlen(value); - if (max > MISC_LENGTH - 1) + if (as_seconds(value, &config->common.metrics_cache_max_age, PGAGROAL_PROMETHEUS_CACHE_DISABLED)) { - max = MISC_LENGTH - 1; + unknown = true; } - memcpy(&srv->server.tls_cert_file, value, max); } - else if (key_in_section("tls_key_file", section, key, false, &unknown)) + else if (key_in_section("metrics_cache_max_size", section, key, true, &unknown)) { - max = strlen(value); - if (max > MISC_LENGTH - 1) + if (as_bytes(value, &config->common.metrics_cache_max_size, PROMETHEUS_DEFAULT_CACHE_SIZE)) { - max = MISC_LENGTH - 1; + unknown = true; } - memcpy(&srv->server.tls_key_file, value, max); } else if (key_in_section("authentication_timeout", section, key, true, &unknown)) { diff --git a/src/libpgagroal/prometheus.c b/src/libpgagroal/prometheus.c index 9028d199..49ed797c 100644 --- a/src/libpgagroal/prometheus.c +++ b/src/libpgagroal/prometheus.c @@ -348,7 +348,7 @@ pgagroal_vault_init_prometheus(size_t* p_size, void** p_shmem) error: - return 1; + return 1; } void diff --git a/src/libpgagroal/security.c b/src/libpgagroal/security.c index 9f9bb21c..a7dad428 100644 --- a/src/libpgagroal/security.c +++ b/src/libpgagroal/security.c @@ -238,7 +238,7 @@ pgagroal_authenticate(int client_fd, char* address, int* slot, SSL** client_ssl, { pgagroal_log_debug("SSL request from client: %d", client_fd); - if (config->tls) + if (config->common.tls) { SSL_CTX* ctx = NULL; @@ -469,6 +469,56 @@ pgagroal_authenticate(int client_fd, char* address, int* slot, SSL** client_ssl, return AUTH_ERROR; } +int +accept_ssl_vault(struct vault_configuration* config, int client_fd, SSL** client_ssl) +{ + + pgagroal_log_debug("SSL request from client: %d", client_fd); + int status = MESSAGE_STATUS_ERROR; + SSL_CTX* ctx = NULL; + SSL* c_ssl = NULL; + + /* We are acting as a server against the client */ + if (create_ssl_ctx(false, &ctx)) + { + goto error; + } + + if (create_ssl_server(ctx, client_fd, &c_ssl)) + { + goto error; + } + + *client_ssl = c_ssl; + + /* Switch to TLS mode */ + status = SSL_accept(c_ssl); + if (status != 1) + { + unsigned long err; + + err = ERR_get_error(); + pgagroal_log_error("SSL failed: %s", ERR_reason_error_string(err)); + goto error; + } + + return 0; +error: + + if (ctx != NULL) + { + SSL_CTX_free(ctx); + } + + if (c_ssl != NULL) + { + SSL_free(c_ssl); + } + + pgagroal_log_debug("accept_ssl_vault: ERROR"); + return 1; +} + int pgagroal_prefill_auth(char* username, char* password, char* database, int* slot, SSL** server_ssl) { @@ -603,7 +653,7 @@ pgagroal_remote_management_auth(int client_fd, char* address, SSL** client_ssl) { pgagroal_log_debug("SSL request from client: %d", client_fd); - if (config->tls) + if (config->common.tls) { SSL_CTX* ctx = NULL; @@ -3337,49 +3387,49 @@ pgagroal_tls_valid(void) config = (struct main_configuration*)shmem; - if (config->tls) + if (config->common.tls) { - if (strlen(config->tls_cert_file) == 0) + if (strlen(config->common.tls_cert_file) == 0) { pgagroal_log_error("No TLS certificate defined"); goto error; } - if (strlen(config->tls_key_file) == 0) + if (strlen(config->common.tls_key_file) == 0) { pgagroal_log_error("No TLS private key defined"); goto error; } - if (stat(config->tls_cert_file, &st) == -1) + if (stat(config->common.tls_cert_file, &st) == -1) { - pgagroal_log_error("Can't locate TLS certificate file: %s", config->tls_cert_file); + pgagroal_log_error("Can't locate TLS certificate file: %s", config->common.tls_cert_file); goto error; } if (!S_ISREG(st.st_mode)) { - pgagroal_log_error("TLS certificate file is not a regular file: %s", config->tls_cert_file); + pgagroal_log_error("TLS certificate file is not a regular file: %s", config->common.tls_cert_file); goto error; } if (st.st_uid && st.st_uid != geteuid()) { - pgagroal_log_error("TLS certificate file not owned by user or root: %s", config->tls_cert_file); + pgagroal_log_error("TLS certificate file not owned by user or root: %s", config->common.tls_cert_file); goto error; } memset(&st, 0, sizeof(struct stat)); - if (stat(config->tls_key_file, &st) == -1) + if (stat(config->common.tls_key_file, &st) == -1) { - pgagroal_log_error("Can't locate TLS private key file: %s", config->tls_key_file); + pgagroal_log_error("Can't locate TLS private key file: %s", config->common.tls_key_file); goto error; } if (!S_ISREG(st.st_mode)) { - pgagroal_log_error("TLS private key file is not a regular file: %s", config->tls_key_file); + pgagroal_log_error("TLS private key file is not a regular file: %s", config->common.tls_key_file); goto error; } @@ -3387,7 +3437,7 @@ pgagroal_tls_valid(void) { if (st.st_mode & (S_IRWXG | S_IRWXO)) { - pgagroal_log_error("TLS private key file must have 0600 permissions when owned by a non-root user: %s", config->tls_key_file); + pgagroal_log_error("TLS private key file must have 0600 permissions when owned by a non-root user: %s", config->common.tls_key_file); goto error; } } @@ -3395,36 +3445,36 @@ pgagroal_tls_valid(void) { if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) { - pgagroal_log_error("TLS private key file must have at least 0640 permissions when owned by root: %s", config->tls_key_file); + pgagroal_log_error("TLS private key file must have at least 0640 permissions when owned by root: %s", config->common.tls_key_file); goto error; } } else { - pgagroal_log_error("TLS private key file not owned by user or root: %s", config->tls_key_file); + pgagroal_log_error("TLS private key file not owned by user or root: %s", config->common.tls_key_file); goto error; } - if (strlen(config->tls_ca_file) > 0) + if (strlen(config->common.tls_ca_file) > 0) { memset(&st, 0, sizeof(struct stat)); - if (stat(config->tls_ca_file, &st) == -1) + if (stat(config->common.tls_ca_file, &st) == -1) { - pgagroal_log_error("Can't locate TLS CA file: %s", config->tls_ca_file); + pgagroal_log_error("Can't locate TLS CA file: %s", config->common.tls_ca_file); goto error; } if (!S_ISREG(st.st_mode)) { - pgagroal_log_error("TLS CA file is not a regular file: %s", config->tls_ca_file); + pgagroal_log_error("TLS CA file is not a regular file: %s", config->common.tls_ca_file); goto error; } if (st.st_uid && st.st_uid != geteuid()) { - pgagroal_log_error("TLS CA file not owned by user or root: %s", config->tls_ca_file); + pgagroal_log_error("TLS CA file not owned by user or root: %s", config->common.tls_ca_file); goto error; } } @@ -4533,9 +4583,9 @@ create_ssl_server(SSL_CTX* ctx, int socket, SSL** ssl) { SSL* s = NULL; STACK_OF(X509_NAME) * root_cert_list = NULL; - struct main_configuration* config; + struct configuration* config; - config = (struct main_configuration*)shmem; + config = (struct configuration*)shmem; if (strlen(config->tls_cert_file) == 0) { diff --git a/src/vault.c b/src/vault.c index 69636973..394cd00c 100644 --- a/src/vault.c +++ b/src/vault.c @@ -68,8 +68,7 @@ static int connect_pgagroal(struct vault_configuration* config, char* username, static void route_users(char* username, char** response, SSL* s_ssl, int client_fd); static void route_not_found(char** response); static void route_found(char** response, char* password); -static int router(SSL* ssl, int client_fd); -static void shutdown_ports(void); +static int router(SSL* ccl, SSL* ssl, int client_fd); static volatile int keep_running = 1; static char** argv_ptr; @@ -83,7 +82,7 @@ static int server_fds_length = -1; static int default_buffer_size = DEFAULT_BUFFER_SIZE; static int -router(SSL* s_ssl, int client_fd) +router(SSL* c_ssl, SSL* s_ssl, int client_fd) { int exit_code = 0; ssize_t bytes_read; @@ -99,8 +98,16 @@ router(SSL* s_ssl, int client_fd) memset(&response, 0, sizeof(response)); // Read the request - bytes_read = read(client_fd, buffer, sizeof(buffer) - 1); - buffer[bytes_read] = '\0'; + if (c_ssl != NULL) + { + bytes_read = SSL_read(c_ssl, buffer, sizeof(buffer) - 1); + buffer[bytes_read] = '\0'; + } + else + { + bytes_read = read(client_fd, buffer, sizeof(buffer) - 1); + buffer[bytes_read] = '\0'; + } sscanf(buffer, "%7s %127s", method, path); @@ -133,7 +140,14 @@ router(SSL* s_ssl, int client_fd) } // Send the response - bytes_write = write(client_fd, response, strlen(response)); + if (c_ssl) + { + bytes_write = SSL_write(c_ssl, response, strlen(response)); + } + else + { + bytes_write = write(client_fd, response, strlen(response)); + } if (bytes_write <= 0) { @@ -605,9 +619,13 @@ accept_vault_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) struct sockaddr_in6 client_addr; socklen_t client_addr_length; int client_fd; + ssize_t peek_bytes; + char peek_buffer[HTTP_BUFFER_SIZE]; char address[INET6_ADDRSTRLEN]; pid_t pid; + SSL* c_ssl = NULL; SSL* s_ssl = NULL; + bool ssl_req = false; struct vault_configuration* config; if (EV_ERROR & revents) @@ -681,9 +699,47 @@ accept_vault_cb(struct ev_loop* loop, struct ev_io* watcher, int revents) ev_loop_fork(loop); shutdown_ports(); - if (router(s_ssl, client_fd)) + // MSG_Peek + peek_bytes = recv(client_fd, peek_buffer, sizeof(peek_buffer), MSG_PEEK); + if (peek_bytes <= 0) + { + pgagroal_log_error("unable to peek network data from client"); + close(client_fd); + exit(1); + } + + // Check for SSL request by matching `Client Hello` bytes + if ( + ((unsigned char)peek_buffer[0] == 0x16) && + ((unsigned char)peek_buffer[1] == 0x03) && + ((unsigned char)peek_buffer[2] == 0x01 || (unsigned char)peek_buffer[2] == 0x02 || (unsigned char)peek_buffer[2] == 0x03 || (unsigned char)peek_buffer[2] == 0x04) + ) + { + ssl_req = true; + } + + // Handle ssl request from client + if (config->common.tls && ssl_req) + { + if (accept_ssl_vault(config, client_fd, &c_ssl)) + { + pgagroal_log_error("accept_ssl_vault: SSL failed"); + pgagroal_disconnect(client_fd); + exit(1); + } + } + else if (ssl_req) + { + pgagroal_log_error("client requests ssl connection to http server"); + pgagroal_disconnect(client_fd); + exit(1); + } + + // Handle http request + if (router(c_ssl, s_ssl, client_fd)) { pgagroal_log_error("Couldn't write to client"); + pgagroal_disconnect(client_fd); exit(1); }