On 20/08/2018 05:13, Michael Paquier wrote:
> Patch v6 of this thread is failing to apply.  Could you rebase?

attached

Changes in v7 since v6:

- Added support for ssl_passphrase_command.

- Test suite needed some adjustment because GnuTLS doesn't appear to
understand the previously used file format for encrypted keys.

- Removed tls-unique channel binding support.  Support for
tls-server-end-point still needs to be added, but it could be a separate
patch.

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
>From 85465f4ad3e210a3948216ebc5c6fbd8c6993bdb Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pete...@gmx.net>
Date: Fri, 31 Aug 2018 13:00:26 +0200
Subject: [PATCH v7] GnuTLS support

---
 configure                                     | 166 +++-
 configure.in                                  |  37 +-
 doc/src/sgml/client-auth.sgml                 |   2 +-
 doc/src/sgml/config.sgml                      |  69 +-
 doc/src/sgml/installation.sgml                |  47 +-
 doc/src/sgml/libpq.sgml                       |  54 +-
 doc/src/sgml/runtime.sgml                     |  13 +-
 doc/src/sgml/sslinfo.sgml                     |   1 +
 src/Makefile.global.in                        |   1 +
 src/backend/libpq/Makefile                    |   4 +-
 src/backend/libpq/be-secure-gnutls.c          | 795 +++++++++++++++++
 src/backend/libpq/be-secure-openssl.c         |   4 +-
 src/backend/libpq/be-secure.c                 |   3 +
 src/backend/libpq/hba.c                       |   2 +-
 src/backend/utils/misc/guc.c                  |  25 +
 src/backend/utils/misc/postgresql.conf.sample |  11 +-
 src/common/Makefile                           |   4 +-
 src/common/sha2_gnutls.c                      |  99 +++
 src/include/common/sha2.h                     |  14 +-
 src/include/libpq/libpq-be.h                  |  15 +-
 src/include/libpq/libpq.h                     |   1 +
 src/include/pg_config.h.in                    |  17 +
 src/include/pg_config_manual.h                |   2 +-
 src/interfaces/libpq/.gitignore               |   1 +
 src/interfaces/libpq/Makefile                 |  14 +-
 src/interfaces/libpq/fe-secure-gnutls.c       | 803 ++++++++++++++++++
 src/interfaces/libpq/fe-secure.c              |   2 +-
 src/interfaces/libpq/libpq-fe.h               |   2 +-
 src/interfaces/libpq/libpq-int.h              |  14 +-
 src/port/pg_strong_random.c                   |  18 +-
 src/test/Makefile                             |   2 +-
 src/test/ssl/Makefile                         |   7 +-
 src/test/ssl/ssl/server-password.key          |  35 +-
 src/test/ssl/t/001_ssltests.pl                |  63 +-
 src/test/ssl/t/002_scram.pl                   |   2 +-
 src/tools/msvc/Mkvcbuild.pm                   |  10 +
 src/tools/pgindent/typedefs.list              |   3 +
 37 files changed, 2248 insertions(+), 114 deletions(-)
 create mode 100644 src/backend/libpq/be-secure-gnutls.c
 create mode 100644 src/common/sha2_gnutls.c
 create mode 100644 src/interfaces/libpq/fe-secure-gnutls.c

diff --git a/configure b/configure
index dd94c5bbab..564f33ae5d 100755
--- a/configure
+++ b/configure
@@ -707,6 +707,7 @@ UUID_EXTRA_OBJS
 with_uuid
 with_systemd
 with_selinux
+with_gnutls
 with_openssl
 with_ldap
 with_krb_srvnam
@@ -853,6 +854,7 @@ with_bsd_auth
 with_ldap
 with_bonjour
 with_openssl
+with_gnutls
 with_selinux
 with_systemd
 with_readline
@@ -1553,6 +1555,7 @@ Optional Packages:
   --with-ldap             build with LDAP support
   --with-bonjour          build with Bonjour support
   --with-openssl          build with OpenSSL support
+  --with-gnutls           build with GnuTLS support
   --with-selinux          build with SELinux support
   --with-systemd          build with systemd support
   --without-readline      do not use GNU Readline nor BSD Libedit for editing
@@ -7933,6 +7936,47 @@ fi
 $as_echo "$with_openssl" >&6; }
 
 
+
+#
+# GnuTLS
+#
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build with GnuTLS 
support" >&5
+$as_echo_n "checking whether to build with GnuTLS support... " >&6; }
+
+
+
+# Check whether --with-gnutls was given.
+if test "${with_gnutls+set}" = set; then :
+  withval=$with_gnutls;
+  case $withval in
+    yes)
+
+$as_echo "#define USE_GNUTLS 1" >>confdefs.h
+
+      ;;
+    no)
+      :
+      ;;
+    *)
+      as_fn_error $? "no argument expected for --with-gnutls option" "$LINENO" 
5
+      ;;
+  esac
+
+else
+  with_gnutls=no
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_gnutls" >&5
+$as_echo "$with_gnutls" >&6; }
+
+
+if test "$with_openssl" = yes && test "$with_gnutls" = yes; then
+  as_fn_error $? "cannot specify both --with-openssl and --with-gnutls" 
"$LINENO" 5
+fi
+
+
 #
 # SELinux
 #
@@ -12052,6 +12096,107 @@ done
 
 fi
 
+if test "$with_gnutls" = yes ; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing 
gnutls_init" >&5
+$as_echo_n "checking for library containing gnutls_init... " >&6; }
+if ${ac_cv_search_gnutls_init+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gnutls_init ();
+int
+main ()
+{
+return gnutls_init ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' gnutls; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_gnutls_init=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_gnutls_init+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_gnutls_init+:} false; then :
+
+else
+  ac_cv_search_gnutls_init=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gnutls_init" >&5
+$as_echo "$ac_cv_search_gnutls_init" >&6; }
+ac_res=$ac_cv_search_gnutls_init
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+else
+  as_fn_error $? "library 'gnutls' is required for GnuTLS" "$LINENO" 5
+fi
+
+  # GnuTLS versions before 3.4.0 do not support sorting incorrectly sorted
+  # certificate chains.
+  ac_fn_c_check_decl "$LINENO" "GNUTLS_ALPN_SERVER_PRECEDENCE" 
"ac_cv_have_decl_GNUTLS_ALPN_SERVER_PRECEDENCE" "#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+"
+if test "x$ac_cv_have_decl_GNUTLS_ALPN_SERVER_PRECEDENCE" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GNUTLS_ALPN_SERVER_PRECEDENCE $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "GNUTLS_X509_CRT_LIST_SORT" 
"ac_cv_have_decl_GNUTLS_X509_CRT_LIST_SORT" "#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+"
+if test "x$ac_cv_have_decl_GNUTLS_X509_CRT_LIST_SORT" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GNUTLS_X509_CRT_LIST_SORT $ac_have_decl
+_ACEOF
+
+  for ac_func in gnutls_pkcs11_set_pin_function
+do :
+  ac_fn_c_check_func "$LINENO" "gnutls_pkcs11_set_pin_function" 
"ac_cv_func_gnutls_pkcs11_set_pin_function"
+if test "x$ac_cv_func_gnutls_pkcs11_set_pin_function" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_GNUTLS_PKCS11_SET_PIN_FUNCTION 1
+_ACEOF
+
+fi
+done
+
+fi
+
 if test "$with_pam" = yes ; then
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pam_start in -lpam" >&5
 $as_echo_n "checking for pam_start in -lpam... " >&6; }
@@ -12954,6 +13099,17 @@ else
 fi
 
 
+fi
+
+if test "$with_gnutls" = yes ; then
+  ac_fn_c_check_header_mongrel "$LINENO" "gnutls/gnutls.h" 
"ac_cv_header_gnutls_gnutls_h" "$ac_includes_default"
+if test "x$ac_cv_header_gnutls_gnutls_h" = xyes; then :
+
+else
+  as_fn_error $? "header file <gnutls/gnutls.h> is required for GnuTLS" 
"$LINENO" 5
+fi
+
+
 fi
 
 if test "$with_pam" = yes ; then
@@ -17835,9 +17991,11 @@ fi
 # in the template or configure command line.
 
 # If not selected manually, try to select a source automatically.
-if test "$enable_strong_random" = "yes" && test x"$USE_OPENSSL_RANDOM" = x"" 
&& test x"$USE_WIN32_RANDOM" = x"" && test x"$USE_DEV_URANDOM" = x"" ; then
+if test "$enable_strong_random" = "yes" && test x"$USE_OPENSSL_RANDOM" = x"" 
&& test x"$USE_GNUTLS_RANDOM" = x"" && test x"$USE_WIN32_RANDOM" = x"" && test 
x"$USE_DEV_URANDOM" = x"" ; then
   if test x"$with_openssl" = x"yes" ; then
     USE_OPENSSL_RANDOM=1
+  elif test x"$with_gnutls" = x"yes" ; then
+    USE_GNUTLS_RANDOM=1
   elif test "$PORTNAME" = "win32" ; then
     USE_WIN32_RANDOM=1
   else
@@ -17876,6 +18034,12 @@ $as_echo "#define USE_OPENSSL_RANDOM 1" >>confdefs.h
 
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: OpenSSL" >&5
 $as_echo "OpenSSL" >&6; }
+  elif test x"$USE_GNUTLS_RANDOM" = x"1" ; then
+
+$as_echo "#define USE_GNUTLS_RANDOM 1" >>confdefs.h
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: GnuTLS" >&5
+$as_echo "GnuTLS" >&6; }
   elif test x"$USE_WIN32_RANDOM" = x"1" ; then
 
 $as_echo "#define USE_WIN32_RANDOM 1" >>confdefs.h
diff --git a/configure.in b/configure.in
index 3280afa0da..29b203673b 100644
--- a/configure.in
+++ b/configure.in
@@ -822,6 +822,21 @@ PGAC_ARG_BOOL(with, openssl, no, [build with OpenSSL 
support],
 AC_MSG_RESULT([$with_openssl])
 AC_SUBST(with_openssl)
 
+
+#
+# GnuTLS
+#
+AC_MSG_CHECKING([whether to build with GnuTLS support])
+PGAC_ARG_BOOL(with, gnutls, no, [build with GnuTLS support],
+              [AC_DEFINE([USE_GNUTLS], 1, [Define to build with GnuTLS 
support. (--with-gnutls)])])
+AC_MSG_RESULT([$with_gnutls])
+AC_SUBST(with_gnutls)
+
+if test "$with_openssl" = yes && test "$with_gnutls" = yes; then
+  AC_MSG_ERROR([cannot specify both --with-openssl and --with-gnutls])
+fi
+
+
 #
 # SELinux
 #
@@ -1190,6 +1205,17 @@ if test "$with_openssl" = yes ; then
   AC_CHECK_FUNCS([CRYPTO_lock])
 fi
 
+if test "$with_gnutls" = yes ; then
+  AC_SEARCH_LIBS(gnutls_init, gnutls, [], [AC_MSG_ERROR([library 'gnutls' is 
required for GnuTLS])])
+  # GnuTLS versions before 3.4.0 do not support sorting incorrectly sorted
+  # certificate chains.
+  AC_CHECK_DECLS([GNUTLS_ALPN_SERVER_PRECEDENCE, GNUTLS_X509_CRT_LIST_SORT], 
[], [],
+[#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+])
+  AC_CHECK_FUNCS([gnutls_pkcs11_set_pin_function])
+fi
+
 if test "$with_pam" = yes ; then
   AC_CHECK_LIB(pam,    pam_start, [], [AC_MSG_ERROR([library 'pam' is required 
for PAM])])
 fi
@@ -1340,6 +1366,10 @@ if test "$with_openssl" = yes ; then
   AC_CHECK_HEADER(openssl/err.h, [], [AC_MSG_ERROR([header file 
<openssl/err.h> is required for OpenSSL])])
 fi
 
+if test "$with_gnutls" = yes ; then
+  AC_CHECK_HEADER(gnutls/gnutls.h, [], [AC_MSG_ERROR([header file 
<gnutls/gnutls.h> is required for GnuTLS])])
+fi
+
 if test "$with_pam" = yes ; then
   AC_CHECK_HEADERS(security/pam_appl.h, [],
                    [AC_CHECK_HEADERS(pam/pam_appl.h, [],
@@ -2139,9 +2169,11 @@ fi
 # in the template or configure command line.
 
 # If not selected manually, try to select a source automatically.
-if test "$enable_strong_random" = "yes" && test x"$USE_OPENSSL_RANDOM" = x"" 
&& test x"$USE_WIN32_RANDOM" = x"" && test x"$USE_DEV_URANDOM" = x"" ; then
+if test "$enable_strong_random" = "yes" && test x"$USE_OPENSSL_RANDOM" = x"" 
&& test x"$USE_GNUTLS_RANDOM" = x"" && test x"$USE_WIN32_RANDOM" = x"" && test 
x"$USE_DEV_URANDOM" = x"" ; then
   if test x"$with_openssl" = x"yes" ; then
     USE_OPENSSL_RANDOM=1
+  elif test x"$with_gnutls" = x"yes" ; then
+    USE_GNUTLS_RANDOM=1
   elif test "$PORTNAME" = "win32" ; then
     USE_WIN32_RANDOM=1
   else
@@ -2158,6 +2190,9 @@ if test "$enable_strong_random" = yes ; then
   if test x"$USE_OPENSSL_RANDOM" = x"1" ; then
     AC_DEFINE(USE_OPENSSL_RANDOM, 1, [Define to use OpenSSL for random number 
generation])
     AC_MSG_RESULT([OpenSSL])
+  elif test x"$USE_GNUTLS_RANDOM" = x"1" ; then
+    AC_DEFINE(USE_GNUTLS_RANDOM, 1, [Define to use GnuTLS for random number 
generation])
+    AC_MSG_RESULT([GnuTLS])
   elif test x"$USE_WIN32_RANDOM" = x"1" ; then
     AC_DEFINE(USE_WIN32_RANDOM, 1, [Define to use native Windows API for 
random number generation])
     AC_MSG_RESULT([Windows native])
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index c2114021c3..6a7d5bc3bc 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -1790,7 +1790,7 @@ <title>RADIUS Authentication</title>
          <para>
           The encryption vector used will only be cryptographically
           strong if <productname>PostgreSQL</productname> is built with 
support for
-          <productname>OpenSSL</productname>. In other cases, the transmission 
to the
+          an SSL library (e.g., <productname>OpenSSL</productname>). In other 
cases, the transmission to the
           RADIUS server should only be considered obfuscated, not secured, and
           external security measures should be applied if necessary.
          </para>
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index bee4afbe4e..e9e4d06b72 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1156,6 +1156,37 @@ <title>SSL</title>
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-ssl-dh-params-file" xreflabel="ssl_dh_params_file">
+      <term><varname>ssl_dh_params_file</varname> (<type>string</type>)
+      <indexterm>
+       <primary><varname>ssl_dh_params_file</varname> configuration 
parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Specifies the name of the file containing Diffie-Hellman parameters
+        used for so-called ephemeral DH family of SSL ciphers. The default is
+        empty, in which case compiled-in default DH parameters used. Using
+        custom DH parameters reduces the exposure if an attacker manages to
+        crack the well-known compiled-in DH parameters. You can create your own
+        DH parameters file with the command
+        <command>openssl dhparam -out dhparams.pem 2048</command>.
+       </para>
+
+       <para>
+        This parameter can only be set in the 
<filename>postgresql.conf</filename>
+        file or on the server command line.
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+
+    <para>
+     The following settings are only applicable if the
+     <productname>OpenSSL</productname> library is used.
+    </para>
+
+    <variablelist>
      <varlistentry id="guc-ssl-ciphers" xreflabel="ssl_ciphers">
       <term><varname>ssl_ciphers</varname> (<type>string</type>)
       <indexterm>
@@ -1289,27 +1320,36 @@ <title>SSL</title>
        </para>
       </listitem>
      </varlistentry>
+    </variablelist>
 
-     <varlistentry id="guc-ssl-dh-params-file" xreflabel="ssl_dh_params_file">
-      <term><varname>ssl_dh_params_file</varname> (<type>string</type>)
+    <para>
+     The following settings are only applicable if the
+     <productname>GnuTLS</productname> library is used.
+    </para>
+
+    <variablelist>
+     <varlistentry id="guc-gnutls-priority" xreflabel="gnutls_priority">
+      <term><varname>gnutls_priority</varname> (<type>string</type>)
       <indexterm>
-       <primary><varname>ssl_dh_params_file</varname> configuration 
parameter</primary>
+       <primary><varname>gnutls_priority</varname> configuration 
parameter</primary>
       </indexterm>
       </term>
       <listitem>
        <para>
-        Specifies the name of the file containing Diffie-Hellman parameters
-        used for so-called ephemeral DH family of SSL ciphers. The default is
-        empty, in which case compiled-in default DH parameters used. Using
-        custom DH parameters reduces the exposure if an attacker manages to
-        crack the well-known compiled-in DH parameters. You can create your own
-        DH parameters file with the command
-        <command>openssl dhparam -out dhparams.pem 2048</command>.
+        Sets the priorities for the cipher suites supported by GnuTLS.  This
+        can be used to specify which SSL cipher suites are allowed to be
+        used on secure connections and related settings.  See the
+        documentation on GnuTLS priority strings for details.
+        This parameter can only be set in the 
<filename>postgresql.conf</filename>
+        file or on the server command line.
        </para>
 
        <para>
-        This parameter can only be set in the 
<filename>postgresql.conf</filename>
-        file or on the server command line.
+        The default value is <literal>NORMAL:%SERVER_PRECEDENCE</literal> (or
+        just <literal>NORMAL</literal> with older
+        <productname>GnuTLS</productname> versions that don't support the
+        server precedence setting).  The default is usually a reasonable
+        choice unless you have specific security requirements.
        </para>
       </listitem>
      </varlistentry>
@@ -1374,6 +1414,7 @@ <title>SSL</title>
       </listitem>
      </varlistentry>
     </variablelist>
+
     </sect2>
    </sect1>
 
@@ -8411,8 +8452,8 @@ <title>Preset Options</title>
        <para>
         Reports the name of the SSL library that this PostgreSQL server was
         built with (even if SSL is not currently configured or in use on this
-        instance), for example <literal>OpenSSL</literal>, or an empty string
-        if none.
+        instance), for example <literal>OpenSSL</literal> or
+        <literal>GnuTLS</literal>, or an empty string if none.
        </para>
       </listitem>
      </varlistentry>
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index 4487d0cfd1..e0231bdc5e 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -244,9 +244,9 @@ <title>Requirements</title>
 
     <listitem>
      <para>
-      You need <productname>OpenSSL</productname>, if you want to support
-      encrypted client connections. The minimum required version is
-      0.9.8.
+      If you want to support encrypted client connections (SSL/TLS), you need
+      <productname>OpenSSL</productname> (at least version 0.9.8) or
+      <productname>GnuTLS</productname>.
      </para>
     </listitem>
 
@@ -727,6 +727,29 @@ <title>Configuration</title>
        </listitem>
       </varlistentry>
 
+      <varlistentry>
+       <term><option>--with-gnutls</option>
+       <indexterm>
+        <primary>GnuTLS</primary>
+        <seealso>SSL</seealso>
+       </indexterm>
+       </term>
+       <listitem>
+        <para>
+         Build with support for <acronym>TLS</acronym>/<acronym>SSL</acronym>
+         (encrypted) connections using the <productname>GnuTLS</productname>
+         package.  <filename>configure</filename> will check for the required
+         header files and libraries to make sure that your
+         <productname>GnuTLS</productname> installation is sufficient before
+         proceeding.
+        </para>
+
+        <para>
+         See also <option>--with-openssl</option> for an alternative.
+        </para>
+       </listitem>
+      </varlistentry>
+
       <varlistentry>
        <term><option>--with-gssapi</option></term>
        <listitem>
@@ -833,12 +856,16 @@ <title>Configuration</title>
        </term>
        <listitem>
         <para>
-         Build with support for <acronym>SSL</acronym> (encrypted)
-         connections. This requires the <productname>OpenSSL</productname>
-         package to be installed.  <filename>configure</filename> will check
-         for the required header files and libraries to make sure that
-         your <productname>OpenSSL</productname> installation is sufficient
-         before proceeding.
+         Build with support for <acronym>SSL</acronym>/<acronym>TLS</acronym>
+         (encrypted) connections using the <productname>OpenSSL</productname>
+         package.  <filename>configure</filename> will check for the required
+         header files and libraries to make sure that your
+         <productname>OpenSSL</productname> installation is sufficient before
+         proceeding.
+        </para>
+
+        <para>
+         See also <option>--with-gnutls</option> for an alternative.
         </para>
        </listitem>
       </varlistentry>
@@ -2370,7 +2397,7 @@ <title>Cygwin</title>
 
      <listitem>
       <para>
-       OpenSSL is not supported.
+       SSL is not supported.
       </para>
      </listitem>
 
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 5e7931ba90..5ec3e78717 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1449,6 +1449,9 @@ <title>Parameter Key Words</title>
         does not support disabling compression, so this parameter is ignored
         with those versions, and whether compression is used depends on the
         server.
+        <productname>GnuTLS</productname> does not support SSL compression,
+        and this parameter will be ignored if <productname>libpq</productname>
+        is using <productname>GnuTLS</productname>.
        </para>
 
        <para>
@@ -2201,8 +2204,8 @@ <title>Connection Status Functions</title>
          <term><literal>library</literal></term>
           <listitem>
            <para>
-            Name of the SSL implementation in use. (Currently, only
-            <literal>"OpenSSL"</literal> is implemented)
+            Name of the SSL implementation in use, e.g.,
+            <literal>OpenSSL</literal> or <literal>GnuTLS</literal>
            </para>
           </listitem>
          </varlistentry>
@@ -2271,11 +2274,11 @@ <title>Connection Status Functions</title>
 <synopsis>
 void *PQsslStruct(const PGconn *conn, const char *struct_name);
 </synopsis>
+       The struct(s) available depend on the SSL implementation in use.
       </para>
       <para>
-       The struct(s) available depend on the SSL implementation in use.
-       For OpenSSL, there is one struct, available under the name "OpenSSL",
-       and it returns a pointer to the OpenSSL <literal>SSL</literal> struct.
+       For OpenSSL, there is one struct, available under the name 
<literal>"OpenSSL"</literal>,
+       and it returns a pointer to the OpenSSL <type>SSL</type> struct.
        To use this function, code along the following lines could be used:
 <programlisting><![CDATA[
 #include <libpq-fe.h>
@@ -2294,12 +2297,31 @@ <title>Connection Status Functions</title>
         /* use OpenSSL functions to access ssl */
     }
 ]]></programlisting>
-      </para>
-      <para>
        This structure can be used to verify encryption levels, check server
        certificates, and more. Refer to the <productname>OpenSSL</productname>
        documentation for information about this structure.
       </para>
+      <para>
+       Similarly, for GnuTLS, the <type>gnutls_session_t</type> can be
+       obtained under the name <literal>"GnuTLS"</literal>. For example:
+<programlisting><![CDATA[
+#include <libpq-fe.h>
+#include <gnutls/gnutls.h>
+
+...
+
+    gnutls_session_t ssl;
+
+    dbconn = PQconnectdb(...);
+    ...
+
+    ssl = PQsslStruct(dbconn, "GnuTLS");
+    if (ssl)
+    {
+        /* use GnuTLS functions to access ssl */
+    }
+    ]]></programlisting>
+      </para>
      </listitem>
     </varlistentry>
 
@@ -7697,6 +7719,7 @@ <title>SSL Support</title>
   </para>
 
   <para>
+   When <productname>OpenSSL</productname> is used, then
    <application>libpq</application> reads the system-wide
    <productname>OpenSSL</productname> configuration file. By default, this
    file is named <filename>openssl.cnf</filename> and is located in the
@@ -8070,6 +8093,13 @@ <title>SSL Library Initialization</title>
    for details on the SSL API.
   </para>
 
+  <para>
+   If you are using <productname>OpenSSL</productname> version 1.1.0 or later
+   and use initialization function <function>OPENSSL_init_ssl()</function> or
+   the implicit initialization, then you don't need to do this.  Similarly,
+   this is not necessary with <productname>GnuTLS</productname>.
+  </para>
+
   <para>
    <variablelist>
     <varlistentry id="libpq-pqinitopenssl">
@@ -8105,6 +8135,10 @@ <title>SSL Library Initialization</title>
        before first opening a database connection.  Also be sure that you
        have done that initialization before opening a database connection.
       </para>
+
+      <para>
+       With <productname>GnuTLS</productname>, this function does nothing.
+      </para>
      </listitem>
     </varlistentry>
 
@@ -8125,12 +8159,16 @@ <title>SSL Library Initialization</title>
       </para>
 
       <para>
-       This function is equivalent to
+       With <productname>OpenSSL</productname>, this function is equivalent to
        <literal>PQinitOpenSSL(do_ssl, do_ssl)</literal>.
        It is sufficient for applications that initialize both or neither
        of <application>OpenSSL</application> and <literal>libcrypto</literal>.
       </para>
 
+      <para>
+       With <productname>GnuTLS</productname>, this function does nothing.
+      </para>
+
       <para>
        <function>PQinitSSL</function> has been present since
        <productname>PostgreSQL</productname> 8.0, while 
<function>PQinitOpenSSL</function>
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 8d9d40664b..8b8201f89f 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -2167,10 +2167,14 @@ <title>Secure TCP/IP Connections with SSL</title>
   <para>
    <productname>PostgreSQL</productname> has native support for using
    <acronym>SSL</acronym> connections to encrypt client/server communications
-   for increased security. This requires that
-   <productname>OpenSSL</productname> is installed on both client and
-   server systems and that support in <productname>PostgreSQL</productname> is
-   enabled at build time (see <xref linkend="installation"/>).
+   for increased security.  This requires that support in
+   <productname>PostgreSQL</productname> is enabled at build time (see <xref
+   linkend="installation"/>).  <productname>PostgreSQL</productname> supports
+   both <productname>OpenSSL</productname> and
+   <productname>GnuTLS</productname> as the SSL implementation.  This is
+   chosen at build time.  Third-party clients may also use other SSL
+   implementations.  Clients and servers using different SSL implementations
+   are compatible.
   </para>
 
   <sect2 id="ssl-setup">
@@ -2249,6 +2253,7 @@ <title>Basic Setup</title>
    <title>OpenSSL Configuration</title>
 
   <para>
+   When using <productname>OpenSSL</productname>,
    <productname>PostgreSQL</productname> reads the system-wide
    <productname>OpenSSL</productname> configuration file. By default, this
    file is named <filename>openssl.cnf</filename> and is located in the
diff --git a/doc/src/sgml/sslinfo.sgml b/doc/src/sgml/sslinfo.sgml
index cda09aaafd..782d63fd40 100644
--- a/doc/src/sgml/sslinfo.sgml
+++ b/doc/src/sgml/sslinfo.sgml
@@ -17,6 +17,7 @@ <title>sslinfo</title>
  <para>
   This extension won't build at all unless the installation was
   configured with <literal>--with-openssl</literal>.
+  (GnuTLS is currently not supported.)
  </para>
 
  <sect2>
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 91d7cb83dc..e9c3eed337 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -184,6 +184,7 @@ with_icu    = @with_icu@
 with_perl      = @with_perl@
 with_python    = @with_python@
 with_tcl       = @with_tcl@
+with_gnutls    = @with_gnutls@
 with_openssl   = @with_openssl@
 with_selinux   = @with_selinux@
 with_systemd   = @with_systemd@
diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile
index 3dbec23e30..c3720539d3 100644
--- a/src/backend/libpq/Makefile
+++ b/src/backend/libpq/Makefile
@@ -17,7 +17,9 @@ include $(top_builddir)/src/Makefile.global
 OBJS = be-fsstubs.o be-secure.o be-secure-common.o auth.o crypt.o hba.o 
ifaddr.o pqcomm.o \
        pqformat.o pqmq.o pqsignal.o auth-scram.o
 
-ifeq ($(with_openssl),yes)
+ifeq ($(with_gnutls),yes)
+OBJS += be-secure-gnutls.o
+else ifeq ($(with_openssl),yes)
 OBJS += be-secure-openssl.o
 endif
 
diff --git a/src/backend/libpq/be-secure-gnutls.c 
b/src/backend/libpq/be-secure-gnutls.c
new file mode 100644
index 0000000000..24fcfa500c
--- /dev/null
+++ b/src/backend/libpq/be-secure-gnutls.c
@@ -0,0 +1,795 @@
+/*-------------------------------------------------------------------------
+ *
+ * be-secure-gnutls.c
+ *       functions for GnuTLS support in the backend.
+ *
+ *
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *       src/backend/libpq/be-secure-gnutls.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include <sys/stat.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#endif
+#include <gnutls/x509.h>
+#include <gnutls/pkcs11.h>
+
+#include "libpq/libpq.h"
+#include "miscadmin.h"
+#include "pgstat.h"
+#include "storage/fd.h"
+#include "storage/latch.h"
+#include "tcop/tcopprot.h"
+#include "utils/memutils.h"
+
+
+static ssize_t my_sock_read(gnutls_transport_ptr_t h, void *buf, size_t size);
+static ssize_t my_sock_write(gnutls_transport_ptr_t h, const void *buf, size_t 
size);
+static int     get_peer_certificate(gnutls_session_t ssl, gnutls_x509_crt_t 
*peer);
+static bool load_dh_file(gnutls_dh_params_t dh, char *filename, bool 
isServerStart);
+static bool load_dh_buffer(gnutls_dh_params_t dh, const char *, size_t, bool 
isServerStart);
+#ifdef HAVE_GNUTLS_PKCS11_SET_PIN_FUNCTION
+static int pin_function(void *userdata, int attempt,
+                        const char *token_url,
+                        const char *token_label,
+                        unsigned int flags,
+                        char *pin, size_t pin_max);
+static int dummy_pin_function(void *userdata, int attempt,
+                                  const char *token_url,
+                                  const char *token_label,
+                                  unsigned int flags,
+                                  char *pin, size_t pin_max);
+#endif
+static int     verify_cb(gnutls_session_t ssl);
+static bool initialize_dh(gnutls_dh_params_t *dh_params, bool isServerStart);
+
+static gnutls_certificate_credentials_t tls_credentials = NULL;
+static gnutls_dh_params_t tls_dh_params = NULL;
+static gnutls_priority_t tls_priority = NULL;
+static bool tls_initialized = false;
+static bool pin_function_called = false;
+static bool ssl_is_server_start;
+
+
+/* ------------------------------------------------------------ */
+/*                                              Public interface               
                                */
+/* ------------------------------------------------------------ */
+
+int
+be_tls_init(bool isServerStart)
+{
+       gnutls_certificate_credentials_t credentials = NULL;
+       gnutls_priority_t priority = NULL;
+       gnutls_dh_params_t dh_params = NULL;
+       int                     ret;
+       const char *err_pos;
+
+       /* This stuff need be done only once. */
+       if (!tls_initialized)
+       {
+               gnutls_global_init();
+               tls_initialized = true;
+       }
+
+       ret = gnutls_certificate_allocate_credentials(&credentials);
+       if (ret < 0)
+       {
+               ereport(isServerStart ? FATAL : LOG,
+                               (errmsg("could not create SSL credentials: %s",
+                                               gnutls_strerror(ret))));
+               goto error;
+       }
+
+       /*
+        * Set PIN (passphrase) callback.  Note that there is no default for 
this
+        * in GnuTLS.
+        *
+        * If reloading, substitute a dummy callback, because we don't want to
+        * prompt for a passphrase in an already-running server.
+        */
+#ifdef HAVE_GNUTLS_PKCS11_SET_PIN_FUNCTION
+       if (isServerStart)
+               gnutls_pkcs11_set_pin_function(pin_function, NULL);
+       else
+               gnutls_pkcs11_set_pin_function(dummy_pin_function, NULL);
+#endif
+       /* used by the callback */
+       ssl_is_server_start = isServerStart;
+
+       /*
+        * Load and verify server's certificate and private key
+        */
+       if (!check_ssl_key_file_permissions(ssl_key_file, isServerStart))
+               goto error;
+
+       pin_function_called = false;
+
+       ret = gnutls_certificate_set_x509_key_file(credentials, ssl_cert_file, 
ssl_key_file, GNUTLS_X509_FMT_PEM);
+       if (ret < 0)
+       {
+               if (pin_function_called)
+                       ereport(isServerStart ? FATAL : LOG,
+                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                                        errmsg("private key file \"%s\" cannot 
be reloaded because it requires a passphrase",
+                                                       ssl_key_file)));
+               else
+                       ereport(isServerStart ? FATAL : LOG,
+                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                                        errmsg("could not load server 
certificate \"%s\" or key file \"%s\": %s",
+                                                       ssl_cert_file, 
ssl_key_file, gnutls_strerror(ret))));
+               goto error;
+       }
+
+       /* set up ephemeral DH keys */
+       if (!initialize_dh(&dh_params, isServerStart))
+               goto error;
+
+       gnutls_certificate_set_dh_params(credentials, dh_params);
+
+       /* set up the allowed cipher list */
+       ret = gnutls_priority_init(&priority, gnutls_priority, &err_pos);
+       if (ret < 0)
+       {
+               if (ret == GNUTLS_E_INVALID_REQUEST)
+                       ereport(isServerStart ? FATAL : LOG,
+                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                                        errmsg("could not set the cipher list: 
syntax error at %s", err_pos)));
+               else
+                       ereport(isServerStart ? FATAL : LOG,
+                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                                        errmsg("could not set the cipher list: 
%s", gnutls_strerror(ret))));
+               goto error;
+       }
+
+       /*
+        * Load CA store, so we can verify client certificates if needed.
+        */
+       if (ssl_ca_file[0])
+       {
+               ret = gnutls_certificate_set_x509_trust_file(credentials, 
ssl_ca_file, GNUTLS_X509_FMT_PEM);
+               if (ret < 0)
+               {
+                       ereport(isServerStart ? FATAL : LOG,
+                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                                        errmsg("could not load root 
certificate file \"%s\": %s",
+                                                       ssl_ca_file, 
gnutls_strerror(ret))));
+                       goto error;
+               }
+
+               gnutls_certificate_set_verify_function(credentials, verify_cb);
+       }
+
+       /*
+        * Load the Certificate Revocation List (CRL).
+        */
+       if (ssl_crl_file[0])
+       {
+               ret = gnutls_certificate_set_x509_crl_file(credentials, 
ssl_crl_file, GNUTLS_X509_FMT_PEM);
+               if (ret < 0)
+               {
+                       ereport(isServerStart ? FATAL : LOG,
+                                       (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                                        errmsg("could not load SSL certificate 
revocation list file \"%s\": %s",
+                                                       ssl_crl_file, 
gnutls_strerror(ret))));
+                       goto error;
+               }
+       }
+
+       /*
+        * Success!  Replace any existing credentials.
+        */
+       if (tls_credentials)
+               gnutls_certificate_free_credentials(tls_credentials);
+       if (tls_priority)
+               gnutls_priority_deinit(tls_priority);
+       if (tls_dh_params)
+               gnutls_dh_params_deinit(tls_dh_params);
+
+       tls_credentials = credentials;
+       tls_priority = priority;
+       tls_dh_params = dh_params;
+
+       /*
+        * Set flag to remember whether CA store has been loaded.
+        */
+       if (ssl_ca_file[0])
+               ssl_loaded_verify_locations = true;
+       else
+               ssl_loaded_verify_locations = false;
+
+       return 0;
+
+error:
+       if (credentials)
+               gnutls_certificate_free_credentials(credentials);
+       if (priority)
+               gnutls_priority_deinit(priority);
+       if (dh_params)
+               gnutls_dh_params_deinit(dh_params);
+       return -1;
+}
+
+void
+be_tls_destroy(void)
+{
+       if (tls_credentials)
+               gnutls_certificate_free_credentials(tls_credentials);
+       if (tls_priority)
+               gnutls_priority_deinit(tls_priority);
+       if (tls_dh_params)
+               gnutls_dh_params_deinit(tls_dh_params);
+       tls_credentials = NULL;
+       tls_priority = NULL;
+       tls_dh_params = NULL;
+       ssl_loaded_verify_locations = false;
+}
+
+int
+be_tls_open_server(Port *port)
+{
+       int                     ret;
+
+       Assert(!port->ssl);
+       Assert(!port->peer);
+
+       if (!tls_credentials || !tls_priority)
+       {
+               ereport(COMMERROR,
+                               (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                errmsg("could not initialize SSL connection: 
SSL context not set up")));
+               return -1;
+       }
+
+       ret = gnutls_init(&port->ssl, GNUTLS_SERVER);
+       if (ret < 0)
+       {
+               ereport(COMMERROR,
+                               (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                errmsg("could not initialize SSL connection: 
%s",
+                                               gnutls_strerror(ret))));
+               return -1;
+       }
+
+       gnutls_transport_set_ptr(port->ssl, port);
+       gnutls_transport_set_pull_function(port->ssl, my_sock_read);
+       gnutls_transport_set_push_function(port->ssl, my_sock_write);
+
+       ret = gnutls_priority_set(port->ssl, tls_priority);
+       if (ret < 0)
+       {
+               ereport(COMMERROR,
+                               (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                errmsg("could not initialize SSL connection: 
%s",
+                                               gnutls_strerror(ret))));
+               return -1;
+       }
+
+       ret = gnutls_credentials_set(port->ssl, GNUTLS_CRD_CERTIFICATE, 
tls_credentials);
+       if (ret < 0)
+       {
+               ereport(COMMERROR,
+                               (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                errmsg("could not initialize SSL connection: 
%s",
+                                               gnutls_strerror(ret))));
+               return -1;
+       }
+
+       if (ssl_loaded_verify_locations)
+               gnutls_certificate_server_set_request(port->ssl, 
GNUTLS_CERT_REQUEST);
+
+       port->ssl_in_use = true;
+
+       do
+       {
+               ret = gnutls_handshake(port->ssl);
+       }
+       while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
+
+       if (ret < 0)
+       {
+               ereport(COMMERROR,
+                               (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                errmsg("could not accept SSL connection: %s",
+                                               gnutls_strerror(ret))));
+               return -1;
+       }
+
+       /* Get client certificate, if available. */
+       ret = get_peer_certificate(port->ssl, &port->peer);
+       if (ret < 0 && ret != GNUTLS_E_NO_CERTIFICATE_FOUND)
+       {
+               ereport(COMMERROR,
+                               (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                errmsg("could not load peer certificates: %s",
+                                               gnutls_strerror(ret))));
+       }
+
+       /* and extract the Common Name from it. */
+       port->peer_cn = NULL;
+       port->peer_cert_valid = false;
+       if (port->peer != NULL)
+       {
+               size_t          len = 0;
+
+               gnutls_x509_crt_get_dn_by_oid(port->peer,
+                                                                         
GNUTLS_OID_X520_COMMON_NAME,
+                                                                         0, 0, 
NULL, &len);
+
+               if (len > 0)
+               {
+                       char       *peer_cn;
+
+                       peer_cn = MemoryContextAlloc(TopMemoryContext, len);
+
+                       ret = gnutls_x509_crt_get_dn_by_oid(port->peer,
+                                                                               
                GNUTLS_OID_X520_COMMON_NAME,
+                                                                               
                0, 0, peer_cn, &len);
+
+                       if (ret != 0)
+                       {
+                               /* shouldn't happen */
+                               pfree(peer_cn);
+                               return -1;
+                       }
+
+                       /*
+                        * Reject embedded NULLs in certificate common name to 
prevent
+                        * attacks like CVE-2009-4034.
+                        */
+                       if (len != strlen(peer_cn))
+                       {
+                               ereport(COMMERROR,
+                                               
(errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                                errmsg("SSL certificate's 
common name contains embedded null")));
+                               pfree(peer_cn);
+                               return -1;
+                       }
+
+
+                       if (ret == 0)
+                               port->peer_cn = peer_cn;
+                       else
+                               pfree(peer_cn);
+
+               }
+
+               port->peer_cert_valid = true;
+       }
+
+       return 0;
+}
+
+void
+be_tls_close(Port *port)
+{
+       if (port->ssl)
+       {
+               gnutls_bye(port->ssl, GNUTLS_SHUT_RDWR);
+               gnutls_deinit(port->ssl);
+               port->ssl = NULL;
+               port->ssl_in_use = false;
+       }
+
+       if (port->peer)
+       {
+               gnutls_x509_crt_deinit(port->peer);
+               port->peer = NULL;
+       }
+
+       if (port->peer_cn)
+       {
+               pfree(port->peer_cn);
+               port->peer_cn = NULL;
+       }
+}
+
+ssize_t
+be_tls_read(Port *port, void *ptr, size_t len, int *waitfor)
+{
+       ssize_t         n;
+
+       n = gnutls_record_recv(port->ssl, ptr, len);
+
+       if (n > 0)
+               return n;
+
+       switch (n)
+       {
+               case 0:
+
+                       /*
+                        * the SSL connnection was closed, leave it to the 
caller to
+                        * ereport it
+                        */
+                       errno = ECONNRESET;
+                       n = -1;
+                       break;
+               case GNUTLS_E_AGAIN:
+               case GNUTLS_E_INTERRUPTED:
+                       *waitfor = WL_SOCKET_READABLE;
+                       errno = EWOULDBLOCK;
+                       n = -1;
+                       break;
+               default:
+                       ereport(COMMERROR,
+                                       (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                        errmsg("SSL error: %s",
+                                                       gnutls_strerror(n))));
+                       errno = ECONNRESET;
+                       n = -1;
+                       break;
+       }
+
+       return n;
+}
+
+ssize_t
+be_tls_write(Port *port, void *ptr, size_t len, int *waitfor)
+{
+       ssize_t         n;
+
+       n = gnutls_record_send(port->ssl, ptr, len);
+
+       if (n >= 0)
+               return n;
+
+       switch (n)
+       {
+               case GNUTLS_E_AGAIN:
+               case GNUTLS_E_INTERRUPTED:
+                       *waitfor = WL_SOCKET_WRITEABLE;
+                       errno = EWOULDBLOCK;
+                       n = -1;
+                       break;
+               default:
+                       ereport(COMMERROR,
+                                       (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                        errmsg("SSL error: %s",
+                                                       gnutls_strerror(n))));
+                       errno = ECONNRESET;
+                       n = -1;
+                       break;
+       }
+
+       return n;
+}
+
+/* ------------------------------------------------------------ */
+/*                                             Internal functions              
                                */
+/* ------------------------------------------------------------ */
+
+/*
+ * Private substitute transport layer: this does the sending and receiving
+ * using send() and recv() instead. This is so that we can enable and disable
+ * interrupts just while calling recv(). We cannot have interrupts occurring
+ * while the bulk of GnuTLS runs, because it uses malloc() and possibly other
+ * non-reentrant libc facilities. We also need to call send() and recv()
+ * directly so it gets passed through the socket/signals layer on Win32.
+ */
+
+static ssize_t
+my_sock_read(gnutls_transport_ptr_t port, void *buf, size_t size)
+{
+       return secure_raw_read((Port *) port, buf, size);
+}
+
+static ssize_t
+my_sock_write(gnutls_transport_ptr_t port, const void *buf, size_t size)
+{
+       return secure_raw_write((Port *) port, buf, size);
+}
+
+#if !HAVE_DECL_GNUTLS_X509_CRT_LIST_SORT
+/*
+ * GnuTLS versions before 3.4.0 do not support sorting incorrectly sorted
+ * certificate chains, so we skip doing so in these earlier versions.
+ */
+#define GNUTLS_X509_CRT_LIST_SORT 0
+#endif
+
+/*
+ *     Get peer certificate from a session
+ *
+ *     Returns GNUTLS_E_NO_CERTIFICATE_FOUND when not x509 certifcate was 
found.
+ */
+static int
+get_peer_certificate(gnutls_session_t ssl, gnutls_x509_crt_t *peer)
+{
+       if (gnutls_certificate_type_get(ssl) == GNUTLS_CRT_X509)
+       {
+               unsigned int n;
+               int                     ret;
+               gnutls_datum_t const *raw_certs;
+               gnutls_x509_crt_t *certs;
+
+               raw_certs = gnutls_certificate_get_peers(ssl, &n);
+
+               if (n == 0)
+                       return GNUTLS_E_NO_CERTIFICATE_FOUND;
+
+               certs = palloc(n * sizeof(gnutls_x509_crt_t));
+
+               ret = gnutls_x509_crt_list_import(certs, &n, raw_certs,
+                                                                               
  GNUTLS_X509_FMT_DER,
+                                                                               
  GNUTLS_X509_CRT_LIST_SORT);
+
+               if (ret >= 1)
+               {
+                       unsigned int i;
+
+                       for (i = 1; i < ret; i++)
+                               gnutls_x509_crt_deinit(certs[i]);
+
+                       *peer = certs[0];
+
+                       ret = GNUTLS_E_SUCCESS;
+               }
+               else if (ret == 0)
+                       ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
+
+               pfree(certs);
+
+               return ret;
+       }
+
+       return GNUTLS_E_NO_CERTIFICATE_FOUND;
+}
+
+#define MAX_DH_FILE_SIZE 10240
+
+/*
+ *     Load precomputed DH parameters.
+ *
+ *     To prevent "downgrade" attacks, we perform a number of checks
+ *     to verify that the DBA-generated DH parameters file contains
+ *     what we expect it to contain.
+ */
+static bool
+load_dh_file(gnutls_dh_params_t dh_params, char *filename, bool isServerStart)
+{
+       FILE       *fp;
+       char            buffer[MAX_DH_FILE_SIZE];
+       gnutls_datum_t datum = {(unsigned char *) buffer};
+       int                     ret;
+
+       /* attempt to open file.  It's not an error if it doesn't exist. */
+       if ((fp = AllocateFile(filename, "r")) == NULL)
+       {
+               ereport(isServerStart ? FATAL : LOG,
+                               (errcode_for_file_access(),
+                                errmsg("could not open DH parameters file 
\"%s\": %m",
+                                               filename)));
+               return false;
+       }
+
+       datum.size = fread(buffer, sizeof(buffer[0]), sizeof(buffer), fp);
+
+       FreeFile(fp);
+
+       if (datum.size < 0)
+       {
+               ereport(isServerStart ? FATAL : LOG,
+                               (errcode_for_file_access(),
+                                errmsg("could not load DH parameters file: %s",
+                                               gnutls_strerror(ret))));
+               return false;
+       }
+
+       ret = gnutls_dh_params_import_pkcs3(dh_params, &datum, 
GNUTLS_X509_FMT_PEM);
+
+       if (ret < 0)
+       {
+               ereport(isServerStart ? FATAL : LOG,
+                               (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                                errmsg("could not load DH parameters file: %s",
+                                               gnutls_strerror(ret))));
+               return false;
+       }
+
+       return true;
+}
+
+/*
+ *     Load hardcoded DH parameters.
+ *
+ *     To prevent problems if the DH parameters files don't even
+ *     exist, we can load DH parameters hardcoded into this file.
+ */
+static bool
+load_dh_buffer(gnutls_dh_params_t dh_params, const char *buffer, size_t len, 
bool isServerStart)
+{
+       gnutls_datum_t datum = {(unsigned char *) buffer, len};
+       int                     ret;
+
+       ret = gnutls_dh_params_import_pkcs3(dh_params, &datum, 
GNUTLS_X509_FMT_PEM);
+
+       if (ret < 0)
+       {
+               ereport(isServerStart ? FATAL : LOG,
+                               (errmsg_internal("DH load buffer: %s", 
gnutls_strerror(ret))));
+               return false;
+       }
+
+       return true;
+}
+
+#ifdef HAVE_GNUTLS_PKCS11_SET_PIN_FUNCTION
+/*
+ * PIN callback
+ */
+static int
+pin_function(void *userdata, int attempt,
+                        const char *token_url,
+                        const char *token_label,
+                        unsigned int flags,
+                        char *pin, size_t pin_max)
+{
+       const char *prompt = token_url;
+
+       if (ssl_passphrase_command[0])
+               run_ssl_passphrase_command(prompt, ssl_is_server_start, pin, 
pin_max);
+       else
+               simple_prompt(prompt, pin, pin_max, false);
+
+       return 0;
+}
+
+/*
+ * Dummy PIN callback during server reload
+ *
+ * The standard callback is no good during a postmaster SIGHUP cycle, not to
+ * mention SSL context reload in an EXEC_BACKEND postmaster child.  So
+ * override it with this dummy function that just returns an error,
+ * guaranteeing failure.
+ */
+static int
+dummy_pin_function(void *userdata, int attempt,
+                                  const char *token_url,
+                                  const char *token_label,
+                                  unsigned int flags,
+                                  char *pin, size_t pin_max)
+{
+       /* Set flag to change the error message we'll report */
+       pin_function_called = true;
+       return -1;
+}
+#endif
+
+/*
+ *     Certificate verification callback
+ *
+ *     This callback is where we verify the identity of the client.
+ */
+static int
+verify_cb(gnutls_session_t ssl)
+{
+       unsigned int status;
+       int                     ret;
+
+       ret = gnutls_certificate_verify_peers2(ssl, &status);
+
+       if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND)
+               return 0;
+       else if (ret < 0)
+               return ret;
+
+       return status;
+}
+
+/*
+ * Set DH parameters for generating ephemeral DH keys.  The
+ * DH parameters can take a long time to compute, so they must be
+ * precomputed.
+ *
+ * Since few sites will bother to create a parameter file, we also
+ * also provide a fallback to the parameters provided by the
+ * OpenSSL project.
+ *
+ * These values can be static (once loaded or computed) since the
+ * OpenSSL library can efficiently generate random keys from the
+ * information provided.
+ */
+static bool
+initialize_dh(gnutls_dh_params_t *dh_params, bool isServerStart)
+{
+       bool            loaded = false;
+       int                     ret;
+
+       ret = gnutls_dh_params_init(dh_params);
+       if (ret < 0)
+       {
+               ereport(isServerStart ? FATAL : LOG,
+                               (errmsg_internal("DH init error: %s",
+                                                                
gnutls_strerror(ret))));
+               return false;
+       }
+
+       if (ssl_dh_params_file[0])
+               loaded = load_dh_file(*dh_params, ssl_dh_params_file, 
isServerStart);
+       if (!loaded)
+               loaded = load_dh_buffer(*dh_params, FILE_DH2048, 
sizeof(FILE_DH2048), isServerStart);
+       if (!loaded)
+       {
+               ereport(isServerStart ? FATAL : LOG,
+                               (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                                (errmsg("DH: could not load DH parameters"))));
+               return false;
+       }
+
+       return true;
+}
+
+int
+be_tls_get_cipher_bits(Port *port)
+{
+       if (port->ssl)
+               return gnutls_cipher_get_key_size(gnutls_cipher_get(port->ssl)) 
* 8;
+       else
+               return 0;
+}
+
+bool
+be_tls_get_compression(Port *port)
+{
+       if (port->ssl)
+       {
+               gnutls_compression_method_t comp = 
gnutls_compression_get(port->ssl);
+
+               return comp != GNUTLS_COMP_UNKNOWN && comp != GNUTLS_COMP_NULL;
+       }
+       else
+               return false;
+}
+
+const char *
+be_tls_get_version(Port *port)
+{
+       if (port->ssl)
+               return 
gnutls_protocol_get_name(gnutls_protocol_get_version(port->ssl));
+       else
+               return NULL;
+}
+
+const char *
+be_tls_get_cipher(Port *port)
+{
+       if (port->ssl)
+               return gnutls_cipher_get_name(gnutls_cipher_get(port->ssl));
+       else
+               return NULL;
+}
+
+void
+be_tls_get_peerdn_name(Port *port, char *ptr, size_t len)
+{
+       if (port->peer)
+       {
+               int                     ret;
+
+               ret = gnutls_x509_crt_get_dn_by_oid(port->peer,
+                                                                               
        GNUTLS_OID_X520_COMMON_NAME,
+                                                                               
        0, 0, ptr, &len);
+
+               if (ret != 0)
+                       ptr[0] = '\0';
+       }
+       else
+               ptr[0] = '\0';
+}
diff --git a/src/backend/libpq/be-secure-openssl.c 
b/src/backend/libpq/be-secure-openssl.c
index 1b659a5870..5fd58a2f38 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -229,10 +229,8 @@ be_tls_init(bool isServerStart)
                }
        }
 
-       /*----------
+       /*
         * Load the Certificate Revocation List (CRL).
-        * 
http://searchsecurity.techtarget.com/sDefinition/0,,sid14_gci803160,00.html
-        *----------
         */
        if (ssl_crl_file[0])
        {
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index d349d7c2c7..6a4aa32e74 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -60,6 +60,9 @@ char     *SSLECDHCurve;
 /* GUC variable: if false, prefer client ciphers */
 bool           SSLPreferServerCiphers;
 
+/* GUC variable controlling GnuTLS priorities */
+char      *gnutls_priority;
+
 /* ------------------------------------------------------------ */
 /*                      Procedures common to all secure sessions               
        */
 /* ------------------------------------------------------------ */
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 1a65ec87bd..f34559dc7d 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -1016,7 +1016,7 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
                        ereport(elevel,
                                        (errcode(ERRCODE_CONFIG_FILE_ERROR),
                                         errmsg("hostssl record cannot match 
because SSL is not supported by this build"),
-                                        errhint("Compile with --with-openssl 
to use SSL connections."),
+                                        errhint("Compile with --with-gnutls or 
--with-openssl to use SSL connections."),
                                         errcontext("line %d of configuration 
file \"%s\"",
                                                                line_num, 
HbaFileName)));
                        *err_msg = "hostssl record cannot match because SSL is 
not supported by this build";
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 0625eff219..567392398f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -3731,7 +3731,13 @@ static struct config_string ConfigureNamesString[] =
                },
                &ssl_library,
 #ifdef USE_SSL
+#if defined(USE_OPENSSL)
                "OpenSSL",
+#elif defined(USE_GNUTLS)
+               "GnuTLS",
+#else
+#error SSL implementation must set ssl_library string
+#endif
 #else
                "",
 #endif
@@ -3840,6 +3846,25 @@ static struct config_string ConfigureNamesString[] =
                NULL, NULL, NULL
        },
 
+       {
+               {"gnutls_priority", PGC_SIGHUP, CONN_AUTH_SSL,
+                       gettext_noop("Sets priorities for the cipher suites 
supported by GnuTLS."),
+                       NULL,
+                       GUC_SUPERUSER_ONLY
+               },
+               &gnutls_priority,
+#ifdef USE_SSL
+#if HAVE_DECL_GNUTLS_ALPN_SERVER_PRECEDENCE
+               "NORMAL:%SERVER_PRECEDENCE",
+#else
+               "NORMAL",
+#endif
+#else
+               "none",
+#endif
+               NULL, NULL, NULL
+       },
+
        {
                {"ssl_dh_params_file", PGC_SIGHUP, CONN_AUTH_SSL,
                        gettext_noop("Location of the SSL DH parameters file."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample 
b/src/backend/utils/misc/postgresql.conf.sample
index 7486d20a34..ce0de5d362 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -100,13 +100,18 @@
 #ssl_cert_file = 'server.crt'
 #ssl_crl_file = ''
 #ssl_key_file = 'server.key'
-#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
-#ssl_prefer_server_ciphers = on
-#ssl_ecdh_curve = 'prime256v1'
 #ssl_dh_params_file = ''
 #ssl_passphrase_command = ''
 #ssl_passphrase_command_supports_reload = off
 
+# Parameters for OpenSSL.  Leave these commented out if not using OpenSSL.
+#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
+#ssl_prefer_server_ciphers = on
+#ssl_ecdh_curve = 'prime256v1'
+
+# Parameters for GnuTLS.  Leave these commented out if not using GnuTLS.
+#gnutls_priority = 'NORMAL:%SERVER_PRECEDENCE'
+
 
 #------------------------------------------------------------------------------
 # RESOURCE USAGE (except WAL)
diff --git a/src/common/Makefile b/src/common/Makefile
index 1fc2c66225..6abe10f0d5 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -45,7 +45,9 @@ OBJS_COMMON = base64.o config_info.o controldata_utils.o 
exec.o file_perm.o \
        rmtree.o saslprep.o scram-common.o string.o unicode_norm.o \
        username.o wait_error.o
 
-ifeq ($(with_openssl),yes)
+ifeq ($(with_gnutls),yes)
+OBJS_COMMON += sha2_gnutls.o
+else ifeq ($(with_openssl),yes)
 OBJS_COMMON += sha2_openssl.o
 else
 OBJS_COMMON += sha2.o
diff --git a/src/common/sha2_gnutls.c b/src/common/sha2_gnutls.c
new file mode 100644
index 0000000000..279b5370fa
--- /dev/null
+++ b/src/common/sha2_gnutls.c
@@ -0,0 +1,99 @@
+/*-------------------------------------------------------------------------
+ *
+ * sha2_gnutlsl.c
+ *       Set of wrapper routines on top of GnuTLS to support SHA-224
+ *       SHA-256, SHA-384 and SHA-512 functions.
+ *
+ * This should only be used if code is compiled with GnuTLS support.
+ *
+ * Portions Copyright (c) 2017, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *               src/common/sha2_gnutls.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include "common/sha2.h"
+
+/* Interface routines for SHA-256 */
+void
+pg_sha256_init(pg_sha256_ctx *ctx)
+{
+       gnutls_hash_init(ctx, GNUTLS_DIG_SHA256);
+}
+
+void
+pg_sha256_update(pg_sha256_ctx *ctx, const uint8 *data, size_t len)
+{
+       gnutls_hash(*ctx, data, len);
+}
+
+void
+pg_sha256_final(pg_sha256_ctx *ctx, uint8 *dest)
+{
+       gnutls_hash_deinit(*ctx, dest);
+}
+
+/* Interface routines for SHA-512 */
+void
+pg_sha512_init(pg_sha512_ctx *ctx)
+{
+       gnutls_hash_init(ctx, GNUTLS_DIG_SHA512);
+}
+
+void
+pg_sha512_update(pg_sha512_ctx *ctx, const uint8 *data, size_t len)
+{
+       gnutls_hash(*ctx, data, len);
+}
+
+void
+pg_sha512_final(pg_sha512_ctx *ctx, uint8 *dest)
+{
+       gnutls_hash_deinit(*ctx, dest);
+}
+
+/* Interface routines for SHA-384 */
+void
+pg_sha384_init(pg_sha384_ctx *ctx)
+{
+       gnutls_hash_init(ctx, GNUTLS_DIG_SHA384);
+}
+
+void
+pg_sha384_update(pg_sha384_ctx *ctx, const uint8 *data, size_t len)
+{
+       gnutls_hash(*ctx, data, len);
+}
+
+void
+pg_sha384_final(pg_sha384_ctx *ctx, uint8 *dest)
+{
+       gnutls_hash_deinit(*ctx, dest);
+}
+
+/* Interface routines for SHA-224 */
+void
+pg_sha224_init(pg_sha224_ctx *ctx)
+{
+       gnutls_hash_init(ctx, GNUTLS_DIG_SHA224);
+}
+
+void
+pg_sha224_update(pg_sha224_ctx *ctx, const uint8 *data, size_t len)
+{
+       gnutls_hash(*ctx, data, len);
+}
+
+void
+pg_sha224_final(pg_sha224_ctx *ctx, uint8 *dest)
+{
+       gnutls_hash_deinit(*ctx, dest);
+}
diff --git a/src/include/common/sha2.h b/src/include/common/sha2.h
index f3fd0d0d28..b064554a3e 100644
--- a/src/include/common/sha2.h
+++ b/src/include/common/sha2.h
@@ -50,8 +50,11 @@
 #ifndef _PG_SHA2_H_
 #define _PG_SHA2_H_
 
-#ifdef USE_SSL
+#if defined(USE_OPENSSL)
 #include <openssl/sha.h>
+#elif defined(USE_GNUTLS)
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
 #endif
 
 /*** SHA224/256/384/512 Various Length Definitions ***********************/
@@ -69,11 +72,16 @@
 #define PG_SHA512_DIGEST_STRING_LENGTH (PG_SHA512_DIGEST_LENGTH * 2 + 1)
 
 /* Context Structures for SHA-1/224/256/384/512 */
-#ifdef USE_SSL
+#if defined(USE_OPENSSL)
 typedef SHA256_CTX pg_sha256_ctx;
 typedef SHA512_CTX pg_sha512_ctx;
 typedef SHA256_CTX pg_sha224_ctx;
 typedef SHA512_CTX pg_sha384_ctx;
+#elif defined(USE_GNUTLS)
+typedef gnutls_hash_hd_t pg_sha256_ctx;
+typedef gnutls_hash_hd_t pg_sha512_ctx;
+typedef gnutls_hash_hd_t pg_sha224_ctx;
+typedef gnutls_hash_hd_t pg_sha384_ctx;
 #else
 typedef struct pg_sha256_ctx
 {
@@ -89,7 +97,7 @@ typedef struct pg_sha512_ctx
 } pg_sha512_ctx;
 typedef struct pg_sha256_ctx pg_sha224_ctx;
 typedef struct pg_sha512_ctx pg_sha384_ctx;
-#endif                                                 /* USE_SSL */
+#endif
 
 /* Interface routines for SHA224/256/384/512 */
 extern void pg_sha224_init(pg_sha224_ctx *ctx);
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index ef5528c897..fe36a062c0 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -19,9 +19,11 @@
 #define LIBPQ_BE_H
 
 #include <sys/time.h>
-#ifdef USE_OPENSSL
+#if defined(USE_OPENSSL)
 #include <openssl/ssl.h>
 #include <openssl/err.h>
+#elif defined(USE_GNUTLS)
+#include <gnutls/gnutls.h>
 #endif
 #ifdef HAVE_NETINET_TCP_H
 #include <netinet/tcp.h>
@@ -183,12 +185,15 @@ typedef struct Port
        bool            peer_cert_valid;
 
        /*
-        * OpenSSL structures. (Keep these last so that the locations of other
-        * fields are the same whether or not you build with OpenSSL.)
+        * SSL library specific structures. (Keep these last so that the 
locations
+        * of other fields are the same whether or not you build with SSL.)
         */
-#ifdef USE_OPENSSL
+#if defined(USE_OPENSSL)
        SSL                *ssl;
        X509       *peer;
+#elif defined(USE_GNUTLS)
+       gnutls_session_t ssl;
+       gnutls_x509_crt_t peer;
 #endif
 } Port;
 
@@ -275,7 +280,7 @@ extern void be_tls_get_peerdn_name(Port *port, char *ptr, 
size_t len);
 extern char *be_tls_get_certificate_hash(Port *port, size_t *len);
 #endif
 
-#endif /* USE_SSL */
+#endif                                                 /* USE_SSL */
 
 extern ProtocolVersion FrontendProtocol;
 
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index 36baf6b919..4cf67523f5 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -102,6 +102,7 @@ extern WaitEventSet *FeBeWaitSet;
 extern char *SSLCipherSuites;
 extern char *SSLECDHCurve;
 extern bool SSLPreferServerCiphers;
+extern char *gnutls_priority;
 
 /*
  * prototypes for functions in be-secure-common.c
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 347d5b56dc..b508ab0959 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -134,6 +134,14 @@
    don't. */
 #undef HAVE_DECL_F_FULLFSYNC
 
+/* Define to 1 if you have the declaration of `GNUTLS_ALPN_SERVER_PRECEDENCE',
+   and to 0 if you don't. */
+#undef HAVE_DECL_GNUTLS_ALPN_SERVER_PRECEDENCE
+
+/* Define to 1 if you have the declaration of `GNUTLS_X509_CRT_LIST_SORT', and
+   to 0 if you don't. */
+#undef HAVE_DECL_GNUTLS_X509_CRT_LIST_SORT
+
 /* Define to 1 if you have the declaration of
    `LLVMCreateGDBRegistrationListener', and to 0 if you don't. */
 #undef HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER
@@ -282,6 +290,9 @@
 /* Define to 1 if you have the `gettimeofday' function. */
 #undef HAVE_GETTIMEOFDAY
 
+/* Define to 1 if you have the `gnutls_pkcs11_set_pin_function' function. */
+#undef HAVE_GNUTLS_PKCS11_SET_PIN_FUNCTION
+
 /* Define to 1 if you have the <gssapi/gssapi.h> header file. */
 #undef HAVE_GSSAPI_GSSAPI_H
 
@@ -890,6 +901,12 @@
    (--enable-float8-byval) */
 #undef USE_FLOAT8_BYVAL
 
+/* Define to build with GnuTLS support. (--with-gnutls) */
+#undef USE_GNUTLS
+
+/* Define to use GnuTLS for random number generation */
+#undef USE_GNUTLS_RANDOM
+
 /* Define to build with ICU support. (--with-icu) */
 #undef USE_ICU
 
diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h
index b309395f11..e2ff2ce693 100644
--- a/src/include/pg_config_manual.h
+++ b/src/include/pg_config_manual.h
@@ -165,7 +165,7 @@
  * implementation.  (Currently, only OpenSSL is supported, but we might add
  * more implementations in the future.)
  */
-#ifdef USE_OPENSSL
+#if defined(USE_OPENSSL) || defined(USE_GNUTLS)
 #define USE_SSL
 #endif
 
diff --git a/src/interfaces/libpq/.gitignore b/src/interfaces/libpq/.gitignore
index 5c232ae2d1..371800f0c7 100644
--- a/src/interfaces/libpq/.gitignore
+++ b/src/interfaces/libpq/.gitignore
@@ -27,6 +27,7 @@
 /base64.c
 /scram-common.c
 /sha2.c
+/sha2_gnutls.c
 /sha2_openssl.c
 /saslprep.c
 /unicode_norm.c
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index abe0a50e98..b5958daf1d 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -51,7 +51,9 @@ OBJS += encnames.o wchar.o
 # src/common
 OBJS += base64.o ip.o md5.o scram-common.o saslprep.o unicode_norm.o
 
-ifeq ($(with_openssl),yes)
+ifeq ($(with_gnutls),yes)
+OBJS += fe-secure-gnutls.o fe-secure-common.o sha2_gnutls.o
+else ifeq ($(with_openssl),yes)
 OBJS += fe-secure-openssl.o fe-secure-common.o sha2_openssl.o
 else
 OBJS += sha2.o
@@ -78,12 +80,12 @@ endif
 # shared library link.  (The order in which you list them here doesn't
 # matter.)
 ifneq ($(PORTNAME), win32)
-SHLIB_LINK += $(filter -lcrypt -ldes -lcom_err -lcrypto -lk5crypto -lkrb5 
-lgssapi_krb5 -lgss -lgssapi -lssl -lsocket -lnsl -lresolv -lintl, $(LIBS)) 
$(LDAP_LIBS_FE) $(PTHREAD_LIBS)
+SHLIB_LINK += $(filter -lcrypt -ldes -lcom_err -lcrypto -lk5crypto -lkrb5 
-lgssapi_krb5 -lgss -lgssapi -lssl -lgnutls -lsocket -lnsl -lresolv -lintl, 
$(LIBS)) $(LDAP_LIBS_FE) $(PTHREAD_LIBS)
 else
-SHLIB_LINK += $(filter -lcrypt -ldes -lcom_err -lcrypto -lk5crypto -lkrb5 
-lgssapi32 -lssl -lsocket -lnsl -lresolv -lintl $(PTHREAD_LIBS), $(LIBS)) 
$(LDAP_LIBS_FE)
+SHLIB_LINK += $(filter -lcrypt -ldes -lcom_err -lcrypto -lk5crypto -lkrb5 
-lgssapi32 -lssl -lgnutls -lsocket -lnsl -lresolv -lintl $(PTHREAD_LIBS), 
$(LIBS)) $(LDAP_LIBS_FE)
 endif
 ifeq ($(PORTNAME), win32)
-SHLIB_LINK += -lshell32 -lws2_32 -lsecur32 $(filter -leay32 -lssleay32 
-lcomerr32 -lkrb5_32, $(LIBS))
+SHLIB_LINK += -lshell32 -lws2_32 -lsecur32 $(filter -leay32 -lssleay32 
-lgnutls -lcomerr32 -lkrb5_32, $(LIBS))
 endif
 
 SHLIB_EXPORTS = exports.txt
@@ -106,7 +108,7 @@ backend_src = $(top_srcdir)/src/backend
 chklocale.c crypt.c erand48.c getaddrinfo.c getpeereid.c inet_aton.c 
inet_net_ntop.c noblock.c open.c system.c pgsleep.c pg_strong_random.c 
pgstrcasecmp.c pqsignal.c snprintf.c strerror.c strlcpy.c strnlen.c thread.c 
win32error.c win32setlocale.c: % : $(top_srcdir)/src/port/%
        rm -f $@ && $(LN_S) $< .
 
-ip.c md5.c base64.c scram-common.c sha2.c sha2_openssl.c saslprep.c 
unicode_norm.c: % : $(top_srcdir)/src/common/%
+ip.c md5.c base64.c scram-common.c sha2.c sha2_openssl.c sha2_gnutls.c 
saslprep.c unicode_norm.c: % : $(top_srcdir)/src/common/%
        rm -f $@ && $(LN_S) $< .
 
 encnames.c wchar.c: % : $(backend_src)/utils/mb/%
@@ -156,7 +158,7 @@ clean distclean: clean-lib
        rm -f pg_config_paths.h
 # Remove files we (may have) symlinked in from src/port and other places
        rm -f chklocale.c crypt.c erand48.c getaddrinfo.c getpeereid.c 
inet_aton.c inet_net_ntop.c noblock.c open.c system.c pgsleep.c 
pg_strong_random.c pgstrcasecmp.c pqsignal.c snprintf.c strerror.c strlcpy.c 
strnlen.c thread.c win32error.c win32setlocale.c
-       rm -f ip.c md5.c base64.c scram-common.c sha2.c sha2_openssl.c 
saslprep.c unicode_norm.c
+       rm -f ip.c md5.c base64.c scram-common.c sha2.c sha2_openssl.c 
sha2_gnutls.c saslprep.c unicode_norm.c
        rm -f encnames.c wchar.c
 
 maintainer-clean: distclean maintainer-clean-lib
diff --git a/src/interfaces/libpq/fe-secure-gnutls.c 
b/src/interfaces/libpq/fe-secure-gnutls.c
new file mode 100644
index 0000000000..99ee53d067
--- /dev/null
+++ b/src/interfaces/libpq/fe-secure-gnutls.c
@@ -0,0 +1,803 @@
+/*-------------------------------------------------------------------------
+ *
+ * fe-secure-gnutls.c
+ *       GnuTLS support
+ *
+ *
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *       src/interfaces/libpq/fe-secure-gnutls.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres_fe.h"
+#include "fe-secure-common.h"
+#include "libpq-int.h"
+
+#include <sys/stat.h>
+
+#ifdef ENABLE_THREAD_SAFETY
+#ifdef WIN32
+#include "pthread-win32.h"
+#else
+#include <pthread.h>
+#endif
+#endif
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+static int     initialize_SSL(PGconn *conn);
+static PostgresPollingStatusType open_client_SSL(PGconn *);
+
+static ssize_t my_sock_read(gnutls_transport_ptr_t h, void *buf, size_t size);
+static ssize_t my_sock_write(gnutls_transport_ptr_t h, const void *buf, size_t 
size);
+static int     get_peer_certificate(gnutls_session_t ssl, gnutls_x509_crt_t 
*peer);
+static int     verify_cb(gnutls_session_t ssl);
+
+static bool ssl_lib_initialized = false;
+
+#ifdef ENABLE_THREAD_SAFETY
+#ifndef WIN32
+static pthread_mutex_t ssl_config_mutex = PTHREAD_MUTEX_INITIALIZER;
+#else
+static pthread_mutex_t ssl_config_mutex = NULL;
+static long win32_ssl_create_mutex = 0;
+#endif
+#endif                                                 /* ENABLE_THREAD_SAFETY 
*/
+
+
+/* ------------------------------------------------------------ */
+/*                      Procedures common to all secure sessions               
        */
+/* ------------------------------------------------------------ */
+
+void
+pgtls_init_library(bool do_ssl, int do_crypto)
+{
+       /* not used with GnuTLS */
+}
+
+PostgresPollingStatusType
+pgtls_open_client(PGconn *conn)
+{
+       /* First time through? */
+       if (conn->ssl == NULL)
+       {
+               /*
+                * Create a connection-specific SSL object, and load client
+                * certificate, private key, and trusted CA certs.
+                */
+               if (initialize_SSL(conn) != 0)
+               {
+                       /* initialize_SSL already put a message in 
conn->errorMessage */
+                       pgtls_close(conn);
+                       return PGRES_POLLING_FAILED;
+               }
+       }
+
+       /* Begin or continue the actual handshake */
+       return open_client_SSL(conn);
+}
+
+ssize_t
+pgtls_read(PGconn *conn, void *ptr, size_t len)
+{
+       ssize_t         n;
+       int                     result_errno;
+       char            sebuf[256];
+
+       n = gnutls_record_recv(conn->ssl, ptr, len);
+
+       if (n > 0)
+       {
+               SOCK_ERRNO_SET(0);
+               return n;
+       }
+
+       switch (n)
+       {
+               case 0:
+                       printfPQExpBuffer(&conn->errorMessage,
+                                                         libpq_gettext("SSL 
connection has been closed unexpectedly\n"));
+                       result_errno = ECONNRESET;
+                       n = -1;
+                       break;
+               case GNUTLS_E_REHANDSHAKE:
+                       /* Ignore re-handsake requests and have the caller 
retry */
+               case GNUTLS_E_INTERRUPTED:
+                       result_errno = EINTR;
+                       n = -1;
+                       break;
+               case GNUTLS_E_AGAIN:
+                       result_errno = EAGAIN;
+                       n = -1;
+                       break;
+#ifdef GNUTLS_E_PREMATURE_TERMINATION
+               case GNUTLS_E_PREMATURE_TERMINATION:
+#endif
+               case GNUTLS_E_PUSH_ERROR:
+                       result_errno = SOCK_ERRNO;
+                       n = -1;
+                       if (result_errno == EPIPE || result_errno == ECONNRESET)
+                               printfPQExpBuffer(&conn->errorMessage,
+                                                                 libpq_gettext(
+                                                                               
                "server closed the connection unexpectedly\n"
+                                                                               
                "\tThis probably means the server terminated abnormally\n"
+                                                                               
                "\tbefore or while processing the request.\n"));
+                       else
+                               printfPQExpBuffer(&conn->errorMessage,
+                                                                 
libpq_gettext("SSL SYSCALL error: %s\n"),
+                                                                 
SOCK_STRERROR(result_errno,
+                                                                               
                sebuf, sizeof(sebuf)));
+                       break;
+               default:
+                       printfPQExpBuffer(&conn->errorMessage,
+                                                         libpq_gettext("SSL 
error: %s\n"),
+                                                         gnutls_strerror(n));
+                       /* assume the connection is broken */
+                       result_errno = ECONNRESET;
+                       n = -1;
+                       break;
+       }
+
+       /* ensure we return the intended errno to caller */
+       SOCK_ERRNO_SET(result_errno);
+
+       return n;
+}
+
+bool
+pgtls_read_pending(PGconn *conn)
+{
+       return gnutls_record_check_pending(conn->ssl);
+}
+
+ssize_t
+pgtls_write(PGconn *conn, const void *ptr, size_t len)
+{
+       ssize_t         n;
+       int                     result_errno;
+       char            sebuf[256];
+
+       n = gnutls_record_send(conn->ssl, ptr, len);
+
+       if (n >= 0)
+       {
+               SOCK_ERRNO_SET(0);
+               return n;
+       }
+
+       switch (n)
+       {
+               case GNUTLS_E_INTERRUPTED:
+                       result_errno = EINTR;
+                       n = -1;
+                       break;
+               case GNUTLS_E_AGAIN:
+                       result_errno = EAGAIN;
+                       n = -1;
+                       break;
+#ifdef GNUTLS_E_PREMATURE_TERMINATION
+               case GNUTLS_E_PREMATURE_TERMINATION:
+#endif
+               case GNUTLS_E_PUSH_ERROR:
+                       result_errno = SOCK_ERRNO;
+                       n = -1;
+                       if (result_errno == EPIPE || result_errno == ECONNRESET)
+                               printfPQExpBuffer(&conn->errorMessage,
+                                                                 libpq_gettext(
+                                                                               
                "server closed the connection unexpectedly\n"
+                                                                               
                "\tThis probably means the server terminated abnormally\n"
+                                                                               
                "\tbefore or while processing the request.\n"));
+                       else
+                               printfPQExpBuffer(&conn->errorMessage,
+                                                                 
libpq_gettext("SSL SYSCALL error: %s\n"),
+                                                                 
SOCK_STRERROR(result_errno,
+                                                                               
                sebuf, sizeof(sebuf)));
+                       break;
+               default:
+                       printfPQExpBuffer(&conn->errorMessage,
+                                                         libpq_gettext("SSL 
error: %s\n"),
+                                                         gnutls_strerror(n));
+                       /* assume the connection is broken */
+                       result_errno = ECONNRESET;
+                       n = -1;
+                       break;
+       }
+
+       /* ensure we return the intended errno to caller */
+       SOCK_ERRNO_SET(result_errno);
+
+       return n;
+}
+
+/* ------------------------------------------------------------ */
+/*                                             GnuTLS specific code            
                        */
+/* ------------------------------------------------------------ */
+
+
+
+#define MAX_CN 256
+
+/*
+ * Verify that the server certificate matches the hostname we connected to.
+ *
+ * The certificate's Common Name and Subject Alternative Names are considered.
+ */
+int
+pgtls_verify_peer_name_matches_certificate_guts(PGconn *conn,
+                                                                               
                int *names_examined,
+                                                                               
                char **first_name)
+{
+       char            namedata[MAX_CN];
+       size_t          namelen;
+       int                     i;
+       int                     ret;
+       int                     rc = 0;
+
+       /*
+        * First, get the Subject Alternative Names (SANs) from the certificate,
+        * and compare them against the originally given hostname.
+        */
+       for (i = 0;; i++)
+       {
+               namelen = sizeof(namedata);
+               ret = gnutls_x509_crt_get_subject_alt_name(conn->peer, i,
+                                                                               
                   namedata,
+                                                                               
                   &namelen,
+                                                                               
                   NULL);
+
+               if (ret < 0)
+                       break;
+
+               if (ret == GNUTLS_SAN_DNSNAME)
+               {
+                       char       *alt_name = NULL;
+
+                       (*names_examined)++;
+
+                       rc = pq_verify_peer_name_matches_certificate_name(conn, 
namedata, namelen, &alt_name);
+
+                       if (alt_name)
+                       {
+                               if (!*first_name)
+                                       *first_name = alt_name;
+                               else
+                                       free(alt_name);
+                       }
+               }
+
+               if (rc != 0)
+                       break;
+       }
+
+       /*
+        * If there is no subjectAltName extension of type dNSName, check the
+        * Common Name.
+        *
+        * (Per RFC 2818 and RFC 6125, if the subjectAltName extension of type
+        * dNSName is present, the CN must be ignored.)
+        */
+       if (*names_examined == 0)
+       {
+               namelen = sizeof(namedata);
+               ret = gnutls_x509_crt_get_dn_by_oid(conn->peer, 
GNUTLS_OID_X520_COMMON_NAME, 0, 0, namedata, &namelen);
+
+               if (ret >= 0)
+               {
+                       (*names_examined)++;
+                       rc = pq_verify_peer_name_matches_certificate_name(conn, 
namedata, namelen, first_name);
+               }
+       }
+
+       return rc;
+}
+
+/*
+ * Initialize SSL library.
+ *
+ * In threadsafe mode, this includes setting up libcrypto callback functions
+ * to do thread locking.
+ */
+int
+pgtls_init(PGconn *conn)
+{
+#ifdef ENABLE_THREAD_SAFETY
+#ifdef WIN32
+       /* Also see similar code in fe-connect.c, default_threadlock() */
+       if (ssl_config_mutex == NULL)
+       {
+               while (InterlockedExchange(&win32_ssl_create_mutex, 1) == 1)
+                        /* loop, another thread own the lock */ ;
+               if (ssl_config_mutex == NULL)
+               {
+                       if (pthread_mutex_init(&ssl_config_mutex, NULL))
+                               return -1;
+               }
+               InterlockedExchange(&win32_ssl_create_mutex, 0);
+       }
+#endif
+       if (pthread_mutex_lock(&ssl_config_mutex))
+               return -1;
+#endif                                                 /* ENABLE_THREAD_SAFETY 
*/
+
+       if (!ssl_lib_initialized)
+       {
+               gnutls_global_init();
+               ssl_lib_initialized = true;
+       }
+
+#ifdef ENABLE_THREAD_SAFETY
+       pthread_mutex_unlock(&ssl_config_mutex);
+#endif
+       return 0;
+}
+
+/*
+ *     Create per-connection SSL object, and load the client certificate,
+ *     private key, and trusted CA certs.
+ *
+ *     Returns 0 if OK, -1 on failure (with a message in conn->errorMessage).
+ */
+static int
+initialize_SSL(PGconn *conn)
+{
+       gnutls_certificate_credentials_t creds;
+       int                     ret;
+       struct stat buf;
+       char            homedir[MAXPGPATH];
+       char            fnbuf[MAXPGPATH];
+       char            keybuf[MAXPGPATH];
+       char            sebuf[256];
+       bool            have_homedir;
+
+       /*
+        * We'll need the home directory if any of the relevant parameters are
+        * defaulted.  If pqGetHomeDirectory fails, act as though none of the
+        * files could be found.
+        */
+       if (!(conn->sslcert && strlen(conn->sslcert) > 0) ||
+               !(conn->sslkey && strlen(conn->sslkey) > 0) ||
+               !(conn->sslrootcert && strlen(conn->sslrootcert) > 0) ||
+               !(conn->sslcrl && strlen(conn->sslcrl) > 0))
+               have_homedir = pqGetHomeDirectory(homedir, sizeof(homedir));
+       else                                            /* won't need it */
+               have_homedir = false;
+
+       ret = gnutls_certificate_allocate_credentials(&creds);
+       if (ret < 0)
+       {
+               printfPQExpBuffer(&conn->errorMessage,
+                                                 libpq_gettext("could not 
create SSL credentials: %s\n"),
+                                                 gnutls_strerror(ret));
+               return -1;
+       }
+
+       /*
+        * If the root cert file exists, load it so we can perform certificate
+        * verification. If sslmode is "verify-full" we will also do further
+        * verification after the connection has been completed.
+        */
+       if (conn->sslrootcert && strlen(conn->sslrootcert) > 0)
+               strlcpy(fnbuf, conn->sslrootcert, sizeof(fnbuf));
+       else if (have_homedir)
+               snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, 
ROOT_CERT_FILE);
+       else
+               fnbuf[0] = '\0';
+
+       if (fnbuf[0] != '\0' &&
+               stat(fnbuf, &buf) == 0)
+       {
+               ret = gnutls_certificate_set_x509_trust_file(creds, fnbuf, 
GNUTLS_X509_FMT_PEM);
+               if (ret < 0)
+               {
+                       printfPQExpBuffer(&conn->errorMessage,
+                                                         libpq_gettext("could 
not read root certificate file \"%s\": %s\n"),
+                                                         fnbuf, 
gnutls_strerror(ret));
+                       gnutls_certificate_free_credentials(creds);
+                       return -1;
+               }
+
+               gnutls_certificate_set_verify_function(creds, verify_cb);
+
+               if (conn->sslcrl && strlen(conn->sslcrl) > 0)
+                       strlcpy(fnbuf, conn->sslcrl, sizeof(fnbuf));
+               else if (have_homedir)
+                       snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, 
ROOT_CRL_FILE);
+               else
+                       fnbuf[0] = '\0';
+
+               if (fnbuf[0] != '\0' && stat(fnbuf, &buf) == 0)
+               {
+                       ret = gnutls_certificate_set_x509_crl_file(creds, 
fnbuf, GNUTLS_X509_FMT_PEM);
+                       if (ret < 0)
+                       {
+                               printfPQExpBuffer(&conn->errorMessage,
+                                                                 
libpq_gettext("could not read crl file \"%s\": %s\n"),
+                                                                 fnbuf, 
gnutls_strerror(ret));
+                               gnutls_certificate_free_credentials(creds);
+                               return -1;
+                       }
+               }
+       }
+       else
+       {
+               /*
+                * stat() failed; assume root file doesn't exist.  If sslmode is
+                * verify-ca or verify-full, this is an error.  Otherwise, 
continue
+                * without performing any server cert verification.
+                */
+               if (conn->sslmode[0] == 'v')    /* "verify-ca" or "verify-full" 
*/
+               {
+                       /*
+                        * The only way to reach here with an empty filename is 
if
+                        * pqGetHomeDirectory failed.  That's a sufficiently 
unusual case
+                        * that it seems worth having a specialized error 
message for it.
+                        */
+                       if (fnbuf[0] == '\0')
+                               printfPQExpBuffer(&conn->errorMessage,
+                                                                 
libpq_gettext("could not get home directory to locate root certificate file\n"
+                                                                               
                "Either provide the file or change sslmode to disable server 
certificate verification.\n"));
+                       else
+                               printfPQExpBuffer(&conn->errorMessage,
+                                                                 
libpq_gettext("root certificate file \"%s\" does not exist\n"
+                                                                               
                "Either provide the file or change sslmode to disable server 
certificate verification.\n"), fnbuf);
+                       gnutls_certificate_free_credentials(creds);
+                       return -1;
+               }
+       }
+
+       /* Read the client certificate file */
+       if (conn->sslcert && strlen(conn->sslcert) > 0)
+               strlcpy(fnbuf, conn->sslcert, sizeof(fnbuf));
+       else if (have_homedir)
+               snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, 
USER_CERT_FILE);
+       else
+               fnbuf[0] = '\0';
+
+       if (fnbuf[0] == '\0')
+       {
+               /* no home directory, proceed without a client cert */
+       }
+       else if (stat(fnbuf, &buf) != 0)
+       {
+               /*
+                * If file is not present, just go on without a client cert; 
server
+                * might or might not accept the connection.  Any other error,
+                * however, is grounds for complaint.
+                */
+               if (errno != ENOENT && errno != ENOTDIR)
+               {
+                       printfPQExpBuffer(&conn->errorMessage,
+                                                         libpq_gettext("could 
not open certificate file \"%s\": %s\n"),
+                                                         fnbuf, 
pqStrerror(errno, sebuf, sizeof(sebuf)));
+                       gnutls_certificate_free_credentials(creds);
+                       return -1;
+               }
+       }
+       else
+       {
+               if (conn->sslkey && strlen(conn->sslkey) > 0)
+                       strlcpy(keybuf, conn->sslkey, sizeof(keybuf));
+               else if (have_homedir)
+                       snprintf(keybuf, sizeof(keybuf), "%s/%s", homedir, 
USER_KEY_FILE);
+               else
+                       keybuf[0] = '\0';
+
+               if (keybuf[0] != '\0')
+               {
+                       if (stat(keybuf, &buf) != 0)
+                       {
+                               printfPQExpBuffer(&conn->errorMessage,
+                                                                 
libpq_gettext("certificate present, but not private key file \"%s\"\n"),
+                                                                 keybuf);
+                               return -1;
+                       }
+#ifndef WIN32
+                       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"),
+                                                                 keybuf);
+                               return -1;
+                       }
+#endif
+               }
+
+               ret = gnutls_certificate_set_x509_key_file(creds, fnbuf, 
keybuf, GNUTLS_X509_FMT_PEM);
+               if (ret < 0)
+               {
+                       printfPQExpBuffer(&conn->errorMessage,
+                                                         libpq_gettext("could 
not read certificate and key files \"%s\" \"%s\": %s\n"),
+                                                         fnbuf, keybuf, 
gnutls_strerror(ret));
+                       gnutls_certificate_free_credentials(creds);
+                       return -1;
+               }
+       }
+
+       ret = gnutls_init(&conn->ssl, GNUTLS_CLIENT);
+       if (ret < 0)
+       {
+               printfPQExpBuffer(&conn->errorMessage,
+                                                 libpq_gettext("could not 
establish SSL connection: %s\n"),
+                                                 gnutls_strerror(ret));
+               gnutls_certificate_free_credentials(creds);
+               return -1;
+       }
+
+       gnutls_priority_set_direct(conn->ssl, "NORMAL", NULL);
+       if (ret < 0)
+       {
+               printfPQExpBuffer(&conn->errorMessage,
+                                                 libpq_gettext("could not 
establish SSL connection: %s\n"),
+                                                 gnutls_strerror(ret));
+               gnutls_certificate_free_credentials(creds);
+               return -1;
+       }
+
+       ret = gnutls_credentials_set(conn->ssl, GNUTLS_CRD_CERTIFICATE, creds);
+       if (ret < 0)
+       {
+               printfPQExpBuffer(&conn->errorMessage,
+                                                 libpq_gettext("could not 
establish SSL connection: %s\n"),
+                                                 gnutls_strerror(ret));
+               gnutls_deinit(conn->ssl);
+               gnutls_certificate_free_credentials(creds);
+               return -1;
+       }
+
+       gnutls_transport_set_ptr(conn->ssl, conn);
+       gnutls_transport_set_pull_function(conn->ssl, my_sock_read);
+       gnutls_transport_set_push_function(conn->ssl, my_sock_write);
+
+       conn->ssl_in_use = true;
+
+       return 0;
+}
+
+/*
+ *     Attempt to negotiate SSL connection.
+ */
+static PostgresPollingStatusType
+open_client_SSL(PGconn *conn)
+{
+       int                     ret;
+
+       do
+       {
+               ret = gnutls_handshake(conn->ssl);
+       }
+       while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
+
+       if (ret < 0)
+       {
+               printfPQExpBuffer(&conn->errorMessage,
+                                                 libpq_gettext("SSL error: 
%s\n"),
+                                                 gnutls_strerror(ret));
+               pgtls_close(conn);
+               return PGRES_POLLING_FAILED;
+       }
+
+       /*
+        * We already checked the server certificate in gnutls_handshake() using
+        * verify_cb(), if root.crt exists.
+        */
+
+       /* get server certificate */
+       ret = get_peer_certificate(conn->ssl, &conn->peer);
+       if (conn->peer == NULL)
+       {
+               printfPQExpBuffer(&conn->errorMessage,
+                                                 libpq_gettext("certificate 
could not be obtained: %s\n"),
+                                                 gnutls_strerror(ret));
+               pgtls_close(conn);
+               return PGRES_POLLING_FAILED;
+       }
+
+       if (!pq_verify_peer_name_matches_certificate(conn))
+       {
+               pgtls_close(conn);
+               return PGRES_POLLING_FAILED;
+       }
+
+       /* SSL handshake is complete */
+       return PGRES_POLLING_OK;
+}
+
+void
+pgtls_close(PGconn *conn)
+{
+       if (conn->ssl)
+       {
+               gnutls_bye(conn->ssl, GNUTLS_SHUT_RDWR);
+               gnutls_deinit(conn->ssl);
+               conn->ssl = NULL;
+               conn->ssl_in_use = false;
+       }
+
+       if (conn->peer)
+       {
+               gnutls_x509_crt_deinit(conn->peer);
+               conn->peer = NULL;
+       }
+}
+
+/* ------------------------------------------------------------ */
+/*                                     SSL information functions               
                        */
+/* ------------------------------------------------------------ */
+
+/*
+ *     Return pointer to OpenSSL object, which is none for GnuTLS.
+ */
+void *
+PQgetssl(PGconn *conn)
+{
+       return NULL;
+}
+
+void *
+PQsslStruct(PGconn *conn, const char *struct_name)
+{
+       if (!conn)
+               return NULL;
+       if (strcmp(struct_name, "GnuTLS") == 0)
+               return conn->ssl;
+       return NULL;
+}
+
+const char *const *
+PQsslAttributeNames(PGconn *conn)
+{
+       static const char *const result[] = {
+               "library",
+               "key_bits",
+               "cipher",
+               "compression",
+               "protocol",
+               NULL
+       };
+
+       return result;
+}
+
+const char *
+PQsslAttribute(PGconn *conn, const char *attribute_name)
+{
+       if (!conn)
+               return NULL;
+       if (conn->ssl == NULL)
+               return NULL;
+
+       if (strcmp(attribute_name, "library") == 0)
+               return "GnuTLS";
+
+       if (strcmp(attribute_name, "key_bits") == 0)
+       {
+               static char sslbits_str[10];
+               int                     sslbytes;
+
+               sslbytes = 
gnutls_cipher_get_key_size(gnutls_cipher_get(conn->ssl));
+
+               if (sslbytes == 0)
+                       return NULL;
+
+               snprintf(sslbits_str, sizeof(sslbits_str), "%d", sslbytes * 8);
+               return sslbits_str;
+       }
+
+       if (strcmp(attribute_name, "cipher") == 0)
+               return gnutls_cipher_get_name(gnutls_cipher_get(conn->ssl));
+
+       if (strcmp(attribute_name, "compression") == 0)
+       {
+               gnutls_compression_method_t comp = 
gnutls_compression_get(conn->ssl);
+
+               if (comp == GNUTLS_COMP_NULL || comp == GNUTLS_COMP_UNKNOWN)
+                       return "off";
+               else
+                       return "on";
+       }
+
+       if (strcmp(attribute_name, "protocol") == 0)
+               return 
gnutls_protocol_get_name(gnutls_protocol_get_version(conn->ssl));
+
+       return NULL;                            /* unknown attribute */
+}
+
+/*
+ * Private substitute transport layer: this does the sending and receiving 
using
+ * pqsecure_raw_write() and pqsecure_raw_read() instead, to allow those
+ * functions to disable SIGPIPE and give better error messages on I/O errors.
+ */
+
+static ssize_t
+my_sock_read(gnutls_transport_ptr_t conn, void *buf, size_t size)
+{
+       return pqsecure_raw_read((PGconn *) conn, buf, size);
+}
+
+static ssize_t
+my_sock_write(gnutls_transport_ptr_t conn, const void *buf, size_t size)
+{
+       return pqsecure_raw_write((PGconn *) conn, buf, size);
+}
+
+#if !HAVE_DECL_GNUTLS_X509_CRT_LIST_SORT
+/*
+ * GnuTLS versions before 3.4.0 do not support sorting incorrectly sorted
+ * certificate chains, so we skip doing so in these earlier versions.
+ */
+#define GNUTLS_X509_CRT_LIST_SORT 0
+#endif
+
+/*
+ *     Get peer certificate from a session
+ *
+ *     Returns GNUTLS_E_NO_CERTIFICATE_FOUND when not x509 certifcate was 
found.
+ */
+static int
+get_peer_certificate(gnutls_session_t ssl, gnutls_x509_crt_t *peer)
+{
+       if (gnutls_certificate_type_get(ssl) == GNUTLS_CRT_X509)
+       {
+               unsigned int n;
+               int                     ret;
+               gnutls_datum_t const *raw_certs;
+               gnutls_x509_crt_t *certs;
+
+               raw_certs = gnutls_certificate_get_peers(ssl, &n);
+
+               if (n == 0)
+                       return GNUTLS_E_NO_CERTIFICATE_FOUND;
+
+               certs = malloc(n * sizeof(gnutls_x509_crt_t));
+               if (!certs)
+                       return GNUTLS_E_NO_CERTIFICATE_FOUND;
+
+               ret = gnutls_x509_crt_list_import(certs, &n, raw_certs,
+                                                                               
  GNUTLS_X509_FMT_DER,
+                                                                               
  GNUTLS_X509_CRT_LIST_SORT);
+
+               if (ret >= 1)
+               {
+                       unsigned int i;
+
+                       for (i = 1; i < ret; i++)
+                               gnutls_x509_crt_deinit(certs[i]);
+
+                       *peer = certs[0];
+
+                       ret = GNUTLS_E_SUCCESS;
+               }
+               else if (ret == 0)
+                       ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
+
+               free(certs);
+
+               return ret;
+       }
+
+       return GNUTLS_E_NO_CERTIFICATE_FOUND;
+}
+
+/*
+ *     Certificate verification callback
+ *
+ *     This callback is where we verify the identity of the server.
+ */
+static int
+verify_cb(gnutls_session_t ssl)
+{
+       unsigned int status;
+       int                     ret;
+
+       ret = gnutls_certificate_verify_peers2(ssl, &status);
+       if (ret < 0)
+               return ret;
+
+       return status;
+}
diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c
index f7dc249bf0..5776c55114 100644
--- a/src/interfaces/libpq/fe-secure.c
+++ b/src/interfaces/libpq/fe-secure.c
@@ -139,7 +139,7 @@ PQsslInUse(PGconn *conn)
 
 /*
  *     Exported function to allow application to tell us it's already
- *     initialized OpenSSL.
+ *     initialized the SSL library.
  */
 void
 PQinitSSL(int do_init)
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index ed9c806861..68e4053056 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -339,7 +339,7 @@ extern const char *const *PQsslAttributeNames(PGconn *conn);
  * unencrypted connections or if any other TLS library is in use. */
 extern void *PQgetssl(PGconn *conn);
 
-/* Tell libpq whether it needs to initialize OpenSSL */
+/* Tell libpq whether it needs to initialize the SSL library */
 extern void PQinitSSL(int do_init);
 
 /* More detailed way to tell libpq whether it needs to initialize OpenSSL */
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index fb04c8c61d..83a6f7cb08 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -71,14 +71,15 @@ typedef struct
 #endif
 #endif                                                 /* ENABLE_SSPI */
 
-#ifdef USE_OPENSSL
+#if defined(USE_OPENSSL)
 #include <openssl/ssl.h>
 #include <openssl/err.h>
-
 #ifndef OPENSSL_NO_ENGINE
 #define USE_SSL_ENGINE
 #endif
-#endif                                                 /* USE_OPENSSL */
+#elif defined(USE_GNUTLS)
+#include <gnutls/gnutls.h>
+#endif
 
 /*
  * POSTGRES backend dependent Constants.
@@ -463,7 +464,7 @@ struct pg_conn
        bool            allow_ssl_try;  /* Allowed to try SSL negotiation */
        bool            wait_ssl_try;   /* Delay SSL negotiation until after
                                                                 * attempting 
normal connection */
-#ifdef USE_OPENSSL
+#if defined(USE_OPENSSL)
        SSL                *ssl;                        /* SSL status, if have 
SSL connection */
        X509       *peer;                       /* X509 cert of server */
 #ifdef USE_SSL_ENGINE
@@ -472,7 +473,10 @@ struct pg_conn
        void       *engine;                     /* dummy field to keep struct 
the same if
                                                                 * OpenSSL 
version changes */
 #endif
-#endif                                                 /* USE_OPENSSL */
+#elif defined(USE_GNUTLS)
+       gnutls_session_t ssl;           /* SSL status, if have SSL connection */
+       gnutls_x509_crt_t peer;         /* X509 cert of server */
+#endif
 #endif                                                 /* USE_SSL */
 
 #ifdef ENABLE_GSS
diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c
index f9a06d6606..c3bdd41885 100644
--- a/src/port/pg_strong_random.c
+++ b/src/port/pg_strong_random.c
@@ -24,8 +24,11 @@
 #include <unistd.h>
 #include <sys/time.h>
 
-#ifdef USE_OPENSSL
+#if defined(USE_OPENSSL)
 #include <openssl/rand.h>
+#elif defined(USE_GNUTLS)
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
 #endif
 #ifdef WIN32
 #include <wincrypt.h>
@@ -85,8 +88,9 @@ random_from_file(char *filename, void *buf, size_t len)
  * We support a number of sources:
  *
  * 1. OpenSSL's RAND_bytes()
- * 2. Windows' CryptGenRandom() function
- * 3. /dev/urandom
+ * 2. GnuTLS's gnutls_rnd()
+ * 3. Windows' CryptGenRandom() function
+ * 4. /dev/urandom
  *
  * The configure script will choose which one to use, and set
  * a USE_*_RANDOM flag accordingly.
@@ -136,6 +140,14 @@ pg_strong_random(void *buf, size_t len)
                return true;
        return false;
 
+       /*
+        * When built with GnuTLS, use GnuTLS's gnutls_rnd function.
+        */
+#elif defined(USE_GNUTLS_RANDOM)
+       if (gnutls_rnd(GNUTLS_RND_RANDOM, buf, len) == 0)
+               return true;
+       return false;
+
        /*
         * Windows has CryptoAPI for strong cryptographic numbers.
         */
diff --git a/src/test/Makefile b/src/test/Makefile
index efb206aa75..a6d41c7e46 100644
--- a/src/test/Makefile
+++ b/src/test/Makefile
@@ -27,7 +27,7 @@ ifneq (,$(filter ldap,$(PG_TEST_EXTRA)))
 SUBDIRS += ldap
 endif
 endif
-ifeq ($(with_openssl),yes)
+ifeq ($(filter yes,$(with_openssl) $(with_gnutls)),yes)
 ifneq (,$(filter ssl,$(PG_TEST_EXTRA)))
 SUBDIRS += ssl
 endif
diff --git a/src/test/ssl/Makefile b/src/test/ssl/Makefile
index 97389c90f8..e8d0ed43b0 100644
--- a/src/test/ssl/Makefile
+++ b/src/test/ssl/Makefile
@@ -13,7 +13,7 @@ subdir = src/test/ssl
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-export with_openssl
+export with_openssl with_gnutls
 
 CERTIFICATES := server_ca server-cn-and-alt-names \
        server-cn-only server-single-alt-name server-multiple-alt-names \
@@ -72,9 +72,10 @@ ssl/server-ss.crt: ssl/server-cn-only.key 
ssl/server-cn-only.crt server-cn-only.
        openssl x509 -req -days 10000 -in ssl/server-ss.csr -signkey 
ssl/server-cn-only.key -out ssl/server-ss.crt  -extensions v3_req -extfile 
server-cn-only.config
        rm ssl/server-ss.csr
 
-# Password-protected version of server-cn-only.key
+# Password-protected version of server-cn-only.key (need to use PKCS#8
+# format instead of traditional OpenSSL format for GnuTLS support)
 ssl/server-password.key: ssl/server-cn-only.key
-       openssl rsa -des -in $< -out $@ -passout 'pass:secret1'
+       openssl pkcs8 -topk8 -in $< -out $@ -passout 'pass:secret1'
 
 # Client certificate, signed by the client CA:
 ssl/client.crt: ssl/client.key ssl/client_ca.crt
diff --git a/src/test/ssl/ssl/server-password.key 
b/src/test/ssl/ssl/server-password.key
index adcd38ab88..95ee3fd203 100644
--- a/src/test/ssl/ssl/server-password.key
+++ b/src/test/ssl/ssl/server-password.key
@@ -1,18 +1,17 @@
------BEGIN RSA PRIVATE KEY-----
-Proc-Type: 4,ENCRYPTED
-DEK-Info: DES-CBC,2FAEFD1C1B2C881C
-
-PGi9r3pm05iUwz5QbZik+ZNu0fHNaX8LJFZqpOhg0TV38csLtQ2PRjZ0Q/diBlVT
-SD8JJnIvwPoIWXyMMTax/krFL0CpbFqgAzD4CEgfWxGNhwnMD1DkNaYp/UF/NfuF
-7TqXomUlcH/pVaZlu7G0wrIo5rnjef70I7GEY2vwT5adSLsUBAgrs/u3MAAx/Wh4
-PkVxZELmyiH/8MdIevodjRcJrgIzRheEph39eHrWKgWeSbO0DEQK91vv3prICwo2
-w2iU0Zohf92QuquA2MKZWruCHb4A4HusUZf3Zc14Yueu/HyztSrHmFeBp0amlWep
-/o6mx274XVj7IpanOPPM4qEhrF97LHdaSEPn9HwxvvV4GFJDNCVEBl4zuaHo0N8C
-85GPazIxUWB3CB9PrtXduxeI22lwrIiUdmzA68EXHD7Wg8R90397MNMOomLgfNcu
-rXarrTXmTNgOa20hc1Ue5AXg9fVS9V/5GP4Dn9SX/CdaE1rz0b73N/ViQzVrS9Ne
-n04qYPbnf+MQmFWnzMXctZbYG6jDCbuGFIGP4i/LG+wOE8Rntu8Re9re+HANu5VJ
-Ht20wYOGZIpNwo4YenxvPeTTlbB0Qcma2lnw2bt19owpNQVIeTnRQXxZs3/Y3a+A
-+/B8VvIkQ0u0EpnSVLBetEmJqtOQvBz7c4Z+0Cl+DL1bTqrDn54MxUBap6dgU+/1
-R6pxx1F0ZTtQauVmO8n3rWKwOGG5NeMhf4iId2JWpw39VtRk8LNtnGUbUAbL5znY
-rkUVyJstQg6U6kNTgDWQ1nBxCzlRz2xpHyghnyxLkMpW5ECpmwwLDQ==
------END RSA PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICoTAbBgkqhkiG9w0BBQMwDgQIECagSEM3B/MCAggABIICgF9tG895A9Q81uR/
+d+EcY21a787f2yiUvgOuhuClmWiqOTNSEC/iJqHb83NL0q31QsIG3SPGtTvtafF8
++uVDzqmx4bmKP5LVX88eOgF6kjTT88ouWk1syHtEa7hSU70XPjh/fnUWwqTqW6gn
+BVKH6J5hOhyI1aWQpRrhmlq6LQD01UlRed0sti35KUji+ohWSPyyC0wSKz8cCKIx
+oCUyc1IDxbr/PCzXwxSK9iVCIIXx+3emi4puwt9QSVMwqo+LMFMhLz/L3bLXE6iZ
+BQOBUKtVoO5kLcvtIwRJWBir8HSeIIZnzGI23YnIythY4WnkPLkUFH9uoaYZU3l6
+UkZ2/cAQwbT6xZxgZQz/HhWLHuqrOCWZboG1oYmTkvO6+8FYRVfPrbJsQqop8olj
+T2jnlD37W79lAbT5xMJEfvow+h6ebu+wf4Bq9f223JgfBXrGevoksVfWRINtQ7iy
+Mxrj4dabHRiQTF6semNnHedvulZK6UtwoNQudM0vOzZTd42W8FMjgjU4U7KI+6AX
+G9SaSAjRMlM5x4PyMnyA+wjyboWpo4jMLdUhNqSs2W+3AWh1qYuh8Ny9ENcKTAY6
+6hu2RCKQyJBsHm5XN1XaueNsyEq11yk9AZFLAWM5h5WPziZNYSHYwEBXpZlIcpWY
+6MR/XUqv43B8KvQwr7bHS2GZ2fAD5sd7oq9qpBr7o6IRO3MKh16T6pwoaQ7sqRg4
+1Ftk7htujwEIrTmIQihzmZRZguA3ceAYUduSFElckZD04LDJnxhhj+AVHnbFA+6x
+VWOoxECXWa3ReOoJMQvbR4gF5yhNtZOtlbaqOp0iVGT/d2e9Bl66E/FqnkWweE4d
+0iziYMw=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 2b875a3c95..3602199ff6 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -6,15 +6,13 @@
 use ServerSetup;
 use File::Copy;
 
-if ($ENV{with_openssl} eq 'yes')
-{
-       plan tests => 65;
-}
-else
+if ($ENV{with_openssl} ne 'yes' && $ENV{with_gnutls} ne 'yes')
 {
        plan skip_all => 'SSL not supported by this build';
 }
 
+my $number_of_tests = 63;
+
 #### Some configuration
 
 # This is the hostname used to connect to the server. This cannot be a
@@ -52,7 +50,11 @@
 
 # Run this before we lock down access below.
 my $result = $node->safe_psql('postgres', "SHOW ssl_library");
-is($result, 'OpenSSL', 'ssl_library parameter');
+my $expected;
+if ($ENV{'with_openssl'} eq 'yes')             { $expected = 'OpenSSL'; }
+elsif ($ENV{'with_gnutls'} eq 'yes')   { $expected = 'GnuTLS'; }
+else                                                                   { 
$expected = ''; }
+is($result, $expected, 'ssl_library parameter');
 
 configure_test_server_for_ssl($node, $SERVERHOSTADDR, 'trust');
 
@@ -130,11 +132,22 @@
        "sslrootcert=ssl/client_ca.crt sslmode=verify-full",
        qr/SSL error/, "connect with wrong server root cert 
sslmode=verify-full");
 
-# Try with just the server CA's cert. This fails because the root file
-# must contain the whole chain up to the root CA.
-test_connect_fails($common_connstr,
-       "sslrootcert=ssl/server_ca.crt sslmode=verify-ca",
-       qr/SSL error/, "connect with server CA cert, without root CA");
+# Try with just the server CA's cert. This fails with OpenSSL because
+# the root file must contain the whole chain up to the root CA.
+if ($ENV{'with_openssl'} eq 'yes')
+{
+       test_connect_fails($common_connstr,
+                                          "sslrootcert=ssl/server_ca.crt 
sslmode=verify-ca",
+                                          qr/SSL error/,
+                                          "connect with server CA cert, 
without root CA");
+       $number_of_tests++;
+}
+else
+{
+       test_connect_ok($common_connstr,
+                                       "sslrootcert=ssl/server_ca.crt 
sslmode=verify-ca",
+                                       "connect with server CA cert, without 
root CA");
+}
 
 # And finally, with the correct root cert.
 test_connect_ok(
@@ -169,12 +182,21 @@
        "sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=invalid",
        "sslcrl option with invalid file name");
 
-# A CRL belonging to a different CA is not accepted, fails
-test_connect_fails(
-       $common_connstr,
-       "sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca 
sslcrl=ssl/client.crl",
-       qr/SSL error/,
-       "CRL belonging to a different CA");
+if ($ENV{'with_openssl'} eq 'yes')
+{
+       # A CRL belonging to a different CA is not accepted, fails
+       test_connect_fails($common_connstr,
+                                          "sslrootcert=ssl/root+server_ca.crt 
sslmode=verify-ca sslcrl=ssl/client.crl",
+                                          qr/SSL error/,
+                                          "CRL belonging to a different CA");
+       $number_of_tests++;
+}
+else
+{
+       test_connect_ok($common_connstr,
+                                       "sslrootcert=ssl/root+server_ca.crt 
sslmode=verify-ca sslcrl=ssl/client.crl",
+                                       "CRL belonging to a different CA");
+}
 
 # With the correct CRL, succeeds (this cert is not revoked)
 test_connect_ok(
@@ -363,8 +385,13 @@
        "sslmode=require sslcert=ssl/client+client_ca.crt",
        "intermediate client certificate is provided by client");
 test_connect_fails($common_connstr, "sslmode=require sslcert=ssl/client.crt",
-       qr/SSL error/, "intermediate client certificate is missing");
+                                  ($ENV{'with_openssl'} eq 'yes' ?
+                                       qr/SSL error/ :
+                                       qr/connection requires a valid client 
certificate/),
+                                  "intermediate client certificate is 
missing");
 
 # clean up
 unlink("ssl/client_tmp.key", "ssl/client_wrongperms_tmp.key",
        "ssl/client-revoked_tmp.key");
+
+done_testing($number_of_tests);
diff --git a/src/test/ssl/t/002_scram.pl b/src/test/ssl/t/002_scram.pl
index b460a7fa8a..0c10ea8bc4 100644
--- a/src/test/ssl/t/002_scram.pl
+++ b/src/test/ssl/t/002_scram.pl
@@ -8,7 +8,7 @@
 use ServerSetup;
 use File::Copy;
 
-if ($ENV{with_openssl} ne 'yes')
+if ($ENV{with_openssl} ne 'yes' && $ENV{with_gnutls} ne 'yes')
 {
        plan skip_all => 'SSL not supported by this build';
 }
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 4543d87d83..0ae138fbfb 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -124,6 +124,10 @@ sub mkvcbuild
        {
                push(@pgcommonallfiles, 'sha2_openssl.c');
        }
+       elsif ($solution->{options}->{gnutls})
+       {
+               push(@pgcommonallfiles, 'sha2_gnutls.c');
+       }
        else
        {
                push(@pgcommonallfiles, 'sha2.c');
@@ -252,6 +256,12 @@ sub mkvcbuild
                $libpq->RemoveFile('src/interfaces/libpq/fe-secure-openssl.c');
                $libpq->RemoveFile('src/common/sha2_openssl.c');
        }
+       elsif (!$solution->{options}->{gnutls})
+       {
+               $libpq->RemoveFile('src/interfaces/libpq/fe-secure-common.c');
+               $libpq->RemoveFile('src/interfaces/libpq/fe-secure-gnutls.c');
+               $libpq->RemoveFile('src/common/sha2_gnutls.c');
+       }
        else
        {
                $libpq->RemoveFile('src/common/sha2.c');
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 9fe950b29d..07823ccfa9 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2818,6 +2818,9 @@ ginxlogVacuumDataLeafPage
 gistxlogPage
 gistxlogPageSplit
 gistxlogPageUpdate
+gnutls_datum_t
+gnutls_dh_params_t
+gnutls_x509_crt_t
 grouping_sets_data
 gseg_picksplit_item
 gss_OID

base-commit: 2e39f69b6621bd3d67f650a5647fd0412819712d
-- 
2.18.0

Reply via email to