Skip to content

Commit

Permalink
[#404] Support client certificates
Browse files Browse the repository at this point in the history
  • Loading branch information
jesperpedersen committed Feb 20, 2024
1 parent 610e7b8 commit ec23d77
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 16 deletions.
3 changes: 3 additions & 0 deletions doc/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ There can be up to `64` host sections, each with an unique name and different co
| port | | Int | Yes | The port of the PostgreSQL instance |
| primary | | Bool | No | Identify the instance as primary (hint) |
| tls | `off` | Bool | No | Enable Transport Layer Security (TLS) support (Experimental - no pooling) |
| 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. |

Note, that if `host` starts with a `/` it represents a path and `pgagroal` will connect using a Unix Domain Socket.

Expand Down
15 changes: 9 additions & 6 deletions src/include/pgagroal.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,15 @@ extern void* prometheus_cache_shmem;
*/
struct server
{
char name[MISC_LENGTH]; /**< The name of the server */
char host[MISC_LENGTH]; /**< The host name of the server */
int port; /**< The port of the server */
bool tls; /**< Use TLS if possible */
atomic_schar state; /**< The state of the server */
int lineno; /**< The line number within the configuration file */
char name[MISC_LENGTH]; /**< The name of the server */
char host[MISC_LENGTH]; /**< The host name of the server */
int port; /**< The port of the server */
bool tls; /**< Use TLS if possible */
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_schar state; /**< The state of the server */
int lineno; /**< The line number within the configuration file */
} __attribute__ ((aligned (64)));

/** @struct
Expand Down
45 changes: 44 additions & 1 deletion src/libpgagroal/configuration.c
Original file line number Diff line number Diff line change
Expand Up @@ -2524,6 +2524,7 @@ restart_server(struct server* src, struct server* dst)
restart_string(restart_message, dst->host, src->host, false);
snprintf(restart_message, sizeof(restart_message), "Server <%s>, parameter <port>", src->name);
restart_int(restart_message, dst->port, src->port);
/* TODO - TLS */
return 1;
}

Expand Down Expand Up @@ -3163,7 +3164,6 @@ pgagroal_write_config_value(char* buffer, char* config_key, size_t buffer_size)
else if (!strncmp(key, "pipeline", MISC_LENGTH))
{
return to_pipeline(buffer, config->pipeline);

}
else if (!strncmp(key, "failover_script", MISC_LENGTH))
{
Expand Down Expand Up @@ -3345,6 +3345,22 @@ pgagroal_write_server_config_value(char* buffer, char* server_name, char* config

return to_bool(buffer, primary);
}
else if (!strncmp(config_key, "tls", MISC_LENGTH))
{
return to_bool(buffer, config->servers[server_index].tls);
}
else if (!strncmp(config_key, "tls_cert_file", MISC_LENGTH))
{
return to_string(buffer, config->servers[server_index].tls_cert_file, buffer_size);
}
else if (!strncmp(config_key, "tls_key_file", MISC_LENGTH))
{
return to_string(buffer, config->servers[server_index].tls_key_file, buffer_size);
}
else if (!strncmp(config_key, "tls_ca_file", MISC_LENGTH))
{
return to_string(buffer, config->servers[server_index].tls_ca_file, buffer_size);
}
else
{
goto error;
Expand Down Expand Up @@ -3976,6 +3992,15 @@ pgagroal_apply_main_configuration(struct configuration* config,
}
memcpy(config->tls_ca_file, value, max);
}
else if (key_in_section("tls_ca_file", section, key, false, &unknown))
{
max = strlen(value);
if (max > MISC_LENGTH - 1)
{
max = MISC_LENGTH - 1;
}
memcpy(srv->tls_ca_file, value, max);
}
else if (key_in_section("tls_cert_file", section, key, true, &unknown))
{
max = strlen(value);
Expand All @@ -3985,6 +4010,15 @@ pgagroal_apply_main_configuration(struct configuration* config,
}
memcpy(config->tls_cert_file, value, max);
}
else if (key_in_section("tls_cert_file", section, key, false, &unknown))
{
max = strlen(value);
if (max > MISC_LENGTH - 1)
{
max = MISC_LENGTH - 1;
}
memcpy(srv->tls_cert_file, value, max);
}
else if (key_in_section("tls_key_file", section, key, true, &unknown))
{
max = strlen(value);
Expand All @@ -3994,6 +4028,15 @@ pgagroal_apply_main_configuration(struct configuration* config,
}
memcpy(config->tls_key_file, value, max);
}
else if (key_in_section("tls_key_file", section, key, false, &unknown))
{
max = strlen(value);
if (max > MISC_LENGTH - 1)
{
max = MISC_LENGTH - 1;
}
memcpy(srv->tls_key_file, value, max);
}
else if (key_in_section("blocking_timeout", section, key, true, &unknown))
{

Expand Down
15 changes: 6 additions & 9 deletions src/libpgagroal/security.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ static int create_ssl_ctx(bool client, SSL_CTX** ctx);
static int create_ssl_client(SSL_CTX* ctx, char* key, char* cert, char* root, int socket, SSL** ssl);
static int create_ssl_server(SSL_CTX* ctx, int socket, SSL** ssl);
static int establish_client_tls_connection(int server, int fd, SSL** ssl);
static int create_client_tls_connection(int fd, SSL** ssl);
static int create_client_tls_connection(int fd, SSL** ssl, char* tls_key_file, char* tls_cert_file, char* tls_ca_file);

static int auth_query(SSL* c_ssl, int client_fd, int slot, char* username, char* database, int hba_method);
static int auth_query_get_connection(char* username, char* password, char* database, int* server_fd, SSL** server_ssl);
Expand Down Expand Up @@ -4484,7 +4484,7 @@ create_ssl_client(SSL_CTX* ctx, char* key, char* cert, char* root, int socket, S
goto error;
}

if (have_cert && strlen(key) > 0)
if (have_cert && key != NULL && strlen(key) > 0)
{
if (SSL_use_PrivateKey_file(s, key, SSL_FILETYPE_PEM) != 1)
{
Expand Down Expand Up @@ -5716,17 +5716,14 @@ auth_query_client_scram256(SSL* c_ssl, int client_fd, char* username, char* shad
static int
establish_client_tls_connection(int server, int fd, SSL** ssl)
{
bool use_ssl = false;
struct configuration* config = NULL;
struct message* ssl_msg = NULL;
struct message* msg = NULL;
int status = -1;

config = (struct configuration*)shmem;

use_ssl = config->servers[server].tls;

if (use_ssl)
if (config->servers[server].tls)
{
status = pgagroal_create_ssl_message(&ssl_msg);
if (status != MESSAGE_STATUS_OK)
Expand All @@ -5748,7 +5745,7 @@ establish_client_tls_connection(int server, int fd, SSL** ssl)

if (msg->kind == 'S')
{
create_client_tls_connection(fd, ssl);
create_client_tls_connection(fd, ssl, config->servers[server].tls_key_file, config->servers[server].tls_cert_file, config->servers[server].tls_ca_file);
}
}

Expand All @@ -5766,7 +5763,7 @@ establish_client_tls_connection(int server, int fd, SSL** ssl)
}

static int
create_client_tls_connection(int fd, SSL** ssl)
create_client_tls_connection(int fd, SSL** ssl, char* tls_key_file, char* tls_cert_file, char* tls_ca_file)
{
SSL_CTX* ctx = NULL;
SSL* s = NULL;
Expand All @@ -5780,7 +5777,7 @@ create_client_tls_connection(int fd, SSL** ssl)
}

/* Create SSL structure */
if (create_ssl_client(ctx, NULL, NULL, NULL, fd, &s))
if (create_ssl_client(ctx, tls_key_file, tls_cert_file, tls_ca_file, fd, &s))
{
pgagroal_log_error("Client failed");
goto error;
Expand Down

0 comments on commit ec23d77

Please sign in to comment.