diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/interfaces/libpq/fe-connect.c | 29 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-secure.c | 115 | ||||
-rw-r--r-- | src/interfaces/libpq/libpq-int.h | 3 |
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 |