[pgpool-hackers: 137] SSL mutual authentication (with patch)
Warren Armstrong
wa at quintessencelabs.com
Thu Oct 4 10:47:40 JST 2012
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi,
We recently encountered a problem using pgpool with mutual
authentication between a
client (pgpool) and a server (postgres). We determined that the problem
was due to pgpool
not loading client certificates & private keys when connecting to a
backend - while pgpool loaded
a CA certificate to authenticate the backend, it did not provide its own
credentials to said backend.
We were unsure whether or not this was a deliberate omission, and so we
changed the pgpool
codebase to allow for mutual authentication. The changes provide for
additional per-backend
configuration directives to set certificates, keys, etc. These
directives are then used when configuring
the OpenSSL context.
I have attached a patch against Git revision
3f89a334fe08dfcd199d9e45728a04ddb1d2ec85.
Cheers,
Warren Armstrong
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (MingW32)
Comment: Using GnuPG with Mozilla - http://www.enigmail.net/
iEYEARECAAYFAlBs6rsACgkQIZlA5/+bUwn3eQCgjtbapglXoRX/jPle4aMeDOzu
3moAoJC9eqIBVAI+Nm1UtwApuHnKWFyR
=SFLK
-----END PGP SIGNATURE-----
-------------- next part --------------
diff --git a/pcp/libpcp_ext.h b/pcp/libpcp_ext.h
index 84fca61..02f2f2c 100644
--- a/pcp/libpcp_ext.h
+++ b/pcp/libpcp_ext.h
@@ -59,6 +59,10 @@ typedef struct {
char backend_data_directory[MAX_PATH_LENGTH];
unsigned short flag; /* various flags */
unsigned long long int standby_delay; /* The replication delay against the primary */
+ char backend_cert[MAX_PATH_LENGTH];
+ char backend_key[MAX_PATH_LENGTH];
+ char backend_ca[MAX_PATH_LENGTH];
+ char backend_ca_cert_dir[MAX_PATH_LENGTH];
} BackendInfo;
typedef struct {
diff --git a/pool_config.c b/pool_config.c
index ebfbfb6..16940ef 100644
--- a/pool_config.c
+++ b/pool_config.c
@@ -3553,6 +3553,107 @@ int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context)
pool_debug("pool_config: slot number %d flag: %04x", slot, flag);
}
+ else if (!strncmp(key, "backend_cert", 12) &&
+ CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) &&
+ mypid == getpid()) /* this parameter must be modified by parent pid */
+ {
+ int slot;
+ char *str;
+
+ slot = atoi(key + 12);
+ if (slot < 0 || slot >= MAX_CONNECTION_SLOTS)
+ {
+ pool_error("pool_config: backend number %s for backend_cert out of range", key);
+ fclose(fd);
+ return(-1);
+ }
+
+ str = extract_string(yytext, token);
+ if (str == NULL)
+ {
+ fclose(fd);
+ return(-1);
+ }
+ if (context == INIT_CONFIG ||
+ (context == RELOAD_CONFIG && BACKEND_INFO(slot).backend_status == CON_UNUSED))
+ strlcpy(BACKEND_INFO(slot).backend_cert, str, MAX_PATH_LENGTH);
+ }
+ else if (!strncmp(key, "backend_key", 11) &&
+ CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) &&
+ mypid == getpid()) /* this parameter must be modified by parent pid */
+ {
+ int slot;
+ char *str;
+
+ slot = atoi(key + 11);
+ if (slot < 0 || slot >= MAX_CONNECTION_SLOTS)
+ {
+ pool_error("pool_config: backend number %s for backend_key out of range", key);
+ fclose(fd);
+ return(-1);
+ }
+
+ str = extract_string(yytext, token);
+ if (str == NULL)
+ {
+ fclose(fd);
+ return(-1);
+ }
+ if (context == INIT_CONFIG ||
+ (context == RELOAD_CONFIG && BACKEND_INFO(slot).backend_status == CON_UNUSED))
+ strlcpy(BACKEND_INFO(slot).backend_key, str, MAX_PATH_LENGTH);
+ }
+ else if (!strncmp(key, "backend_ca", 10) &&
+ CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) &&
+ mypid == getpid()) /* this parameter must be modified by parent pid */
+ {
+ int slot;
+ char *str;
+
+ slot = atoi(key + 10);
+ if (slot < 0 || slot >= MAX_CONNECTION_SLOTS)
+ {
+ pool_error("pool_config: backend number %s for backend_ca out of range", key);
+ fclose(fd);
+ return(-1);
+ }
+
+ str = extract_string(yytext, token);
+ if (str == NULL)
+ {
+ fclose(fd);
+ return(-1);
+ }
+ if (context == INIT_CONFIG ||
+ (context == RELOAD_CONFIG && BACKEND_INFO(slot).backend_status == CON_UNUSED))
+ strlcpy(BACKEND_INFO(slot).backend_ca, str, MAX_PATH_LENGTH);
+ }
+ else if (!strncmp(key, "backend_ca_cert_dir", 19) &&
+ CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context) &&
+ mypid == getpid()) /* this parameter must be modified by parent pid */
+ {
+ int slot;
+ char *str;
+
+ slot = atoi(key + 19);
+ if (slot < 0 || slot >= MAX_CONNECTION_SLOTS)
+ {
+ pool_error("pool_config: backend number %s for backend_ca_cert_dir out of range", key);
+ fclose(fd);
+ return(-1);
+ }
+
+ str = extract_string(yytext, token);
+ if (str == NULL)
+ {
+ fclose(fd);
+ return(-1);
+ }
+ if (context == INIT_CONFIG ||
+ (context == RELOAD_CONFIG && BACKEND_INFO(slot).backend_status == CON_UNUSED))
+ strlcpy(BACKEND_INFO(slot).backend_ca_cert_dir, str, MAX_PATH_LENGTH);
+ }
+
else if (!strcmp(key, "log_statement") && CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context))
{
int v = eval_logical(yytext);
@@ -4611,6 +4712,10 @@ static void clear_host_entry(int slot)
pool_config->backend_desc->backend_info[slot].backend_port = 0;
pool_config->backend_desc->backend_info[slot].backend_status = CON_UNUSED;
pool_config->backend_desc->backend_info[slot].backend_weight = 0.0;
+ *pool_config->backend_desc->backend_info[slot].backend_cert = '\0';
+ *pool_config->backend_desc->backend_info[slot].backend_key = '\0';
+ *pool_config->backend_desc->backend_info[slot].backend_ca = '\0';
+ *pool_config->backend_desc->backend_info[slot].backend_ca_cert_dir = '\0';
}
#ifdef DEBUG
diff --git a/pool_ssl.c b/pool_ssl.c
index e8e15f6..c675dac 100644
--- a/pool_ssl.c
+++ b/pool_ssl.c
@@ -230,35 +230,53 @@ retry:
static int init_ssl_ctx(POOL_CONNECTION *cp, enum ssl_conn_type conntype) {
int error = 0;
char *cacert = NULL, *cacert_dir = NULL;
+ char *priv_key = NULL, *cert = NULL;
+ BackendInfo *backend = NULL;
/* initialize SSL members */
cp->ssl_ctx = SSL_CTX_new(TLSv1_method());
SSL_RETURN_ERROR_IF( (! cp->ssl_ctx), "SSL_CTX_new" );
if ( conntype == ssl_conn_serverclient) {
- error = SSL_CTX_use_certificate_file(cp->ssl_ctx,
- pool_config->ssl_cert,
- SSL_FILETYPE_PEM);
- SSL_RETURN_ERROR_IF( (error <= 0), "Loading SSL certificate");
-
- error = SSL_CTX_use_PrivateKey_file(cp->ssl_ctx,
- pool_config->ssl_key,
- SSL_FILETYPE_PEM);
- SSL_RETURN_ERROR_IF( (error <= 0), "Loading SSL private key");
+ if (strlen(pool_config->ssl_cert))
+ cert = pool_config->ssl_cert;
+ if (strlen(pool_config->ssl_key))
+ priv_key = pool_config->ssl_key;
+ if (strlen(pool_config->ssl_ca_cert))
+ cacert = pool_config->ssl_ca_cert;
+ if (strlen(pool_config->ssl_ca_cert_dir))
+ cacert_dir = pool_config->ssl_ca_cert_dir;
} else {
+ backend = &BACKEND_INFO(cp->db_node_id);
+ if (strlen(backend->backend_cert))
+ cert = backend->backend_cert;
+ if (strlen(backend->backend_key))
+ priv_key = backend->backend_key;
+ if (strlen(backend->backend_ca))
+ cacert = backend->backend_ca;
+ if (strlen(backend->backend_ca_cert_dir))
+ cacert_dir = backend->backend_ca_cert_dir;
+ }
+
+ if (cert != NULL ) {
+ error = SSL_CTX_use_certificate_file(cp->ssl_ctx,
+ cert,
+ SSL_FILETYPE_PEM);
+ SSL_RETURN_ERROR_IF( (error <= 0), "Loading SSL certificate");
+ }
+ if ( priv_key != NULL ) {
+ error = SSL_CTX_use_PrivateKey_file(cp->ssl_ctx,
+ priv_key,
+ SSL_FILETYPE_PEM);
+ SSL_RETURN_ERROR_IF( (error <= 0), "Loading SSL private key");
+ }
/* set extra verification if ssl_ca_cert or ssl_ca_cert_dir are set */
- if (strlen(pool_config->ssl_ca_cert))
- cacert = pool_config->ssl_ca_cert;
- if (strlen(pool_config->ssl_ca_cert_dir))
- cacert_dir = pool_config->ssl_ca_cert_dir;
-
- if ( cacert || cacert_dir ) {
- error = (!SSL_CTX_load_verify_locations(cp->ssl_ctx,
- cacert,
- cacert_dir));
- SSL_RETURN_ERROR_IF(error, "SSL verification setup");
- SSL_CTX_set_verify(cp->ssl_ctx, SSL_VERIFY_PEER, NULL);
- }
+ if ( cacert || cacert_dir ) {
+ error = (!SSL_CTX_load_verify_locations(cp->ssl_ctx,
+ cacert,
+ cacert_dir));
+ SSL_RETURN_ERROR_IF(error, "SSL verification setup");
+ SSL_CTX_set_verify(cp->ssl_ctx, SSL_VERIFY_PEER, NULL);
}
cp->ssl = SSL_new(cp->ssl_ctx);
More information about the pgpool-hackers
mailing list