In the thread about Secure Transport we agreed to move the consideration
of new SSL libraries to PG12.

Here is my current patch, after all the refactorings.

The status is that it works fine and could be used.

There are two failures in the SSL tests that I cannot explain.  The
tests are for some rather obscure configurations, so the changed
behaviors are not obviously wrong, perhaps legitimate implementation
differences.  But someone wrote those tests with a purpose (probably),
so we should have some kind of explanation for the regressions.

Other non-critical, nice-to-have issues:

- Do something about sslinfo, perhaps fold into pg_stat_ssl view.
- Do something about pgcrypto.
- Add tests for load_dh_file().
- Implement channel binding tls-server-end-point.

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From c76b6efca0f52fe4deb6003009f4f8730201f041 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pete...@gmx.net>
Date: Thu, 8 Mar 2018 14:05:33 -0500
Subject: [PATCH v6] GnuTLS support

---
 configure                                     | 258 ++++++--
 configure.in                                  |  37 +-
 doc/src/sgml/client-auth.sgml                 |   2 +-
 doc/src/sgml/config.sgml                      |  81 ++-
 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          | 820 +++++++++++++++++++++++++
 src/backend/libpq/be-secure-openssl.c         |   4 +-
 src/backend/libpq/be-secure.c                 |   4 +
 src/backend/libpq/hba.c                       |   2 +-
 src/backend/utils/misc/guc.c                  |  38 ++
 src/backend/utils/misc/postgresql.conf.sample |   7 +-
 src/common/Makefile                           |   4 +-
 src/common/sha2_gnutls.c                      |  99 +++
 src/include/common/sha2.h                     |  14 +-
 src/include/libpq/libpq-be.h                  |  13 +-
 src/include/libpq/libpq.h                     |   2 +
 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       | 836 ++++++++++++++++++++++++++
 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                         |   2 +-
 src/test/ssl/t/001_ssltests.pl                |  65 +-
 src/test/ssl/t/002_scram.pl                   |   2 +-
 src/tools/msvc/Mkvcbuild.pm                   |  10 +
 src/tools/pgindent/typedefs.list              |   3 +
 36 files changed, 2360 insertions(+), 135 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 3943711283..f2d4aa502a 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
@@ -838,6 +839,7 @@ with_bsd_auth
 with_ldap
 with_bonjour
 with_openssl
+with_gnutls
 with_selinux
 with_systemd
 with_readline
@@ -1532,6 +1534,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
@@ -1999,6 +2002,52 @@ $as_echo "$ac_res" >&6; }
 
 } # ac_fn_c_check_func
 
+# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
+# ---------------------------------------------
+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
+# accordingly.
+ac_fn_c_check_decl ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  as_decl_name=`echo $2|sed 's/ *(.*//'`
+  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is 
declared" >&5
+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+#ifndef $as_decl_name
+#ifdef __cplusplus
+  (void) $as_decl_use;
+#else
+  (void) $as_decl_name;
+#endif
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_decl
+
 # ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
 # ----------------------------------------------------
 # Tries to find if the field MEMBER exists in type AGGR, after including
@@ -2292,52 +2341,6 @@ rm -f conftest.val
   as_fn_set_status $ac_retval
 
 } # ac_fn_c_compute_int
-
-# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
-# ---------------------------------------------
-# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
-# accordingly.
-ac_fn_c_check_decl ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  as_decl_name=`echo $2|sed 's/ *(.*//'`
-  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is 
declared" >&5
-$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
-if eval \${$3+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-$4
-int
-main ()
-{
-#ifndef $as_decl_name
-#ifdef __cplusplus
-  (void) $as_decl_use;
-#else
-  (void) $as_decl_name;
-#endif
-#endif
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  eval "$3=yes"
-else
-  eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-eval ac_res=\$$3
-              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_decl
 cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
@@ -6001,6 +6004,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
 #
@@ -10176,6 +10220,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; }
@@ -10984,6 +11129,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
@@ -15741,9 +15897,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
@@ -15782,6 +15940,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 1babdbb755..2aa132b7d1 100644
--- a/configure.in
+++ b/configure.in
@@ -706,6 +706,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
 #
@@ -1080,6 +1095,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
@@ -1228,6 +1254,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, [],
@@ -1997,9 +2027,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
@@ -2016,6 +2048,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 53832d08e2..27f31102d7 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -1789,7 +1789,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 3a8fc7d803..1770ed5025 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,31 +1320,41 @@ <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>
     </variablelist>
+
     </sect2>
    </sect1>
 
@@ -8120,6 +8161,22 @@ <title>Preset Options</title>
       </listitem>
      </varlistentry>
 
+     <varlistentry id="guc-ssl-library" xreflabel="ssl_library">
+      <term><varname>ssl_library</varname> (<type>string</type>)
+      <indexterm>
+       <primary><varname>ssl_library</varname> configuration 
parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <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
+        <literal>GnuTLS</literal>, or an empty string if none.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-wal-block-size" xreflabel="wal_block_size">
       <term><varname>wal_block_size</varname> (<type>integer</type>)
       <indexterm>
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index 141494c651..9d10844ea8 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>
@@ -798,12 +821,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>
@@ -2284,7 +2311,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 da9421486b..9d3ee7229b 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1442,8 +1442,9 @@ <title>Parameter Key Words</title>
         compressed.
         If set to 0, compression will be disabled (this requires
         <productname>OpenSSL</productname> 1.0.0 or later).
+        <productname>GnuTLS</productname> does not support SSL compression.
         This parameter is ignored if a connection without SSL is made,
-        or if the version of <productname>OpenSSL</productname> used does not 
support
+        or if the SSL library used does not support
         it.
        </para>
        <para>
@@ -2141,8 +2142,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>
@@ -2211,11 +2212,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>
@@ -2234,12 +2235,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>
 
@@ -7632,6 +7652,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
@@ -8006,6 +8027,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">
@@ -8041,6 +8069,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>
 
@@ -8061,12 +8093,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 587b430527..f18ce4c9ac 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -2152,10 +2152,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">
@@ -2225,6 +2229,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 15c14951e8..a4c2761424 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -183,6 +183,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 7fa2b02743..7af6e22744 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 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..cc8b86331d
--- /dev/null
+++ b/src/backend/libpq/be-secure-gnutls.c
@@ -0,0 +1,820 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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;
+
+
+/* ------------------------------------------------------------ */
+/*                                              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
+
+       /*
+        * 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)
+{
+       simple_prompt(token_url, 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';
+}
+
+char *
+be_tls_get_peer_finished(Port *port, size_t *len)
+{
+       gnutls_datum_t cb;
+       int                     ret;
+       char       *result;
+
+       ret = gnutls_session_channel_binding(port->ssl, GNUTLS_CB_TLS_UNIQUE, 
&cb);
+
+       if (ret < 0)
+               ereport(FATAL,
+                               (errmsg("could not get SSL channel binding 
data: %s",
+                                               gnutls_strerror(ret))));
+
+       result = palloc(cb.size);
+       memcpy(result, cb.data, cb.size);
+       *len = cb.size;
+
+       return result;
+}
+
+/*
+ * Stub function for SCRAM channel binding type tls-server-end-point,
+ * currently not supported with GnuTLS.
+ */
+char *
+be_tls_get_certificate_hash(Port *port, size_t *len)
+{
+       ereport(ERROR,
+                       (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                        errmsg("channel binding type \"tls-server-end-point\" 
is not supported by this build")));
+       return NULL;
+}
diff --git a/src/backend/libpq/be-secure-openssl.c 
b/src/backend/libpq/be-secure-openssl.c
index e1ddfb3c16..f2aeb58a30 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -212,10 +212,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 76c0a9e39b..624765aec3 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -40,6 +40,7 @@
 #include "storage/proc.h"
 
 
+char      *ssl_library;
 char      *ssl_cert_file;
 char      *ssl_key_file;
 char      *ssl_ca_file;
@@ -59,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 acf625e4ec..62531c990b 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 a4f9b3668e..88ce482d3c 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -3542,6 +3542,25 @@ static struct config_string ConfigureNamesString[] =
                check_canonical_path, NULL, NULL
        },
 
+       {
+               {"ssl_library", PGC_INTERNAL, PRESET_OPTIONS,
+                       gettext_noop("Name of the SSL library."),
+                       NULL,
+                       GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+               },
+               &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
+#endif
+               NULL, NULL, NULL
+       },
+
        {
                {"ssl_cert_file", PGC_SIGHUP, CONN_AUTH_SSL,
                        gettext_noop("Location of the SSL server certificate 
file."),
@@ -3644,6 +3663,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 39272925fb..45f892b968 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -100,10 +100,15 @@
 #ssl_cert_file = 'server.crt'
 #ssl_crl_file = ''
 #ssl_key_file = 'server.key'
+#ssl_dh_params_file = ''
+
+# 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'
-#ssl_dh_params_file = ''
+
+# Parameters for GnuTLS.  Leave these commented out if not using GnuTLS.
+#gnutls_priority = 'NORMAL:%SERVER_PRECEDENCE'
 
 
 #------------------------------------------------------------------------------
diff --git a/src/common/Makefile b/src/common/Makefile
index 80e78d72fe..cb1c91373a 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 ip.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 7698cd1f88..0208ac6f3f 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;
 
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index 255222acd7..b7e5d41344 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -75,6 +75,7 @@ extern int    pq_putbytes(const char *s, size_t len);
 /*
  * prototypes for functions in be-secure.c
  */
+extern char *ssl_library;
 extern char *ssl_cert_file;
 extern char *ssl_key_file;
 extern char *ssl_ca_file;
@@ -100,5 +101,6 @@ extern WaitEventSet *FeBeWaitSet;
 extern char *SSLCipherSuites;
 extern char *SSLECDHCurve;
 extern bool SSLPreferServerCiphers;
+extern char *gnutls_priority;
 
 #endif                                                 /* LIBPQ_H */
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index f98f773ff0..023b68bee2 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 `posix_fadvise', and to 0 if you
    don't. */
 #undef HAVE_DECL_POSIX_FADVISE
@@ -256,6 +264,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
 
@@ -834,6 +845,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..8a82edb6c3
--- /dev/null
+++ b/src/interfaces/libpq/fe-secure-gnutls.c
@@ -0,0 +1,836 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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;
+}
+
+char *
+pgtls_get_finished(PGconn *conn, size_t *len)
+{
+       gnutls_datum_t cb;
+       int                     ret;
+       char       *result;
+
+       ret = gnutls_session_channel_binding(conn->ssl, GNUTLS_CB_TLS_UNIQUE, 
&cb);
+
+       if (ret < 0)
+               return NULL;
+
+       result = malloc(cb.size);
+       if (result == NULL)
+               return NULL;
+       memcpy(result, cb.data, cb.size);
+       *len = cb.size;
+
+       return result;
+}
+
+/*
+ * Stub function for SCRAM channel binding type tls-server-end-point,
+ * currently not supported with GnuTLS.
+ */
+char *
+pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len)
+{
+       printfPQExpBuffer(&conn->errorMessage,
+                                         libpq_gettext("channel binding type 
\"tls-server-end-point\" is not supported by this build\n"));
+       return NULL;
+}
+
+/* ------------------------------------------------------------ */
+/*                                             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 cfb77f6d85..37bb86044a 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 eba23dcecc..16b7676703 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.
@@ -461,7 +462,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
@@ -470,7 +471,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 bc7a8aacb9..73c02251ad 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.
@@ -107,6 +111,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 5cd2c5a404..5b166dc433 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 \
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 34df5e9dbb..1169b5e608 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 => 62;
-}
-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 = 61;
+
 #### Some configuration
 
 # This is the hostname used to connect to the server. This cannot be a
@@ -49,6 +47,15 @@
 $ENV{PGHOST} = $node->host;
 $ENV{PGPORT} = $node->port;
 $node->start;
+
+# Run this before we lock down access below.
+my $result = $node->safe_psql('postgres', "SHOW ssl_library");
+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');
 switch_server_cert($node, 'server-cn-only');
 
@@ -94,12 +101,22 @@
                                   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($common_connstr,
@@ -128,11 +145,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($common_connstr,
@@ -282,10 +309,14 @@
                                "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/,
+                                  ($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 a805a3196b..89d770a729 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 72976f44d8..29d768c7e7 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -119,6 +119,10 @@ sub mkvcbuild
        {
                push(@pgcommonallfiles, 'sha2_openssl.c');
        }
+       elsif ($solution->{options}->{gnutls})
+       {
+               push(@pgcommonallfiles, 'sha2_gnutls.c');
+       }
        else
        {
                push(@pgcommonallfiles, 'sha2.c');
@@ -246,6 +250,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 d4765ce3b0..ba2cf56e0c 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2729,6 +2729,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: 04e7ecadf64d18f67ca1d0632d8ab71f120ca5e3
-- 
2.16.2

Reply via email to