aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/interfaces/libpq/fe-connect.c29
-rw-r--r--src/interfaces/libpq/fe-secure.c115
-rw-r--r--src/interfaces/libpq/libpq-int.h3
3 files changed, 81 insertions, 66 deletions
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index d8b243b8d69..e1376dc0173 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.367 2008/11/09 00:28:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.368 2008/11/13 09:45:24 mha Exp $
*
*-------------------------------------------------------------------------
*/
@@ -92,8 +92,10 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options,
#define DefaultPassword ""
#ifdef USE_SSL
#define DefaultSSLMode "prefer"
+#define DefaultSSLVerify "cn"
#else
#define DefaultSSLMode "disable"
+#define DefaultSSLVerify "none"
#endif
/* ----------
@@ -181,6 +183,9 @@ static const PQconninfoOption PQconninfoOptions[] = {
{"sslmode", "PGSSLMODE", DefaultSSLMode, NULL,
"SSL-Mode", "", 8}, /* sizeof("disable") == 8 */
+ {"sslverify", "PGSSLVERIFY", DefaultSSLVerify, NULL,
+ "SSL-Verify", "", 5}, /* sizeof("chain") == 5 */
+
#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
/* Kerberos and GSSAPI authentication support specifying the service name */
{"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL,
@@ -415,6 +420,8 @@ connectOptions1(PGconn *conn, const char *conninfo)
conn->connect_timeout = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "sslmode");
conn->sslmode = tmp ? strdup(tmp) : NULL;
+ tmp = conninfo_getval(connOptions, "sslverify");
+ conn->sslverify = tmp ? strdup(tmp) : NULL;
#ifdef USE_SSL
tmp = conninfo_getval(connOptions, "requiressl");
if (tmp && tmp[0] == '1')
@@ -530,6 +537,24 @@ connectOptions2(PGconn *conn)
conn->sslmode = strdup(DefaultSSLMode);
/*
+ * Validate sslverify option
+ */
+ if (conn->sslverify)
+ {
+ if (strcmp(conn->sslverify, "none") != 0
+ && strcmp(conn->sslverify, "cert") != 0
+ && strcmp(conn->sslverify, "cn") != 0)
+ {
+ conn->status = CONNECTION_BAD;
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("invalid sslverify value: \"%s\"\n"),
+ conn->sslverify);
+ return false;
+ }
+ }
+
+
+ /*
* Only if we get this far is it appropriate to try to connect. (We need a
* state flag, rather than just the boolean result of this function, in
* case someone tries to PQreset() the PGconn.)
@@ -2008,6 +2033,8 @@ freePGconn(PGconn *conn)
free(conn->pgpass);
if (conn->sslmode)
free(conn->sslmode);
+ if (conn->sslverify)
+ free(conn->sslverify);
#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
if (conn->krbsrvname)
free(conn->krbsrvname);
diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index af85257a86b..1cc7c5cbfb0 100644
--- a/src/interfaces/libpq/fe-secure.c
+++ b/src/interfaces/libpq/fe-secure.c
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.106 2008/10/24 12:29:11 mha Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.107 2008/11/13 09:45:25 mha Exp $
*
* NOTES
*
@@ -87,9 +87,7 @@
#define ERR_pop_to_mark() ((void) 0)
#endif
-#ifdef NOT_USED
-static int verify_peer_name_matches_certificate(PGconn *);
-#endif
+static bool verify_peer_name_matches_certificate(PGconn *);
static int verify_cb(int ok, X509_STORE_CTX *ctx);
static int client_cert_cb(SSL *, X509 **, EVP_PKEY **);
static int init_ssl_system(PGconn *conn);
@@ -438,77 +436,44 @@ verify_cb(int ok, X509_STORE_CTX *ctx)
return ok;
}
-#ifdef NOT_USED
/*
* Verify that common name resolves to peer.
*/
-static int
+static bool
verify_peer_name_matches_certificate(PGconn *conn)
{
- struct hostent *cn_hostentry = NULL;
- struct sockaddr server_addr;
- struct sockaddr_in *sin (struct sockaddr_in *) &server_addr;
- ACCEPT_TYPE_ARG3 len;
- char **s;
- unsigned long l;
-
- /* Get the address on the other side of the socket. */
- len = sizeof(server_addr);
- if (getpeername(conn->sock, &server_addr, &len) == -1)
- {
- char sebuf[256];
-
- printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("error querying socket: %s\n"),
- SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
- return -1;
- }
+ /*
+ * If told not to verify the peer name, don't do it. Return
+ * 0 indicating that the verification was successful.
+ */
+ if(strcmp(conn->sslverify, "cn") != 0)
+ return true;
- if (server_addr.sa_family != AF_INET)
+ if (conn->pghostaddr)
{
printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("unsupported protocol\n"));
- return -1;
+ libpq_gettext("verified SSL connections are only supported when connecting to a hostname"));
+ return false;
}
-
- /* Get the IP addresses of the certificate's common name (CN) */
+ else
{
- struct hostent hpstr;
- char buf[BUFSIZ];
- int herrno = 0;
-
/*
- * Currently, pqGethostbyname() is used only on platforms that don't
- * have getaddrinfo(). If you enable this function, you should
- * convert the pqGethostbyname() function call to use getaddrinfo().
+ * Connect by hostname.
+ *
+ * XXX: Should support alternate names here
+ * XXX: Should support wildcard certificates here
*/
- pqGethostbyname(conn->peer_cn, &hpstr, buf, sizeof(buf),
- &cn_hostentry, &herrno);
- }
-
- /* Did we get an IP address? */
- if (cn_hostentry == NULL)
- {
- printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext("could not get information about host \"%s\": %s\n"),
- conn->peer_cn, hstrerror(h_errno));
- return -1;
+ if (pg_strcasecmp(conn->peer_cn, conn->pghost) != 0)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("server common name '%s' does not match hostname '%s'"),
+ conn->peer_cn, conn->pghost);
+ return false;
+ }
+ else
+ return true;
}
-
- /* Does one of the CN's IP addresses match the server's IP address? */
- for (s = cn_hostentry->h_addr_list; *s != NULL; s++)
- if (!memcmp(&sin->sin_addr.s_addr, *s, cn_hostentry->h_length))
- return 0;
-
- l = ntohl(sin->sin_addr.s_addr);
- printfPQExpBuffer(&conn->errorMessage,
- libpq_gettext(
- "server common name \"%s\" does not resolve to %ld.%ld.%ld.%ld\n"),
- conn->peer_cn, (l >> 24) % 0x100, (l >> 16) % 0x100,
- (l >> 8) % 0x100, l % 0x100);
- return -1;
}
-#endif /* NOT_USED */
/*
* Callback used by SSL to load client cert and key.
@@ -846,6 +811,12 @@ initialize_SSL(PGconn *conn)
if (init_ssl_system(conn))
return -1;
+ /*
+ * If sslverify is set to anything other than "none", perform certificate
+ * verification. If set to "cn" we will also do further verifications after
+ * the connection has been completed.
+ */
+
/* Set up to verify server cert, if root.crt is present */
if (pqGetHomeDirectory(homedir, sizeof(homedir)))
{
@@ -889,6 +860,24 @@ initialize_SSL(PGconn *conn)
SSL_CTX_set_verify(SSL_context, SSL_VERIFY_PEER, verify_cb);
}
+ else
+ {
+ if (strcmp(conn->sslverify, "none") != 0)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("root certificate file (%s) not found"), fnbuf);
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ if (strcmp(conn->sslverify, "none") != 0)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("cannot find home directory to locate root certificate file"));
+ return -1;
+ }
}
/* set up mechanism to provide client certificate, if available */
@@ -1004,13 +993,11 @@ open_client_SSL(PGconn *conn)
NID_commonName, conn->peer_cn, SM_USER);
conn->peer_cn[SM_USER] = '\0';
-#ifdef NOT_USED
- if (verify_peer_name_matches_certificate(conn) == -1)
+ if (!verify_peer_name_matches_certificate(conn))
{
close_SSL(conn);
return PGRES_POLLING_FAILED;
}
-#endif
/* SSL handshake is complete */
return PGRES_POLLING_OK;
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index d5ec8ce13fc..adeaa35d0bf 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.136 2008/10/28 12:10:44 mha Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.137 2008/11/13 09:45:25 mha Exp $
*
*-------------------------------------------------------------------------
*/
@@ -291,6 +291,7 @@ struct pg_conn
char *pguser; /* Postgres username and password, if any */
char *pgpass;
char *sslmode; /* SSL mode (require,prefer,allow,disable) */
+ char *sslverify; /* Verify server SSL certificate (none,chain,cn) */
#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
char *krbsrvname; /* Kerberos service name */
#endif