]> granicus.if.org Git - postgresql/blobdiff - src/interfaces/libpq/fe-secure.c
Reject certificates with embedded NULLs in the commonName field. This stops
[postgresql] / src / interfaces / libpq / fe-secure.c
index de3a71cca0c4c5b354572102f72ed8c68dc47c78..6f6052b2b05d378cbb0d7f5df1f77a04dd8f5e9a 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.119 2009/01/28 15:06:47 mha Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.129 2009/12/09 06:37:06 mha Exp $
  *
  * NOTES
  *
@@ -31,6 +31,7 @@
 #include "libpq-fe.h"
 #include "fe-auth.h"
 #include "pqsignal.h"
+#include "libpq-int.h"
 
 #ifdef WIN32
 #include "win32.h"
@@ -62,7 +63,7 @@
 #if (SSLEAY_VERSION_NUMBER >= 0x00907000L)
 #include <openssl/conf.h>
 #endif
-#if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
+#ifdef USE_SSL_ENGINE
 #include <openssl/engine.h>
 #endif
 
@@ -98,11 +99,12 @@ static void close_SSL(PGconn *);
 static char *SSLerrmessage(void);
 static void SSLerrfree(char *buf);
 
-static bool pq_initssllib = true;
+static bool pq_init_ssl_lib = true;
+static bool pq_init_crypto_lib = true;
 static SSL_CTX *SSL_context = NULL;
 
 #ifdef ENABLE_THREAD_SAFETY
-static int ssl_open_connections = 0;
+static long ssl_open_connections = 0;
 
 #ifndef WIN32
 static pthread_mutex_t ssl_config_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -110,53 +112,80 @@ static pthread_mutex_t ssl_config_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t ssl_config_mutex = NULL;
 static long win32_ssl_create_mutex = 0;
 #endif
-
-#endif /* ENABLE_THREAD_SAFETY */
-
-#endif /* SSL */
+#endif   /* ENABLE_THREAD_SAFETY */
+#endif   /* SSL */
 
 
 /*
  * Macros to handle disabling and then restoring the state of SIGPIPE handling.
- * Note that DISABLE_SIGPIPE() must appear at the start of a block.
+ * On Windows, these are all no-ops since there's no SIGPIPEs.
  */
 
 #ifndef WIN32
+
+#define SIGPIPE_MASKED(conn)   ((conn)->sigpipe_so || (conn)->sigpipe_flag)
+
 #ifdef ENABLE_THREAD_SAFETY
 
-#define DISABLE_SIGPIPE(failaction) \
-       sigset_t        osigmask; \
-       bool            sigpipe_pending; \
-       bool            got_epipe = false; \
-\
-       if (pq_block_sigpipe(&osigmask, &sigpipe_pending) < 0) \
-               failaction
+struct sigpipe_info
+{
+       sigset_t        oldsigmask;
+       bool            sigpipe_pending;
+       bool            got_epipe;
+};
+
+#define DECLARE_SIGPIPE_INFO(spinfo) struct sigpipe_info spinfo
+
+#define DISABLE_SIGPIPE(conn, spinfo, failaction) \
+       do { \
+               (spinfo).got_epipe = false; \
+               if (!SIGPIPE_MASKED(conn)) \
+               { \
+                       if (pq_block_sigpipe(&(spinfo).oldsigmask, \
+                                                                &(spinfo).sigpipe_pending) < 0) \
+                               failaction; \
+               } \
+       } while (0)
 
-#define REMEMBER_EPIPE(cond) \
+#define REMEMBER_EPIPE(spinfo, cond) \
        do { \
                if (cond) \
-                       got_epipe = true; \
+                       (spinfo).got_epipe = true; \
+       } while (0)
+
+#define RESTORE_SIGPIPE(conn, spinfo) \
+       do { \
+               if (!SIGPIPE_MASKED(conn)) \
+                       pq_reset_sigpipe(&(spinfo).oldsigmask, (spinfo).sigpipe_pending, \
+                                                        (spinfo).got_epipe); \
        } while (0)
 
-#define RESTORE_SIGPIPE() \
-       pq_reset_sigpipe(&osigmask, sigpipe_pending, got_epipe)
+#else /* !ENABLE_THREAD_SAFETY */
 
-#else  /* !ENABLE_THREAD_SAFETY */
+#define DECLARE_SIGPIPE_INFO(spinfo) pqsigfunc spinfo = NULL
 
-#define DISABLE_SIGPIPE(failaction) \
-       pqsigfunc       oldsighandler = pqsignal(SIGPIPE, SIG_IGN)
+#define DISABLE_SIGPIPE(conn, spinfo, failaction) \
+       do { \
+               if (!SIGPIPE_MASKED(conn)) \
+                       spinfo = pqsignal(SIGPIPE, SIG_IGN); \
+       } while (0)
 
-#define REMEMBER_EPIPE(cond)
+#define REMEMBER_EPIPE(spinfo, cond)
 
-#define RESTORE_SIGPIPE() \
-       pqsignal(SIGPIPE, oldsighandler)
+#define RESTORE_SIGPIPE(conn, spinfo) \
+       do { \
+               if (!SIGPIPE_MASKED(conn)) \
+                       pqsignal(SIGPIPE, spinfo); \
+       } while (0)
 
 #endif /* ENABLE_THREAD_SAFETY */
+
 #else  /* WIN32 */
 
-#define DISABLE_SIGPIPE(failaction)
-#define REMEMBER_EPIPE(cond)
-#define RESTORE_SIGPIPE()
+#define DECLARE_SIGPIPE_INFO(spinfo)
+#define DISABLE_SIGPIPE(conn, spinfo, failaction)
+#define REMEMBER_EPIPE(spinfo, cond)
+#define RESTORE_SIGPIPE(conn, spinfo)
 
 #endif /* WIN32 */
 
@@ -171,9 +200,30 @@ static long win32_ssl_create_mutex = 0;
  */
 void
 PQinitSSL(int do_init)
+{
+       PQinitOpenSSL(do_init, do_init);
+}
+
+/*
+ *     Exported function to allow application to tell us it's already
+ *     initialized OpenSSL and/or libcrypto.
+ */
+void
+PQinitOpenSSL(int do_ssl, int do_crypto)
 {
 #ifdef USE_SSL
-       pq_initssllib = do_init;
+#ifdef ENABLE_THREAD_SAFETY
+
+       /*
+        * Disallow changing the flags while we have open connections, else we'd
+        * get completely confused.
+        */
+       if (ssl_open_connections != 0)
+               return;
+#endif
+
+       pq_init_ssl_lib = do_ssl;
+       pq_init_crypto_lib = do_crypto;
 #endif
 }
 
@@ -213,6 +263,9 @@ pqsecure_open_client(PGconn *conn)
        /* First time through? */
        if (conn->ssl == NULL)
        {
+               /* We cannot use MSG_NOSIGNAL to block SIGPIPE when using SSL */
+               conn->sigpipe_flag = false;
+
                if (!(conn->ssl = SSL_new(SSL_context)) ||
                        !SSL_set_app_data(conn->ssl, conn) ||
                        !SSL_set_fd(conn->ssl, conn->sock))
@@ -265,9 +318,10 @@ pqsecure_read(PGconn *conn, void *ptr, size_t len)
        if (conn->ssl)
        {
                int                     err;
+               DECLARE_SIGPIPE_INFO(spinfo);
 
                /* SSL_read can write to the socket, so we need to disable SIGPIPE */
-               DISABLE_SIGPIPE(return -1);
+               DISABLE_SIGPIPE(conn, spinfo, return -1);
 
 rloop:
                n = SSL_read(conn->ssl, ptr, len);
@@ -294,7 +348,7 @@ rloop:
 
                                        if (n == -1)
                                        {
-                                               REMEMBER_EPIPE(SOCK_ERRNO == EPIPE);
+                                               REMEMBER_EPIPE(spinfo, SOCK_ERRNO == EPIPE);
                                                printfPQExpBuffer(&conn->errorMessage,
                                                                        libpq_gettext("SSL SYSCALL error: %s\n"),
                                                        SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
@@ -330,7 +384,7 @@ rloop:
                                break;
                }
 
-               RESTORE_SIGPIPE();
+               RESTORE_SIGPIPE(conn, spinfo);
        }
        else
 #endif
@@ -346,14 +400,15 @@ ssize_t
 pqsecure_write(PGconn *conn, const void *ptr, size_t len)
 {
        ssize_t         n;
-
-       DISABLE_SIGPIPE(return -1);
+       DECLARE_SIGPIPE_INFO(spinfo);
 
 #ifdef USE_SSL
        if (conn->ssl)
        {
                int                     err;
 
+               DISABLE_SIGPIPE(conn, spinfo, return -1);
+
                n = SSL_write(conn->ssl, ptr, len);
                err = SSL_get_error(conn->ssl, n);
                switch (err)
@@ -378,7 +433,7 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
 
                                        if (n == -1)
                                        {
-                                               REMEMBER_EPIPE(SOCK_ERRNO == EPIPE);
+                                               REMEMBER_EPIPE(spinfo, SOCK_ERRNO == EPIPE);
                                                printfPQExpBuffer(&conn->errorMessage,
                                                                        libpq_gettext("SSL SYSCALL error: %s\n"),
                                                        SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
@@ -416,11 +471,41 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
        else
 #endif
        {
-               n = send(conn->sock, ptr, len, 0);
-               REMEMBER_EPIPE(n < 0 && SOCK_ERRNO == EPIPE);
+               int             flags = 0;
+
+#ifdef MSG_NOSIGNAL
+               if (conn->sigpipe_flag)
+                       flags |= MSG_NOSIGNAL;
+
+retry_masked:
+
+#endif /* MSG_NOSIGNAL */
+
+               DISABLE_SIGPIPE(conn, spinfo, return -1);
+
+               n = send(conn->sock, ptr, len, flags);
+
+               if (n < 0)
+               {
+                       /*
+                        * If we see an EINVAL, it may be because MSG_NOSIGNAL isn't
+                        * available on this machine.  So, clear sigpipe_flag so we don't
+                        * try the flag again, and retry the send().
+                        */
+#ifdef MSG_NOSIGNAL
+                       if (flags != 0 && SOCK_ERRNO == EINVAL)
+                       {
+                               conn->sigpipe_flag = false;
+                               flags = 0;
+                               goto retry_masked;
+                       }
+#endif /* MSG_NOSIGNAL */
+
+                       REMEMBER_EPIPE(spinfo, SOCK_ERRNO == EPIPE);
+               }
        }
 
-       RESTORE_SIGPIPE();
+       RESTORE_SIGPIPE(conn, spinfo);
 
        return n;
 }
@@ -452,11 +537,11 @@ verify_cb(int ok, X509_STORE_CTX *ctx)
  * Check if a wildcard certificate matches the server hostname.
  *
  * The rule for this is:
- *  1. We only match the '*' character as wildcard
- *  2. We match only wildcards at the start of the string
- *  3. The '*' character does *not* match '.', meaning that we match only
- *     a single pathname component.
- *  4. We don't support more than one '*' in a single pattern.
+ *     1. We only match the '*' character as wildcard
+ *     2. We match only wildcards at the start of the string
+ *     3. The '*' character does *not* match '.', meaning that we match only
+ *        a single pathname component.
+ *     4. We don't support more than one '*' in a single pattern.
  *
  * This is roughly in line with RFC2818, but contrary to what most browsers
  * appear to be implementing (point 3 being the difference)
@@ -466,8 +551,8 @@ verify_cb(int ok, X509_STORE_CTX *ctx)
 static int
 wildcard_certificate_match(const char *pattern, const char *string)
 {
-       int lenpat = strlen(pattern);
-       int lenstr = strlen(string);
+       int                     lenpat = strlen(pattern);
+       int                     lenstr = strlen(string);
 
        /* If we don't start with a wildcard, it's not a match (rule 1 & 2) */
        if (lenpat < 3 ||
@@ -479,12 +564,20 @@ wildcard_certificate_match(const char *pattern, const char *string)
                /* If pattern is longer than the string, we can never match */
                return 0;
 
-       if (pg_strcasecmp(pattern+1, string+lenstr-lenpat+1) != 0)
-               /* If string does not end in pattern (minus the wildcard), we don't match */
+       if (pg_strcasecmp(pattern + 1, string + lenstr - lenpat + 1) != 0)
+
+               /*
+                * If string does not end in pattern (minus the wildcard), we don't
+                * match
+                */
                return 0;
 
-       if (strchr(string, '.') < string+lenstr-lenpat)
-               /* If there is a dot left of where the pattern started to match, we don't match (rule 3) */
+       if (strchr(string, '.') < string + lenstr - lenpat)
+
+               /*
+                * If there is a dot left of where the pattern started to match, we
+                * don't match (rule 3)
+                */
                return 0;
 
        /* String ended with pattern, and didn't have a dot before, so we match */
@@ -499,10 +592,10 @@ static bool
 verify_peer_name_matches_certificate(PGconn *conn)
 {
        /*
-        * If told not to verify the peer name, don't do it. Return
-        * 0 indicating that the verification was successful.
+        * 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)
+       if (strcmp(conn->sslmode, "verify-full") != 0)
                return true;
 
        if (conn->pghostaddr)
@@ -629,43 +722,57 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
        BIO_free(bio);
 
        /*
-        * Read the SSL key. If a key is specified, treat it as an engine:key combination
-        * if there is colon present - we don't support files with colon in the name. The
-        * exception is if the second character is a colon, in which case it can be a Windows
-        * filename with drive specification.
+        * Read the SSL key. If a key is specified, treat it as an engine:key
+        * combination if there is colon present - we don't support files with
+        * colon in the name. The exception is if the second character is a colon,
+        * in which case it can be a Windows filename with drive specification.
         */
        if (conn->sslkey && strlen(conn->sslkey) > 0)
        {
-#if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
+#ifdef USE_SSL_ENGINE
                if (strchr(conn->sslkey, ':')
 #ifdef WIN32
                        && conn->sslkey[1] != ':'
 #endif
-                  )
+                       )
                {
                        /* Colon, but not in second character, treat as engine:key */
-                       ENGINE     *engine_ptr;
                        char       *engine_str = strdup(conn->sslkey);
                        char       *engine_colon = strchr(engine_str, ':');
 
-                       *engine_colon = '\0';   /* engine_str now has engine name */
-                       engine_colon++;                 /* engine_colon now has key name */
+                       *engine_colon = '\0';           /* engine_str now has engine name */
+                       engine_colon++;         /* engine_colon now has key name */
+
+                       conn->engine = ENGINE_by_id(engine_str);
+                       if (conn->engine == NULL)
+                       {
+                               char       *err = SSLerrmessage();
+
+                               printfPQExpBuffer(&conn->errorMessage,
+                                        libpq_gettext("could not load SSL engine \"%s\": %s\n"),
+                                                                 engine_str, err);
+                               SSLerrfree(err);
+                               free(engine_str);
+                               ERR_pop_to_mark();
+                               return 0;
+                       }
 
-                       engine_ptr = ENGINE_by_id(engine_str);
-                       if (engine_ptr == NULL)
+                       if (ENGINE_init(conn->engine) == 0)
                        {
                                char       *err = SSLerrmessage();
 
                                printfPQExpBuffer(&conn->errorMessage,
-                                                                 libpq_gettext("could not load SSL engine \"%s\": %s\n"),
+                                        libpq_gettext("could not initialize SSL engine \"%s\": %s\n"),
                                                                  engine_str, err);
                                SSLerrfree(err);
+                               ENGINE_free(conn->engine);
+                               conn->engine = NULL;
                                free(engine_str);
                                ERR_pop_to_mark();
                                return 0;
                        }
 
-                       *pkey = ENGINE_load_private_key(engine_ptr, engine_colon,
+                       *pkey = ENGINE_load_private_key(conn->engine, engine_colon,
                                                                                        NULL, NULL);
                        if (*pkey == NULL)
                        {
@@ -675,16 +782,20 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
                                                                  libpq_gettext("could not read private SSL key \"%s\" from engine \"%s\": %s\n"),
                                                                  engine_colon, engine_str, err);
                                SSLerrfree(err);
+                               ENGINE_finish(conn->engine);
+                               ENGINE_free(conn->engine);
+                               conn->engine = NULL;
                                free(engine_str);
                                ERR_pop_to_mark();
                                return 0;
                        }
                        free(engine_str);
 
-                       fnbuf[0] = '\0'; /* indicate we're not going to load from a file */
+                       fnbuf[0] = '\0';        /* indicate we're not going to load from a
+                                                                * file */
                }
                else
-#endif /* support for SSL engines */
+#endif   /* support for SSL engines */
                {
                        /* PGSSLKEY is not an engine, treat it as a filename */
                        strncpy(fnbuf, conn->sslkey, sizeof(fnbuf));
@@ -712,7 +823,7 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
                if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO))
                {
                        printfPQExpBuffer(&conn->errorMessage,
-                       libpq_gettext("private key file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"),
+                                                         libpq_gettext("private key file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"),
                                                          fnbuf);
                        ERR_pop_to_mark();
                        return 0;
@@ -810,10 +921,10 @@ pq_lockingcallback(int mode, int n, const char *file, int line)
 
 /*
  * Initialize SSL system. In threadsafe mode, this includes setting
- * up OpenSSL callback functions to do thread locking.
+ * up libcrypto callback functions to do thread locking.
  *
- * If the caller has told us (through PQinitSSL) that he's taking care
- * of SSL, we expect that callbacks are already set, and won't try to
+ * If the caller has told us (through PQinitOpenSSL) that he's taking care
+ * of libcrypto, we expect that callbacks are already set, and won't try to
  * override it.
  *
  * The conn parameter is only used to be able to pass back an error
@@ -840,15 +951,15 @@ init_ssl_system(PGconn *conn)
        if (pthread_mutex_lock(&ssl_config_mutex))
                return -1;
 
-       if (pq_initssllib)
+       if (pq_init_crypto_lib)
        {
                /*
-                * If necessary, set up an array to hold locks for OpenSSL. OpenSSL will
-                * tell us how big to make this array.
+                * If necessary, set up an array to hold locks for libcrypto.
+                * libcrypto will tell us how big to make this array.
                 */
                if (pq_lockarray == NULL)
                {
-                       int i;
+                       int                     i;
 
                        pq_lockarray = malloc(sizeof(pthread_mutex_t) * CRYPTO_num_locks());
                        if (!pq_lockarray)
@@ -870,16 +981,16 @@ init_ssl_system(PGconn *conn)
 
                if (ssl_open_connections++ == 0)
                {
-                       /* These are only required for threaded SSL applications */
+                       /* These are only required for threaded libcrypto applications */
                        CRYPTO_set_id_callback(pq_threadidcallback);
                        CRYPTO_set_locking_callback(pq_lockingcallback);
                }
        }
-#endif /* ENABLE_THREAD_SAFETY */
+#endif   /* ENABLE_THREAD_SAFETY */
 
        if (!SSL_context)
        {
-               if (pq_initssllib)
+               if (pq_init_ssl_lib)
                {
 #if SSLEAY_VERSION_NUMBER >= 0x00907000L
                        OPENSSL_config(NULL);
@@ -912,9 +1023,10 @@ init_ssl_system(PGconn *conn)
 /*
  *     This function is needed because if the libpq library is unloaded
  *     from the application, the callback functions will no longer exist when
- *     SSL used by other parts of the system.  For this reason,
- *     we unregister the SSL callback functions when the last libpq
- *     connection is closed.
+ *     libcrypto is used by other parts of the system.  For this reason,
+ *     we unregister the callback functions when the last libpq
+ *     connection is closed.  (The same would apply for OpenSSL callbacks
+ *     if we had any.)
  *
  *     Callbacks are only set when we're compiled in threadsafe mode, so
  *     we only need to remove them in this case.
@@ -927,26 +1039,22 @@ destroy_ssl_system(void)
        if (pthread_mutex_lock(&ssl_config_mutex))
                return;
 
-       if (pq_initssllib)
-       {
-               if (ssl_open_connections > 0)
-                       --ssl_open_connections;
+       if (pq_init_crypto_lib && ssl_open_connections > 0)
+               --ssl_open_connections;
 
-               if (ssl_open_connections == 0)
-               {
-                       /* No connections left, unregister all callbacks */
-                       CRYPTO_set_locking_callback(NULL);
-                       CRYPTO_set_id_callback(NULL);
+       if (pq_init_crypto_lib && ssl_open_connections == 0)
+       {
+               /* No connections left, unregister libcrypto callbacks */
+               CRYPTO_set_locking_callback(NULL);
+               CRYPTO_set_id_callback(NULL);
 
-                       /*
-                        * We don't free the lock array. If we get another connection
-                        * from the same caller, we will just re-use it with the existing
-                        * mutexes.
-                        *
-                        * This means we leak a little memory on repeated load/unload
-                        * of the library.
-                        */
-               }
+               /*
+                * We don't free the lock array. If we get another connection in this
+                * process, we will just re-use it with the existing mutexes.
+                *
+                * This means we leak a little memory on repeated load/unload of the
+                * library.
+                */
        }
 
        pthread_mutex_unlock(&ssl_config_mutex);
@@ -968,19 +1076,20 @@ initialize_SSL(PGconn *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.
+        * If sslmode is set to one of the verify options, perform certificate
+        * verification. If set to "verify-full" we will also do further
+        * verification after the connection has been completed.
         *
-        * If we are going to look for either root certificate or CRL in the home directory,
-        * we need pqGetHomeDirectory() to succeed. In other cases, we don't need to
-        * get the home directory explicitly.
+        * If we are going to look for either root certificate or CRL in the home
+        * directory, we need pqGetHomeDirectory() to succeed. In other cases, we
+        * don't need to get the home directory explicitly.
         */
        if (!conn->sslrootcert || !conn->sslcrl)
        {
                if (!pqGetHomeDirectory(homedir, sizeof(homedir)))
                {
-                       if (strcmp(conn->sslverify, "none") != 0)
+                       if (conn->sslmode[0] == 'v')            /* "verify-ca" or
+                                                                                                * "verify-full" */
                        {
                                printfPQExpBuffer(&conn->errorMessage,
                                                                  libpq_gettext("could not get home directory to locate root certificate file"));
@@ -993,8 +1102,6 @@ initialize_SSL(PGconn *conn)
                homedir[0] = '\0';
        }
 
-
-
        if (conn->sslrootcert)
                strncpy(fnbuf, conn->sslrootcert, sizeof(fnbuf));
        else
@@ -1027,7 +1134,7 @@ initialize_SSL(PGconn *conn)
 /* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */
 #ifdef X509_V_FLAG_CRL_CHECK
                                X509_STORE_set_flags(cvstore,
-                                         X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
+                                                 X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
                        /* if not found, silently ignore;  we do not require CRL */
 #else
                        {
@@ -1047,10 +1154,11 @@ initialize_SSL(PGconn *conn)
        else
        {
                /* stat() failed; assume cert file doesn't exist */
-               if (strcmp(conn->sslverify, "none") != 0)
+               if (conn->sslmode[0] == 'v')    /* "verify-ca" or "verify-full" */
                {
                        printfPQExpBuffer(&conn->errorMessage,
-                                                         libpq_gettext("root certificate file \"%s\" does not exist"), fnbuf);
+                               libpq_gettext("root certificate file \"%s\" does not exist\n"
+                                                         "Either provide the file or change sslmode to disable server certificate verification.\n"), fnbuf);
                        return -1;
                }
        }
@@ -1135,8 +1243,8 @@ open_client_SSL(PGconn *conn)
        }
 
        /*
-        * We already checked the server certificate in initialize_SSL()
-        * using SSL_CTX_set_verify() if root.crt exists.
+        * We already checked the server certificate in initialize_SSL() using
+        * SSL_CTX_set_verify() if root.crt exists.
         */
 
        /* pull out server distinguished and common names */
@@ -1157,9 +1265,28 @@ open_client_SSL(PGconn *conn)
                                          conn->peer_dn, sizeof(conn->peer_dn));
        conn->peer_dn[sizeof(conn->peer_dn) - 1] = '\0';
 
-       X509_NAME_get_text_by_NID(X509_get_subject_name(conn->peer),
+       r = X509_NAME_get_text_by_NID(X509_get_subject_name(conn->peer),
                                                          NID_commonName, conn->peer_cn, SM_USER);
-       conn->peer_cn[SM_USER] = '\0';
+       conn->peer_cn[SM_USER] = '\0'; /* buffer is SM_USER+1 chars! */
+       if (r == -1)
+       {
+               /* Unable to get the CN, set it to blank so it can't be used */
+               conn->peer_cn[0] = '\0';
+       }
+       else
+       {
+               /*
+                * Reject embedded NULLs in certificate common name to prevent attacks like
+                * CVE-2009-4034.
+                */
+               if (r != strlen(conn->peer_cn))
+               {
+                       printfPQExpBuffer(&conn->errorMessage,
+                                                         libpq_gettext("SSL certificate's common name contains embedded null\n"));
+                       close_SSL(conn);
+                       return PGRES_POLLING_FAILED;
+               }
+       }
 
        if (!verify_peer_name_matches_certificate(conn))
        {
@@ -1179,14 +1306,16 @@ close_SSL(PGconn *conn)
 {
        if (conn->ssl)
        {
-               DISABLE_SIGPIPE((void) 0);
+               DECLARE_SIGPIPE_INFO(spinfo);
+
+               DISABLE_SIGPIPE(conn, spinfo, (void) 0);
                SSL_shutdown(conn->ssl);
                SSL_free(conn->ssl);
                conn->ssl = NULL;
                pqsecure_destroy();
                /* We have to assume we got EPIPE */
-               REMEMBER_EPIPE(true);
-               RESTORE_SIGPIPE();
+               REMEMBER_EPIPE(spinfo, true);
+               RESTORE_SIGPIPE(conn, spinfo);
        }
 
        if (conn->peer)
@@ -1194,6 +1323,15 @@ close_SSL(PGconn *conn)
                X509_free(conn->peer);
                conn->peer = NULL;
        }
+
+#ifdef USE_SSL_ENGINE
+       if (conn->engine)
+       {
+               ENGINE_finish(conn->engine);
+               ENGINE_free(conn->engine);
+               conn->engine = NULL;
+       }
+#endif
 }
 
 /*