diff -r acf1c26e3019 configure
--- a/configure	Thu May 15 12:25:25 2014 -0600
+++ b/configure	Thu May 15 13:23:32 2014 -0600
@@ -1006,6 +1006,8 @@
 with_dnet
 enable_ipv6_cname
 with_ipv6_cname
+enable_tls
+with_tls
 enable_rel_alloc
 with_rel_alloc
 enable_dlmalloc
@@ -1938,6 +1940,9 @@
   --with-ipv6-cname       Try IPv6 information first when canonicalizing host
                           names. This option has no effect unless system
                           supports getaddrinfo(3) and getnameinfo(3).
+  --with-tls=TYPE         Support TLS connections. TYPE must be one of "nss",
+                          "gnutls", and "openssl". If TYPE is omitted or
+                          "yes", support is determined automatically.
 
 Memory allocation options
 -------------------------
@@ -4922,6 +4927,22 @@
 else
   with_ipv6_cname="no"
 fi;
+# If --with-tls or --without-tls were given then copy the value to the
+# equivalent enable_tls variable.
+if test "${with_tls+set}" = set; then
+  enable_tls="$with_tls"
+fi;
+# If -enable-tls or --disable-tls were given then copy the value to the
+# equivalent with_tls variable.
+if test "${enable_tls+set}" = set; then
+  with_tls="$enable_tls"
+fi;
+# Check whether --with-tls or --without-tls was given.
+if test "${with_tls+set}" = set; then
+  enableval="$with_tls"
+  withval="$with_tls"
+
+fi;
 
 # If --with-rel-alloc or --without-rel-alloc were given then copy the value to the
 # equivalent enable_rel-alloc variable.
@@ -21000,6 +21021,318 @@
 
 fi
 
+if test "$with_tls" = "yes"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for NSS_InitContext in -lnss3" >&5
+$as_echo_n "checking for NSS_InitContext in -lnss3... " >&6; }
+if ${ac_cv_lib_nss3_NSS_InitContext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnss3  $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 NSS_InitContext ();
+int
+main ()
+{
+return NSS_InitContext ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_nss3_NSS_InitContext=yes
+else
+  ac_cv_lib_nss3_NSS_InitContext=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nss3_NSS_InitContext" >&5
+$as_echo "$ac_cv_lib_nss3_NSS_InitContext" >&6; }
+if test "x$ac_cv_lib_nss3_NSS_InitContext" = xyes; then :
+  with_tls=nss
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gnutls_global_init in -lgnutls" >&5
+$as_echo_n "checking for gnutls_global_init in -lgnutls... " >&6; }
+if ${ac_cv_lib_gnutls_gnutls_global_init+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgnutls  $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_global_init ();
+int
+main ()
+{
+return gnutls_global_init ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_gnutls_gnutls_global_init=yes
+else
+  ac_cv_lib_gnutls_gnutls_global_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnutls_gnutls_global_init" >&5
+$as_echo "$ac_cv_lib_gnutls_gnutls_global_init" >&6; }
+if test "x$ac_cv_lib_gnutls_gnutls_global_init" = xyes; then :
+  with_tls=gnutls
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_library_init in -lssl" >&5
+$as_echo_n "checking for SSL_library_init in -lssl... " >&6; }
+if ${ac_cv_lib_ssl_SSL_library_init+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl  $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 SSL_library_init ();
+int
+main ()
+{
+return SSL_library_init ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_ssl_SSL_library_init=yes
+else
+  ac_cv_lib_ssl_SSL_library_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_library_init" >&5
+$as_echo "$ac_cv_lib_ssl_SSL_library_init" >&6; }
+if test "x$ac_cv_lib_ssl_SSL_library_init" = xyes; then :
+  with_tls=openssl
+else
+  with_tls=no
+fi
+
+fi
+
+fi
+
+elif test "$with_tls" = "nss"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for NSS_InitContext in -lnss3" >&5
+$as_echo_n "checking for NSS_InitContext in -lnss3... " >&6; }
+if ${ac_cv_lib_nss3_NSS_InitContext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnss3  $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 NSS_InitContext ();
+int
+main ()
+{
+return NSS_InitContext ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_nss3_NSS_InitContext=yes
+else
+  ac_cv_lib_nss3_NSS_InitContext=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nss3_NSS_InitContext" >&5
+$as_echo "$ac_cv_lib_nss3_NSS_InitContext" >&6; }
+if test "x$ac_cv_lib_nss3_NSS_InitContext" = xyes; then :
+  with_tls=nss
+else
+  { echo "Error:" "Required NSS support cannot be provided." >&2; exit 1; }
+fi
+
+elif test "$with_tls" = "gnutls"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gnutls_global_init in -lgnutls" >&5
+$as_echo_n "checking for gnutls_global_init in -lgnutls... " >&6; }
+if ${ac_cv_lib_gnutls_gnutls_global_init+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgnutls  $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_global_init ();
+int
+main ()
+{
+return gnutls_global_init ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_gnutls_gnutls_global_init=yes
+else
+  ac_cv_lib_gnutls_gnutls_global_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnutls_gnutls_global_init" >&5
+$as_echo "$ac_cv_lib_gnutls_gnutls_global_init" >&6; }
+if test "x$ac_cv_lib_gnutls_gnutls_global_init" = xyes; then :
+  with_tls=gnutls
+else
+  { echo "Error:" "Required gnutls support cannot be provided." >&2; exit 1; }
+fi
+
+elif test "$with_tls" = "openssl"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_library_init in -lssl" >&5
+$as_echo_n "checking for SSL_library_init in -lssl... " >&6; }
+if ${ac_cv_lib_ssl_SSL_library_init+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lssl  $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 SSL_library_init ();
+int
+main ()
+{
+return SSL_library_init ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_ssl_SSL_library_init=yes
+else
+  ac_cv_lib_ssl_SSL_library_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_library_init" >&5
+$as_echo "$ac_cv_lib_ssl_SSL_library_init" >&6; }
+if test "x$ac_cv_lib_ssl_SSL_library_init" = xyes; then :
+  with_tls=openssl
+else
+  { echo "Error:" "Required openssl support cannot be provided." >&2; exit 1; }
+fi
+
+fi
+if test "$with_tls" != "no"; then
+  $as_echo "#define WITH_TLS 1" >>confdefs.h
+
+  if test "$with_tls" = "nss"; then
+    $as_echo "#define HAVE_NSS 1" >>confdefs.h
+
+    nss_cflags=`pkg-config --cflags nss`
+    if test "$?" = 0; then
+      CPPFLAGS=""$nss_cflags" $CPPFLAGS" &&  if test "$verbose" = "yes"; then echo "    Prepending \""$nss_cflags"\" to \$CPPFLAGS"; fi
+    fi
+    nss_libs=`pkg-config --libs nss`
+    if test "$?" = 0; then
+      LDFLAGS=""$nss_libs" $LDFLAGS" &&  if test "$verbose" = "yes"; then echo "    Prepending \""$nss_libs"\" to \$LDFLAGS"; fi
+    fi
+  elif test "$with_tls" = "gnutls"; then
+    $as_echo "#define HAVE_GNUTLS 1" >>confdefs.h
+
+    gnutls_cflags=`pkg-config --cflags gnutls`
+    if test "$?" = 0; then
+      CPPFLAGS=""$gnutls_cflags" $CPPFLAGS" &&  if test "$verbose" = "yes"; then echo "    Prepending \""$gnutls_cflags"\" to \$CPPFLAGS"; fi
+    fi
+    gnutls_libs=`pkg-config --libs gnutls`
+    if test "$?" = 0; then
+      LDFLAGS=""$gnutls_libs" $LDFLAGS" &&  if test "$verbose" = "yes"; then echo "    Prepending \""$gnutls_libs"\" to \$LDFLAGS"; fi
+    fi
+    ac_fn_c_check_func "$LINENO" "gnutls_certificate_verification_status_print" "ac_cv_func_gnutls_certificate_verification_status_print"
+if test "x$ac_cv_func_gnutls_certificate_verification_status_print" = xyes; then :
+  $as_echo "#define HAVE_GNUTLS_CERTIFICATE_VERIFICATION_STATUS_PRINT 1" >>confdefs.h
+
+fi
+
+    ac_fn_c_check_func "$LINENO" "gnutls_certificate_verify_peers3" "ac_cv_func_gnutls_certificate_verify_peers3"
+if test "x$ac_cv_func_gnutls_certificate_verify_peers3" = xyes; then :
+  $as_echo "#define HAVE_GNUTLS_CERTIFICATE_VERIFY_PEERS3 1" >>confdefs.h
+
+fi
+
+  else
+    $as_echo "#define HAVE_OPENSSL 1" >>confdefs.h
+
+    openssl_cflags=`pkg-config --cflags openssl`
+    if test "$?" = 0; then
+      CPPFLAGS=""$openssl_cflags" $CPPFLAGS" &&  if test "$verbose" = "yes"; then echo "    Prepending \""$openssl_cflags"\" to \$CPPFLAGS"; fi
+    fi
+    openssl_libs=`pkg-config --libs openssl`
+    if test "$?" = 0; then
+      LDFLAGS=""$openssl_libs" $LDFLAGS" &&  if test "$verbose" = "yes"; then echo "    Prepending \""$openssl_libs"\" to \$LDFLAGS"; fi
+    fi
+    ac_fn_c_check_func "$LINENO" "X509_check_host" "ac_cv_func_X509_check_host"
+if test "x$ac_cv_func_X509_check_host" = xyes; then :
+  $as_echo "#define HAVE_X509_CHECK_HOST 1" >>confdefs.h
+
+fi
+
+  fi
+fi
+
 if test "$cross_compiling" = yes; then :
   { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
@@ -21806,12 +22139,18 @@
 test -n "$with_mail_locking" && echo "  Compiling in support for \"$with_mail_locking\" mail spool file locking method."
 
 echo "
-Other Features:"
+Network:"
 test "$with_ipv6_cname" = no && echo "  Inhibiting IPv6 canonicalization at startup."
 test "$with_tooltalk" = yes && echo "  Compiling in support for ToolTalk."
 test "$with_workshop" = yes && echo "  Compiling in support for Sun WorkShop."
 test "$with_socks" = yes && echo "  Compiling in support for SOCKS."
 test "$with_dnet" = yes && echo "  Compiling in support for DNET."
+test "$with_tls" = nss && echo "  Compiling in support for TLS with NSS."
+test "$with_tls" = gnutls && echo "  Compiling in support for TLS with gnutls."
+test "$with_tls" = openssl && echo "  Compiling in support for TLS with OpenSSL."
+
+echo "
+Other Features:"
 test "$with_modules" = "yes" && echo "  Compiling in support for dynamic shared object modules."
 test "$with_bignum" = "gmp" && echo "  Compiling in support for more number types using the GNU MP library."
 test "$with_bignum" = "mpir" && echo "  Compiling in support for more number types using the MPIR library."
diff -r acf1c26e3019 configure.ac
--- a/configure.ac	Thu May 15 12:25:25 2014 -0600
+++ b/configure.ac	Thu May 15 13:23:32 2014 -0600
@@ -917,6 +917,9 @@
 XE_MERGED_ARG([ipv6-cname],
 	AS_HELP_STRING([--with-ipv6-cname],[Try IPv6 information first when canonicalizing host names.  This option has no effect unless system supports getaddrinfo(3) and getnameinfo(3).]),
 	[], [with_ipv6_cname="no"])
+XE_MERGED_ARG([tls],
+	AS_HELP_STRING([--with-tls=TYPE],[Support TLS connections.  TYPE must be one of "nss", "gnutls", and "openssl".  If TYPE is omitted or "yes", support is determined automatically.]),
+	[], [])
 dnl
 XE_HELP_SUBSECTION([Memory allocation options])
 XE_MERGED_ARG([rel-alloc],
@@ -5328,6 +5331,61 @@
   AC_DEFINE(WITH_MP)
 fi
 
+dnl TLS support
+if test "$with_tls" = "yes"; then
+  AC_CHECK_LIB(nss3, NSS_InitContext, [with_tls=nss],
+    AC_CHECK_LIB(gnutls, gnutls_global_init, [with_tls=gnutls],
+      AC_CHECK_LIB(ssl, SSL_library_init, [with_tls=openssl], [with_tls=no])))
+elif test "$with_tls" = "nss"; then
+  AC_CHECK_LIB(nss3, NSS_InitContext, [with_tls=nss],
+    [XE_DIE("Required NSS support cannot be provided.")])
+elif test "$with_tls" = "gnutls"; then
+  AC_CHECK_LIB(gnutls, gnutls_global_init, [with_tls=gnutls],
+    [XE_DIE("Required gnutls support cannot be provided.")])
+elif test "$with_tls" = "openssl"; then
+  AC_CHECK_LIB(ssl, SSL_library_init, [with_tls=openssl],
+    [XE_DIE("Required openssl support cannot be provided.")])
+fi
+if test "$with_tls" != "no"; then
+  AC_DEFINE(WITH_TLS)
+  if test "$with_tls" = "nss"; then
+    AC_DEFINE(HAVE_NSS)
+    nss_cflags=`pkg-config --cflags nss`
+    if test "$?" = 0; then
+      XE_PREPEND("$nss_cflags", CPPFLAGS)
+    fi
+    nss_libs=`pkg-config --libs nss`
+    if test "$?" = 0; then
+      XE_PREPEND("$nss_libs", LDFLAGS)
+    fi
+  elif test "$with_tls" = "gnutls"; then
+    AC_DEFINE(HAVE_GNUTLS)
+    gnutls_cflags=`pkg-config --cflags gnutls`
+    if test "$?" = 0; then
+      XE_PREPEND("$gnutls_cflags", CPPFLAGS)
+    fi
+    gnutls_libs=`pkg-config --libs gnutls`
+    if test "$?" = 0; then
+      XE_PREPEND("$gnutls_libs", LDFLAGS)
+    fi
+    AC_CHECK_FUNC(gnutls_certificate_verification_status_print,
+	[AC_DEFINE(HAVE_GNUTLS_CERTIFICATE_VERIFICATION_STATUS_PRINT)])
+    AC_CHECK_FUNC(gnutls_certificate_verify_peers3,
+	[AC_DEFINE(HAVE_GNUTLS_CERTIFICATE_VERIFY_PEERS3)])
+  else
+    AC_DEFINE(HAVE_OPENSSL)
+    openssl_cflags=`pkg-config --cflags openssl`
+    if test "$?" = 0; then
+      XE_PREPEND("$openssl_cflags", CPPFLAGS)
+    fi
+    openssl_libs=`pkg-config --libs openssl`
+    if test "$?" = 0; then
+      XE_PREPEND("$openssl_libs", LDFLAGS)
+    fi
+    AC_CHECK_FUNC(X509_check_host, [AC_DEFINE(HAVE_X509_CHECK_HOST)])
+  fi
+fi
+
 dnl Unfortunately, just because we can link doesn't mean we can run.
 dnl One of the above link tests may have succeeded but caused resulting
 dnl executables to fail to run.  Also any tests using AC_RUN_IFELSE will
@@ -5959,12 +6017,18 @@
 test -n "$with_mail_locking" && echo "  Compiling in support for \"$with_mail_locking\" mail spool file locking method."
 
 echo "
-Other Features:"
+Network:"
 test "$with_ipv6_cname" = no && echo "  Inhibiting IPv6 canonicalization at startup."
 test "$with_tooltalk" = yes && echo "  Compiling in support for ToolTalk."
 test "$with_workshop" = yes && echo "  Compiling in support for Sun WorkShop."
 test "$with_socks" = yes && echo "  Compiling in support for SOCKS."
 test "$with_dnet" = yes && echo "  Compiling in support for DNET."
+test "$with_tls" = nss && echo "  Compiling in support for TLS with NSS."
+test "$with_tls" = gnutls && echo "  Compiling in support for TLS with gnutls."
+test "$with_tls" = openssl && echo "  Compiling in support for TLS with OpenSSL."
+
+echo "
+Other Features:"
 test "$with_modules" = "yes" && echo "  Compiling in support for dynamic shared object modules."
 test "$with_bignum" = "gmp" && echo "  Compiling in support for more number types using the GNU MP library."
 test "$with_bignum" = "mpir" && echo "  Compiling in support for more number types using the MPIR library."
--- a/src/Makefile.in.in	Thu May 15 12:25:25 2014 -0600
+++ b/src/Makefile.in.in	Thu May 15 13:23:32 2014 -0600
@@ -296,8 +296,8 @@
  rangetab.o realpath.o redisplay.o redisplay-output.o regex.o\
  search.o select.o sequence.o $(sheap_objs) $(shlib_objs) signal.o sound.o\
  specifier.o strftime.o $(sunpro_objs) symbols.o syntax.o sysdep.o\
- text.o $(tooltalk_objs) $(tty_objs) undo.o unicode.o $(x_objs) $(x_gui_objs)\
- widget.o window.o $(win32_objs)
+ text.o tls.o $(tooltalk_objs) $(tty_objs) undo.o unicode.o \
+ $(x_objs) $(x_gui_objs) widget.o window.o $(win32_objs)
 
 obj_rtl = $(objs:.o=.c.rtl)
 
diff -r acf1c26e3019 src/config.h.in
--- a/src/config.h.in	Thu May 15 12:25:25 2014 -0600
+++ b/src/config.h.in	Thu May 15 13:23:32 2014 -0600
@@ -499,6 +499,15 @@
 /* Compile in support for SOCKS? */
 #undef HAVE_SOCKS
 
+/* Compile in support for TLS */
+#undef WITH_TLS
+#undef HAVE_NSS
+#undef HAVE_GNUTLS
+#undef HAVE_GNUTLS_CERTIFICATE_VERIFICATION_STATUS_PRINT
+#undef HAVE_GNUTLS_CERTIFICATE_VERIFY_PEERS3
+#undef HAVE_OPENSSL
+#undef HAVE_X509_CHECK_HOST
+
 /* Compile in support for X pixmaps via the `xpm' library? */
 #undef HAVE_XPM
 #undef FOR_MSW
diff -r acf1c26e3019 src/console-tty.c
--- a/src/console-tty.c	Thu May 15 12:25:25 2014 -0600
+++ b/src/console-tty.c	Thu May 15 13:23:32 2014 -0600
@@ -137,7 +137,8 @@
     }
 
   /* set_descriptor_non_blocking (tty_con->infd); */
-  tty_con->instream  = make_filedesc_input_stream  (tty_con->infd,  0, -1, 0);
+  tty_con->instream  = make_filedesc_input_stream  (tty_con->infd,  0, -1, 0,
+						    NULL);
   Lstream_set_buffering (XLSTREAM (tty_con->instream), LSTREAM_UNBUFFERED, 0);
   tty_con->instream =
     make_coding_input_stream (XLSTREAM (tty_con->instream),
@@ -145,7 +146,8 @@
 			      CODING_DECODE,
 			      LSTREAM_FL_READ_ONE_BYTE_AT_A_TIME);
   Lstream_set_buffering (XLSTREAM (tty_con->instream), LSTREAM_UNBUFFERED, 0);
-  tty_con->outstream = make_filedesc_output_stream (tty_con->outfd, 0, -1, 0);
+  tty_con->outstream = make_filedesc_output_stream (tty_con->outfd, 0, -1, 0,
+						    NULL);
   tty_con->outstream =
     make_coding_output_stream (XLSTREAM (tty_con->outstream),
 			       get_coding_system_for_text_file (Qterminal, 0),
diff -r acf1c26e3019 src/doc.c
--- a/src/doc.c	Thu May 15 12:25:25 2014 -0600
+++ b/src/doc.c	Thu May 15 13:23:32 2014 -0600
@@ -72,7 +72,7 @@
       goto done;
     }
 
-  fdstream = make_filedesc_input_stream (fd, 0, -1, 0);
+  fdstream = make_filedesc_input_stream (fd, 0, -1, 0, NULL);
   Lstream_set_buffering (XLSTREAM (fdstream), LSTREAM_UNBUFFERED, 0);
   instream =
     make_coding_input_stream
@@ -187,7 +187,7 @@
       goto done;
     }
 
-  fdstream = make_filedesc_input_stream (fd, 0, -1, 0);
+  fdstream = make_filedesc_input_stream (fd, 0, -1, 0, NULL);
   Lstream_set_buffering (XLSTREAM (fdstream), LSTREAM_UNBUFFERED, 0);
   instream =
     make_coding_input_stream
diff -r acf1c26e3019 src/emacs.c
--- a/src/emacs.c	Thu May 15 12:25:25 2014 -0600
+++ b/src/emacs.c	Thu May 15 13:23:32 2014 -0600
@@ -437,6 +437,7 @@
 #include "sysfile.h"
 #include "systime.h"
 #include "sysproc.h" /* for qxe_getpid() */
+#include "tls.h"
 
 #ifdef QUANTIFY
 #include <quantify.h>
@@ -1605,6 +1606,7 @@
       syms_of_scrollbar ();
 #endif
       syms_of_text ();
+      syms_of_tls ();
 #ifdef HAVE_TOOLBARS
       syms_of_toolbar ();
 #endif
@@ -2215,6 +2217,7 @@
       vars_of_symbols ();
       vars_of_syntax ();
       vars_of_text ();
+      vars_of_tls ();
 #ifdef HAVE_TOOLBARS
       vars_of_toolbar ();
 #endif
@@ -2677,6 +2680,8 @@
   init_device_tty ();
 #endif
   init_console_stream (restart); /* Create the first console */
+  if (initialized && !restart)
+    init_tls ();
 
   /* try to get the actual pathname of the exec file we are running */
   if (!restart)
diff -r acf1c26e3019 src/event-stream.c
--- a/src/event-stream.c	Thu May 15 12:25:25 2014 -0600
+++ b/src/event-stream.c	Thu May 15 13:23:32 2014 -0600
@@ -4848,7 +4848,8 @@
 		     CREAT_MODE);
       if (fd < 0)
 	report_file_error ("Unable to create dribble file", filename);
-      Vdribble_file = make_filedesc_output_stream (fd, 0, 0, LSTR_CLOSING);
+      Vdribble_file = make_filedesc_output_stream (fd, 0, 0, LSTR_CLOSING,
+						   NULL);
 #ifdef MULE
       Vdribble_file =
 	make_coding_output_stream
diff -r acf1c26e3019 src/event-unixoid.c
--- a/src/event-unixoid.c	Thu May 15 12:25:25 2014 -0600
+++ b/src/event-unixoid.c	Thu May 15 13:23:32 2014 -0600
@@ -357,6 +357,7 @@
 					USID* err_usid,
 					int flags)
 {
+  tls_state_t *tls_state;
   int infd, outfd, errfd;
   /* Decode inhandle and outhandle. Their meaning depends on
      the process implementation being used. */
@@ -366,17 +367,22 @@
   outfd = (EMACS_INT) outhandle;
   errfd = (EMACS_INT) errhandle;
 
+  tls_state = (flags & STREAM_USE_TLS) ? (tls_state_t *) inhandle : NULL;
+
   *instream = (infd >= 0
-	       ? make_filedesc_input_stream (infd, 0, -1, 0)
+	       ? make_filedesc_input_stream (infd, 0, -1,
+					     tls_state ? LSTR_BLOCKED_OK : 0,
+					     tls_state)
 	       : Qnil);
 
   *outstream = (outfd >= 0
-		? make_filedesc_output_stream (outfd, 0, -1, LSTR_BLOCKED_OK)
+		? make_filedesc_output_stream (outfd, 0, -1, LSTR_BLOCKED_OK,
+					       tls_state)
 		: Qnil);
 
   *errstream = (errfd >= 0
-	       ? make_filedesc_input_stream (errfd, 0, -1, 0)
-	       : Qnil);
+		? make_filedesc_input_stream (errfd, 0, -1, 0, tls_state)
+		: Qnil);
 
   /* FLAGS is process->pty_flag for UNIX_PROCESSES */
   if ((flags & STREAM_PTY_FLUSHING) && outfd >= 0)
diff -r acf1c26e3019 src/events.h
--- a/src/events.h	Thu May 15 12:25:25 2014 -0600
+++ b/src/events.h	Thu May 15 13:23:32 2014 -0600
@@ -72,6 +72,7 @@
 /* Flags for create_io_streams_cb() FLAGS parameter */
 #define STREAM_PTY_FLUSHING		0x0001
 #define STREAM_NETWORK_CONNECTION	0x0002
+#define STREAM_USE_TLS			0x0004
 
 extern struct event_stream *event_stream;
 
diff -r acf1c26e3019 src/file-coding.c
--- a/src/file-coding.c	Thu May 15 12:25:25 2014 -0600
+++ b/src/file-coding.c	Thu May 15 13:23:32 2014 -0600
@@ -4342,7 +4342,7 @@
 	goto badopen;
     }
 
-  lstream = make_filedesc_input_stream (fd, 0, -1, 0);
+  lstream = make_filedesc_input_stream (fd, 0, -1, 0, NULL);
   Lstream_set_buffering (XLSTREAM (lstream), LSTREAM_UNBUFFERED, 0);
   nread = Lstream_read (XLSTREAM (lstream), buf, sizeof (buf));
   err = Lstream_errno (XLSTREAM (lstream));
diff -r acf1c26e3019 src/fileio.c
--- a/src/fileio.c	Thu May 15 12:25:25 2014 -0600
+++ b/src/fileio.c	Thu May 15 13:23:32 2014 -0600
@@ -3177,7 +3177,7 @@
     Charbpos cur_point = BUF_PT (buf);
     struct gcpro ngcpro1;
     Lisp_Object stream = make_filedesc_input_stream (fd, 0, total,
-						     LSTR_ALLOW_QUIT);
+						     LSTR_ALLOW_QUIT, NULL);
     Charcount last_tell = -1;
 
     NGCPRO1 (stream);
@@ -3516,7 +3516,7 @@
        that need to be made, and there could be a large latency
        for each request.  So I've increased the buffer size
        to 64K.) */
-    outstream = make_filedesc_output_stream (desc, 0, -1, 0);
+    outstream = make_filedesc_output_stream (desc, 0, -1, 0, NULL);
     Lstream_set_buffering (XLSTREAM (outstream),
 			   LSTREAM_BLOCKN_BUFFERED, 65536);
     outstream =
diff -r acf1c26e3019 src/gpmevent.c
--- a/src/gpmevent.c	Thu May 15 12:25:25 2014 -0600
+++ b/src/gpmevent.c	Thu May 15 13:23:32 2014 -0600
@@ -244,7 +244,8 @@
    ** done.
    */
   output_stream = make_resizing_buffer_output_stream ();
-  terminal_stream = make_filedesc_input_stream (fd, 0, -1, LSTR_BLOCKED_OK);
+  terminal_stream = make_filedesc_input_stream (fd, 0, -1, LSTR_BLOCKED_OK,
+						NULL);
   output_string = Qnil;
 
   /* #### We should arguably use a specbind() and an unwind routine here,
diff -r acf1c26e3019 src/lisp.h
--- a/src/lisp.h	Thu May 15 12:25:25 2014 -0600
+++ b/src/lisp.h	Thu May 15 13:23:32 2014 -0600
@@ -5768,6 +5768,8 @@
 Bytecount fast_lisp_string_match (Lisp_Object, Lisp_Object);
 extern Fixnum warn_about_possibly_incompatible_back_references;
 
+/* Define in sequence.c */
+EXFUN (Ffill, MANY);
 
 /* Defined in signal.c */
 void init_interrupts_late (void);
diff -r acf1c26e3019 src/lread.c
--- a/src/lread.c	Thu May 15 12:25:25 2014 -0600
+++ b/src/lread.c	Thu May 15 13:23:32 2014 -0600
@@ -714,7 +714,7 @@
     struct gcpro ngcpro1;
 
     NGCPRO1 (lispstream);
-    lispstream = make_filedesc_input_stream (fd, 0, -1, LSTR_CLOSING);
+    lispstream = make_filedesc_input_stream (fd, 0, -1, LSTR_CLOSING, NULL);
     /* 64K is used for normal files; 8K should be OK here because Lisp
        files aren't really all that big. */
     Lstream_set_buffering (XLSTREAM (lispstream), LSTREAM_BLOCKN_BUFFERED,
diff -r acf1c26e3019 src/lstream.c
--- a/src/lstream.c	Thu May 15 12:25:25 2014 -0600
+++ b/src/lstream.c	Thu May 15 13:23:32 2014 -0600
@@ -1117,6 +1117,7 @@
 
 struct filedesc_stream
 {
+  tls_state_t *state;
   int fd;
   int pty_max_bytes;
   Ibyte eof_char;
@@ -1142,11 +1143,12 @@
    ignored when writing); -1 for unlimited. */
 static Lisp_Object
 make_filedesc_stream_1 (int filedesc, int offset, int count, int flags,
-			const char *mode)
+			tls_state_t *state, const char *mode)
 {
   Lstream *lstr = Lstream_new (lstream_filedesc, mode);
   struct filedesc_stream *fstr = FILEDESC_STREAM_DATA (lstr);
-  fstr->fd = filedesc;
+  fstr->state = state;
+  fstr->fd = state ? tls_get_fd (state) : filedesc;
   fstr->closing      = !!(flags & LSTR_CLOSING);
   fstr->allow_quit   = !!(flags & LSTR_ALLOW_QUIT);
   fstr->blocked_ok   = !!(flags & LSTR_BLOCKED_OK);
@@ -1154,7 +1156,7 @@
   fstr->blocking_error_p = 0;
   fstr->chars_sans_newline = 0;
   fstr->saved_errno = 0;
-  fstr->starting_pos = lseek (filedesc, offset, SEEK_CUR);
+  fstr->starting_pos = lseek (fstr->fd, offset, SEEK_CUR);
   fstr->current_pos = max (fstr->starting_pos, 0);
   if (count < 0)
     fstr->end_pos = -1;
@@ -1184,15 +1186,17 @@
  */
 
 Lisp_Object
-make_filedesc_input_stream (int filedesc, int offset, int count, int flags)
+make_filedesc_input_stream (int filedesc, int offset, int count, int flags,
+			    tls_state_t *state)
 {
-  return make_filedesc_stream_1 (filedesc, offset, count, flags, "r");
+  return make_filedesc_stream_1 (filedesc, offset, count, flags, state, "r");
 }
 
 Lisp_Object
-make_filedesc_output_stream (int filedesc, int offset, int count, int flags)
+make_filedesc_output_stream (int filedesc, int offset, int count, int flags,
+			     tls_state_t *state)
 {
-  return make_filedesc_stream_1 (filedesc, offset, count, flags, "w");
+  return make_filedesc_stream_1 (filedesc, offset, count, flags, state, "w");
 }
 
 static Bytecount
@@ -1203,9 +1207,11 @@
   str->saved_errno = 0;
   if (str->end_pos >= 0)
     size = min (size, (Bytecount) (str->end_pos - str->current_pos));
-  nread = str->allow_quit ?
-    read_allowing_quit (str->fd, data, size) :
-    retry_read (str->fd, data, size);
+  nread = str->state
+    ? tls_read (str->state, data, size, str->allow_quit)
+    : (str->allow_quit ?
+       read_allowing_quit (str->fd, data, size) :
+       retry_read (str->fd, data, size));
   if (nread > 0)
     str->current_pos += nread;
   if (nread == 0)
@@ -1268,9 +1274,11 @@
 
   /**** start of non-PTY-crap ****/
   if (size > 0)
-    retval = str->allow_quit ?
-      write_allowing_quit (str->fd, data, size) :
-      retry_write (str->fd, data, size);
+    retval = str->state
+      ? tls_write (str->state, data, size, str->allow_quit)
+      : (str->allow_quit ?
+	 write_allowing_quit (str->fd, data, size) :
+	 retry_write (str->fd, data, size));
   else
     retval = 0;
   if (retval < 0 && errno_would_block_p (errno) && str->blocked_ok)
@@ -1409,7 +1417,9 @@
 filedesc_closer (Lstream *stream)
 {
   struct filedesc_stream *str = FILEDESC_STREAM_DATA (stream);
-  if (str->closing)
+  if (str->state)
+    return tls_close (str->state);
+  else if (str->closing)
     return retry_close (str->fd);
   else
     return 0;
diff -r acf1c26e3019 src/lstream.h
--- a/src/lstream.h	Thu May 15 12:25:25 2014 -0600
+++ b/src/lstream.h	Thu May 15 13:23:32 2014 -0600
@@ -24,6 +24,8 @@
 #ifndef INCLUDED_lstream_h_
 #define INCLUDED_lstream_h_
 
+#include "tls.h"
+
 /************************************************************************/
 /*                     definition of Lstream object                     */
 /************************************************************************/
@@ -464,9 +466,9 @@
 Lisp_Object make_stdio_input_stream (FILE *stream, int flags);
 Lisp_Object make_stdio_output_stream (FILE *stream, int flags);
 Lisp_Object make_filedesc_input_stream (int filedesc, int offset, int count,
-					int flags);
+					int flags, tls_state_t *state);
 Lisp_Object make_filedesc_output_stream (int filedesc, int offset, int count,
-					 int flags);
+					 int flags, tls_state_t *state);
 void filedesc_stream_set_pty_flushing (Lstream *stream,
 				       int pty_max_bytes,
 				       Ibyte eof_char);
diff -r acf1c26e3019 src/process-nt.c
--- a/src/process-nt.c	Thu May 15 12:25:25 2014 -0600
+++ b/src/process-nt.c	Thu May 15 13:23:32 2014 -0600
@@ -1324,7 +1324,8 @@
 static void
 nt_open_network_stream (Lisp_Object name, Lisp_Object host,
 			Lisp_Object service,
-			Lisp_Object protocol, void **vinfd, void **voutfd)
+			Lisp_Object protocol, void **vinfd, void **voutfd,
+			Lisp_Object tls)
 {
   struct sockaddr_in address;
   SOCKET s;
diff -r acf1c26e3019 src/process-unix.c
--- a/src/process-unix.c	Thu May 15 12:25:25 2014 -0600
+++ b/src/process-unix.c	Thu May 15 13:23:32 2014 -0600
@@ -1857,10 +1857,11 @@
 static void
 unix_open_network_stream (Lisp_Object name, Lisp_Object host,
 			  Lisp_Object service, Lisp_Object protocol,
-			  void **vinfd, void **voutfd)
+			  void **vinfd, void **voutfd, Lisp_Object tls)
 {
   EMACS_INT inch;
   EMACS_INT outch;
+  tls_state_t *tls_state = NULL;
   volatile int s = -1;
   volatile int port;
   volatile int retry = 0;
@@ -1960,16 +1961,19 @@
 	int family = address.sin_family;
 #endif
 
-	if (EQ (protocol, Qtcp))
-	  s = socket (family, SOCK_STREAM, 0);
-	else /* EQ (protocol, Qudp) */
-	  s = socket (family, SOCK_DGRAM, 0);
+	if (NILP (tls) || TLS_SETUP_SOCK)
+	  {
+	    if (EQ (protocol, Qtcp))
+	      s = socket (family, SOCK_STREAM, 0);
+	    else /* EQ (protocol, Qudp) */
+	      s = socket (family, SOCK_DGRAM, 0);
 
-	if (s < 0)
-	  {
-	    xerrno = errno;
-	    failed_connect = 0;
-	    continue;
+	    if (s < 0)
+	      {
+		xerrno = errno;
+		failed_connect = 0;
+		continue;
+	      }
 	  }
 
       loop:
@@ -1988,10 +1992,25 @@
 	can_break_system_calls = 1;
 
 #ifdef USE_GETADDRINFO
-	retval = connect (s, lres->ai_addr, lres->ai_addrlen);
+	retval = (NILP (tls) || TLS_SETUP_SOCK)
+	  ? connect (s, lres->ai_addr, lres->ai_addrlen)
+	  : 0;
+	if (retval == 0 && !NILP (tls))
+	  {
+	    tls_state = tls_open (s, host, lres->ai_addr);
+	    retval = (tls_state == NULL) ? -1 : 0;
+	  }
 #else
-	retval = connect (s, (struct sockaddr *) &address, sizeof (address));
+	retval = (NILP (tls) || TLS_SETUP_SOCK)
+	  ? connect (s, (struct sockaddr *) &address, sizeof (address))
+	  : 0;
+	if (retval == 0 && !NILP (tls))
+	  {
+	    tls_state = tls_open (s, host, (struct sockaddr *) &address);
+	    retval = (tls_state == NULL) ? -1 : 0;
+	  }
 #endif
+
 	can_break_system_calls = 0;
 	if (retval == -1 && errno != EISCONN)
 	  {
@@ -2020,8 +2039,11 @@
 	      }
 
 	    failed_connect = 1;
-	    retry_close (s);
-            s = -1;
+	    if (NILP (tls) || TLS_SETUP_SOCK)
+	      {
+		retry_close (s);
+		s = -1;
+	      }
 	    continue;
 	  }
 
@@ -2052,7 +2074,7 @@
     freeaddrinfo (res);
 #endif
 
-    if (s < 0)
+    if ((NILP (tls) && s < 0) || (!NILP (tls) && tls_state == NULL))
       {
 	errno = xerrno;
 
@@ -2064,6 +2086,14 @@
       }
   }
 
+  if (!NILP (tls))
+    {
+      set_socket_nonblocking_maybe (tls_get_fd (tls_state), port, "tcp");
+      *vinfd = (void *) tls_state;
+      *voutfd = (void *) tls_state;
+      return;
+    }
+
   inch = s;
   outch = dup (s);
   if (outch < 0)
diff -r acf1c26e3019 src/process.c
--- a/src/process.c	Thu May 15 12:25:25 2014 -0600
+++ b/src/process.c	Thu May 15 13:23:32 2014 -0600
@@ -844,7 +844,7 @@
    connection has no PID; you cannot signal it.  All you can do is
    deactivate and close it via delete-process */
 
-DEFUN ("open-network-stream-internal", Fopen_network_stream_internal, 4, 5,
+DEFUN ("open-network-stream-internal", Fopen_network_stream_internal, 4, 6,
        0, /*
 Open a TCP connection for a service to a host.
 Return a process object to represent the connection.
@@ -863,6 +863,9 @@
 Optional fifth arg PROTOCOL is a network protocol.  Currently only `tcp'
  (Transmission Control Protocol) and `udp' (User Datagram Protocol) are
  supported.  When omitted, `tcp' is assumed.
+Optional sixth arg TLS is a boolean.  If it is NIL, a standard network stream
+ is opened.  If it is non-NIL, a TLS network stream is opened if TLS support
+ is available; otherwise an error is signaled.
 
 Output via `process-send-string' and input via buffer or filter (see
 `set-process-filter') are stream-oriented.  That means UDP datagrams are
@@ -871,12 +874,13 @@
 are usually fine.)  Note further that the UDP protocol does not guard
 against lost packets.
 */
-       (name, buffer, host, service, protocol))
+       (name, buffer, host, service, protocol, tls))
 {
   /* This function can GC */
   Lisp_Object process = Qnil;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, ngcpro1;
   void *inch, *outch;
+  int flags;
 
   GCPRO5 (name, buffer, host, service, protocol);
   CHECK_STRING (name);
@@ -889,7 +893,7 @@
   /* Since this code is inside HAVE_SOCKETS, existence of
      open_network_stream is mandatory */
   PROCMETH (open_network_stream, (name, host, service, protocol,
-				  &inch, &outch));
+				  &inch, &outch, tls));
 
   if (!NILP (buffer))
     buffer = Fget_buffer_create (buffer);
@@ -898,9 +902,11 @@
 
   XPROCESS (process)->pid = Fcons (service, host);
   XPROCESS (process)->buffer = buffer;
+  flags = STREAM_NETWORK_CONNECTION;
+  if (!NILP (tls))
+    flags |= STREAM_USE_TLS;
   init_process_io_handles (XPROCESS (process), (void *) inch, (void *) outch,
-			   (void *) -1,
-			   STREAM_NETWORK_CONNECTION);
+			   (void *) -1, flags);
 
   event_stream_select_process (XPROCESS (process), 1, 1);
 
diff -r acf1c26e3019 src/procimpl.h
--- a/src/procimpl.h	Thu May 15 12:25:25 2014 -0600
+++ b/src/procimpl.h	Thu May 15 13:23:32 2014 -0600
@@ -49,7 +49,7 @@
 #ifdef HAVE_SOCKETS
   void (*open_network_stream) (Lisp_Object name, Lisp_Object host,
 			       Lisp_Object service, Lisp_Object protocol,
-			       void** vinfd, void** voutfd);
+			       void** vinfd, void** voutfd, Lisp_Object tls);
 #ifdef HAVE_MULTICAST
   void (*open_multicast_group) (Lisp_Object name, Lisp_Object dest,
 				Lisp_Object port, Lisp_Object ttl,
diff -r acf1c26e3019 src/tls.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tls.c	Thu May 15 13:23:32 2014 -0600
@@ -0,0 +1,1043 @@
+/* Transport Layer Security implementation.
+   Copyright (C) 2014 Jerry James
+
+This file is part of XEmacs.
+
+XEmacs is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs.  If not, see <http://www.gnu.org/licenses/>. */
+
+/* Synched up with: Not in FSF. */
+
+/* Written by Jerry James. */
+
+#include <config.h>
+#include "lisp.h"
+#include "tls.h"
+#include <errno.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+static Lisp_Object prompt;
+static Lisp_Object Qread_password;
+Lisp_Object Qtls_error;
+
+#ifdef HAVE_NSS
+#include <prinit.h>
+#include <private/pprio.h>
+#include <nss.h>
+#include <pk11pub.h>
+#include <secmod.h>
+#include <ssl.h>
+
+#define NSS_ERRSTR build_extstring (PR_ErrorToName (PR_GetError ()), Qnative)
+
+/* 0 == initialization of NSPR or NSS failed
+ * 1 == the NSPR and NSS libraries have been initialized successfully
+ */
+static int nss_inited;
+
+/* The model file descriptors, for IPv4 and IPv6 */
+static PRFileDesc *nss_model4;
+static PRFileDesc *nss_model6;
+
+int
+tls_get_fd (tls_state_t *state)
+{
+  return PR_FileDesc2NativeHandle (state->tls_file_desc);
+}
+
+Bytecount
+tls_read (tls_state_t *state, unsigned char *data, Bytecount size,
+	  unsigned int allow_quit)
+{
+  if (allow_quit)
+    QUIT;
+  return (Bytecount) PR_Recv (state->tls_file_desc, data, size, 0, 0);
+}
+
+Bytecount
+tls_write (tls_state_t *state, const unsigned char *data, Bytecount size,
+	   unsigned int allow_quit)
+{
+  if (allow_quit)
+    QUIT;
+  return (Bytecount) PR_Send (state->tls_file_desc, data, size, 0, 0);
+}
+
+int
+tls_close (tls_state_t *state)
+{
+  if (--state->tls_refcount == 0)
+    {
+      PRStatus status = PR_Shutdown (state->tls_file_desc, PR_SHUTDOWN_BOTH);
+      PR_Close (state->tls_file_desc);
+      free (state);
+      return (int) status;
+     }
+  return 0;
+}
+
+tls_state_t *
+tls_open (int UNUSED (s), Lisp_Object hostname, struct sockaddr *addr)
+{
+  PRNetAddr pr_addr;
+  tls_state_t *nspr;
+  Extbyte *c_hostname;
+  const int val = 1;
+
+  /* Disable Nagle's algorithm */
+  setsockopt (s, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+
+  /* Convert the hostname to Lisp */
+  if (STRINGP (hostname))
+    c_hostname = LISP_STRING_TO_EXTERNAL (hostname, Qunix_host_name_encoding);
+  else
+    c_hostname = NULL;
+
+  if (!nss_inited)
+    {
+      warn_when_safe (Qtls_error, Qerror, "Cannot use NSS functions");
+      return NULL;
+    }
+
+  /* Create the socket */
+  nspr = xmalloc (sizeof (*nspr));
+  nspr->tls_refcount = 2;
+  nspr->tls_file_desc =
+    SSL_ImportFD ((addr->sa_family == AF_INET) ? nss_model4 : nss_model6,
+		   PR_OpenTCPSocket (addr->sa_family));
+  if (nspr->tls_file_desc == NULL)
+    {
+      free (nspr);
+      warn_when_safe (Qtls_error, Qerror, "NSS unable to open socket: %s",
+		      PR_ErrorToName (PR_GetError ()));
+      return NULL;
+    }
+
+  /* Connect to the server */
+  memset (&pr_addr, 0, sizeof (pr_addr));
+  if (addr->sa_family == AF_INET)
+    {
+      struct sockaddr_in *in_addr = (struct sockaddr_in *) addr;
+      pr_addr.inet.family = in_addr->sin_family;
+      pr_addr.inet.port = in_addr->sin_port;
+      pr_addr.inet.ip = in_addr->sin_addr.s_addr;
+    }
+  else
+    {
+      struct sockaddr_in6 *in_addr = (struct sockaddr_in6 *) addr;
+      pr_addr.ipv6.family = in_addr->sin6_family;
+      pr_addr.ipv6.port = in_addr->sin6_port;
+      pr_addr.ipv6.flowinfo = in_addr->sin6_flowinfo;
+      memcpy (pr_addr.ipv6.ip.pr_s6_addr, in_addr->sin6_addr.s6_addr,
+	      sizeof (pr_addr.ipv6.ip.pr_s6_addr));
+      pr_addr.ipv6.scope_id = in_addr->sin6_scope_id;
+    }
+  if (PR_Connect (nspr->tls_file_desc, &pr_addr, PR_INTERVAL_NO_TIMEOUT)
+		 != PR_SUCCESS)
+    {
+      if (PR_GetError () == PR_IN_PROGRESS_ERROR)
+	{
+	  PRPollDesc pollset[2];
+
+	  pollset[0].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+	  pollset[0].out_flags = 0;
+	  pollset[0].fd = nspr->tls_file_desc;
+	  for (;;)
+	    {
+	      PRInt32 num_fds = PR_Poll (pollset, 1, PR_INTERVAL_NO_TIMEOUT);
+	      if (num_fds < 0)
+		{
+		  free (nspr);
+		  PR_Close (nspr);
+		  warn_when_safe (Qtls_error, Qerror,
+				  "NSS unable to connect: %s",
+				  PR_ErrorToName (PR_GetError ()));
+		  return NULL;
+		}
+	      if (PR_GetConnectStatus (pollset) == PR_SUCCESS)
+		break;
+	    }
+	}
+      else
+	{
+	  free (nspr);
+	  PR_Close (nspr);
+	  warn_when_safe (Qtls_error, Qerror, "NSS unable to connect: %s",
+			  PR_ErrorToName (PR_GetError ()));
+	  return NULL;
+	}
+    }
+
+  /* Perform the handshake */
+  if (SSL_ResetHandshake (nspr->tls_file_desc, PR_FALSE) != SECSuccess)
+    {
+      free (nspr);
+      PR_Close (nspr);
+      warn_when_safe (Qtls_error, Qerror, "NSS unable to reset handshake: %s",
+		      PR_ErrorToName (PR_GetError ()));
+      errno = EACCES;
+      return NULL;
+    }
+  if (c_hostname != NULL &&
+      SSL_SetURL (nspr->tls_file_desc, c_hostname) != SECSuccess)
+    {
+      free (nspr);
+      PR_Close (nspr);
+      warn_when_safe (Qtls_error, Qerror, "NSS unable to set URL (%s): %s",
+		      c_hostname, PR_ErrorToName (PR_GetError ()));
+      errno = EACCES;
+      return NULL;
+    }
+  if (SSL_ForceHandshake (nspr->tls_file_desc) != SECSuccess)
+    {
+      free (nspr);
+      PR_Close (nspr);
+      warn_when_safe (Qtls_error, Qerror,
+		      "NSS unable to complete handshake: %s",
+		      PR_ErrorToName (PR_GetError ()));
+      errno = EACCES;
+      return NULL;
+    }
+  return nspr;
+}
+
+/* Function that gathers passwords for PKCS #11 tokens. */
+static char *
+nss_pk11_password (PK11SlotInfo *slot, PRBool retry, void * UNUSED (arg))
+{
+  Lisp_Object lsp_password, args[2];
+  Extbyte *c_password, *nss_password;
+  const Extbyte *token_name;
+
+  if (retry)
+    return NULL;
+
+  token_name = PK11_GetTokenName (slot);
+  if (token_name == NULL)
+    token_name = "security token";
+  lsp_password =
+    call1 (Qread_password, concat2 (prompt,
+				    build_extstring (token_name, Qnative)));
+  c_password = LISP_STRING_TO_EXTERNAL (lsp_password, Qnative);
+  nss_password = PL_strdup (c_password);
+
+  /* Wipe out the password on the stack and in the Lisp string */
+  args[0] = lsp_password;
+  args[1] = make_char ('*');
+  Ffill (2, args);
+  memset (c_password, '*', strlen (c_password));
+  return nss_password;
+}
+
+void
+init_tls (void)
+{
+  SECMODModule *module;
+
+  /* Check that we are using compatible versions */
+  if (PR_VersionCheck(PR_VERSION) == PR_FALSE)
+    signal_error (Qinternal_error,
+		  "NSPR version mismatch: expected " PR_VERSION, Qnil);
+  if (NSS_VersionCheck(NSS_VERSION) == PR_FALSE)
+    signal_error (Qinternal_error,
+		  "NSS version mismatch: expected " NSS_VERSION, Qnil);
+
+  /* Basic initialization of both libraries */
+  PR_Init (PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+  if (NSS_Init ("sql:/etc/pki/nssdb") != SECSuccess)
+    signal_error (Qtls_error, "Error initializing NSS", NSS_ERRSTR);
+
+  /* Set the cipher suite policy */
+  if (NSS_SetDomesticPolicy() != SECSuccess)
+    signal_error (Qtls_error, "NSS unable to set policy", NSS_ERRSTR);
+
+  /* Load the root certificates */
+  module = SECMOD_LoadUserModule ("library=libnssckbi.so name=\"Root Certs\"",
+				  NULL, PR_FALSE);
+  if (module == NULL || !module->loaded)
+    signal_error (Qtls_error, "NSS unable to load root certificates",
+		  NSS_ERRSTR);
+
+  /* Setup password gathering */
+  PK11_SetPasswordFunc (nss_pk11_password);
+
+  /* Create the model file descriptors */
+  nss_model4 = SSL_ImportFD (NULL, PR_OpenTCPSocket (PR_AF_INET));
+  nss_model6 = SSL_ImportFD (NULL, PR_OpenTCPSocket (PR_AF_INET6));
+  if (nss_model4 == NULL && nss_model6 == NULL)
+    signal_error (Qtls_error, "NSS cannot create model sockets", NSS_ERRSTR);
+
+  /* Set options on the IPv4 socket */
+  if (nss_model4 != NULL)
+    {
+      if (SSL_OptionSet (nss_model4, SSL_SECURITY, PR_TRUE) != SECSuccess)
+	signal_error (Qtls_error, "NSS cannot enable IPv4 model", NSS_ERRSTR);
+      if (SSL_OptionSet (nss_model4, SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess)
+	signal_error (Qtls_error, "NSS unable to disable SSLv2", NSS_ERRSTR);
+      if (SSL_OptionSet (nss_model4, SSL_V2_COMPATIBLE_HELLO, PR_FALSE)
+	  != SECSuccess)
+	signal_error (Qtls_error, "NSS unable to disable SSLv2 handshake",
+		      NSS_ERRSTR);
+      if (SSL_OptionSet (nss_model4, SSL_ENABLE_DEFLATE, PR_FALSE)
+	  != SECSuccess)
+	signal_error (Qtls_error, "NSS unable to disable deflate", NSS_ERRSTR);
+      if (SSL_OptionSet (nss_model4, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE)
+	  != SECSuccess)
+	signal_error (Qtls_error, "NSS unable to ensable handshake as client",
+		      NSS_ERRSTR);
+    }
+  if (nss_model6 != NULL)
+    {
+      if (SSL_OptionSet (nss_model6, SSL_SECURITY, PR_TRUE) != SECSuccess)
+	signal_error (Qtls_error, "NSS cannot enable IPv6 model", NSS_ERRSTR);
+      if (SSL_OptionSet (nss_model6, SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess)
+	signal_error (Qtls_error, "NSS unable to disable SSLv2", NSS_ERRSTR);
+      if (SSL_OptionSet (nss_model6, SSL_V2_COMPATIBLE_HELLO, PR_FALSE)
+	  != SECSuccess)
+	signal_error (Qtls_error, "NSS unable to disable SSLv2 handshake",
+		      NSS_ERRSTR);
+      if (SSL_OptionSet (nss_model6, SSL_ENABLE_DEFLATE, PR_FALSE) != SECSuccess)
+	signal_error (Qtls_error, "NSS unable to disable deflate", NSS_ERRSTR);
+      if (SSL_OptionSet (nss_model6, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE)
+	  != SECSuccess)
+	signal_error (Qtls_error, "NSS unable to ensable handshake as client",
+		      NSS_ERRSTR);
+    }
+
+  nss_inited = 1;
+}
+#endif /* HAVE_NSS */
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/pkcs11.h>
+#include <gnutls/x509.h>
+#include "sysfile.h"
+
+#define GNUTLS_ERRSTR(err) build_extstring (gnutls_strerror (err), Qnative)
+
+/* The global credentials object */
+static gnutls_certificate_credentials_t global_cred;
+
+int
+tls_get_fd (tls_state_t *state)
+{
+  return (int)(unsigned long)gnutls_transport_get_ptr (state->tls_session);
+}
+
+Bytecount
+tls_read (tls_state_t *state, unsigned char *data, Bytecount size,
+	  unsigned int allow_quit)
+{
+  ssize_t bytes;
+
+  if (allow_quit)
+    QUIT;
+  bytes = gnutls_record_recv (state->tls_session, data, size);
+  if (bytes == GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
+    bytes = 0;
+  return (Bytecount) bytes;
+}
+
+Bytecount
+tls_write (tls_state_t *state, const unsigned char *data, Bytecount size,
+	   unsigned int allow_quit)
+{
+  ssize_t bytes;
+
+  do
+    {
+      if (allow_quit)
+	QUIT;
+      bytes = gnutls_record_send (state->tls_session, data, size);
+    }
+  while (bytes == GNUTLS_E_INTERRUPTED);
+  if (bytes == GNUTLS_E_AGAIN)
+    {
+      bytes = -1;
+      errno = EAGAIN;
+    }
+  return (Bytecount) bytes;
+}
+
+int
+tls_close (tls_state_t *state)
+{
+  if (--state->tls_refcount == 0)
+    {
+      int fd, err;
+
+      fd = (int)(unsigned long)gnutls_transport_get_ptr (state->tls_session);
+      gnutls_bye (state->tls_session, GNUTLS_SHUT_RDWR);
+      err = retry_close (fd);
+      gnutls_deinit (state->tls_session);
+      free (state);
+      return err;
+     }
+  return 0;
+}
+
+tls_state_t *
+tls_open (int s, Lisp_Object hostname, struct sockaddr * UNUSED (addr))
+{
+#ifndef HAVE_GNUTLS_CERTIFICATE_VERIFY_PEERS3
+  gnutls_x509_crt_t cert;
+#endif
+  tls_state_t *gnutls;
+  Extbyte *c_hostname;
+  const char *errptr = NULL;
+  const gnutls_datum_t *certs;
+  unsigned int status, certslen = 0U;
+  int err;
+  const int val = 1;
+
+  /* Disable Nagle's algorithm */
+  setsockopt (s, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+
+  /* Create the state object */
+  gnutls = xmalloc (sizeof (*gnutls));
+  gnutls->tls_refcount = 2;
+
+  /* Initialize the session object */
+  err = gnutls_init (&gnutls->tls_session, GNUTLS_CLIENT);
+  if (err != GNUTLS_E_SUCCESS)
+    {
+      free (gnutls);
+      warn_when_safe (Qtls_error, Qerror, "GNUTLS error in gnutls_init: %s",
+		      gnutls_strerror (err));
+      errno = EACCES;
+      return NULL;
+    }
+
+  /* Configure the cipher preferences */
+  err = gnutls_priority_set_direct (gnutls->tls_session, "NORMAL", &errptr);
+  if (err != GNUTLS_E_SUCCESS)
+    {
+      free (gnutls);
+      warn_when_safe (Qtls_error, Qerror,
+		      "GNUTLS error in gnutls_priority_set_direct: %s at %s",
+		      gnutls_strerror (err), errptr);
+      errno = EACCES;
+      return NULL;
+    }
+
+  /* Install the trusted certificates */
+  err = gnutls_credentials_set (gnutls->tls_session, GNUTLS_CRD_CERTIFICATE,
+				global_cred);
+  if (err != GNUTLS_E_SUCCESS)
+    {
+      free (gnutls);
+      warn_when_safe (Qtls_error, Qerror,
+		      "GNUTLS error in gnutls_credentials_set: %s",
+		      gnutls_strerror (err));
+      errno = EACCES;
+      return NULL;
+    }
+
+  /* Associate the socket with the session object */
+  gnutls_transport_set_ptr (gnutls->tls_session,
+			    (gnutls_transport_ptr_t)(unsigned long)s);
+
+  /* Set the server name */
+  if (STRINGP (hostname))
+    {
+      c_hostname =
+	LISP_STRING_TO_EXTERNAL (hostname, Qunix_host_name_encoding);
+      err = gnutls_server_name_set (gnutls->tls_session, GNUTLS_NAME_DNS,
+				    c_hostname, strlen (c_hostname));
+      if (err != GNUTLS_E_SUCCESS)
+	{
+	  free (gnutls);
+	  warn_when_safe (Qtls_error, Qerror,
+			  "GNUTLS error in gnutls_server_name_set: %s",
+			  gnutls_strerror (err));
+	  errno = EACCES;
+	  return NULL;
+	}
+    }
+  else
+    {
+      c_hostname = NULL;
+    }
+
+  /* Perform the handshake */
+  do
+    err = gnutls_handshake (gnutls->tls_session);
+  while (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED);
+  if (err != GNUTLS_E_SUCCESS)
+    {
+      free (gnutls);
+      warn_when_safe (Qtls_error, Qerror,
+		      "GNUTLS error in gnutls_handshake: %s",
+		      gnutls_strerror (err));
+      errno = EACCES;
+      return NULL;
+    }
+
+  /* Get the server certificate chain */
+  certs = gnutls_certificate_get_peers (gnutls->tls_session, &certslen);
+  if (certs == NULL || certslen == 0U)
+    {
+      free (gnutls);
+      warn_when_safe (Qtls_error, Qerror,
+		      "GNUTLS could not get peer certificate: %s",
+		      gnutls_strerror (err));
+      errno = EACCES;
+      return NULL;
+    }
+
+  /* Validate the server certificate chain */
+  status = (unsigned int) -1;
+#ifdef HAVE_GNUTLS_CERTIFICATE_VERIFY_PEERS3
+  err = gnutls_certificate_verify_peers3 (gnutls->tls_session, c_hostname,
+					  &status);
+#else
+  err = gnutls_certificate_verify_peers2 (gnutls->tls_session, &status);
+#endif /* HAVE_GNUTLS_CERTIFICATE_VERIFY_PEERS3 */
+  if (err != GNUTLS_E_SUCCESS)
+    {
+      free (gnutls);
+      warn_when_safe (Qtls_error, Qerror,
+		      "GNUTLS could not verify peer certificate: %s",
+		      gnutls_strerror (err));
+      errno = EACCES;
+      return NULL;
+    }
+  if (status != 0U)
+    {
+      gnutls_datum_t msg;
+
+#ifdef HAVE_GNUTLS_CERTIFICATE_VERIFICATION_STATUS_PRINT
+      int type = gnutls_certificate_type_get (gnutls->tls_session);
+      err =
+	gnutls_certificate_verification_status_print (status, type, &msg, 0);
+#else
+      err = -1;
+#endif /* HAVE_GNUTLS_CERTIFICATE_VERIFICATION_STATUS_PRINT */
+      free (gnutls);
+      if (err == 0)
+	{
+	  warn_when_safe (Qtls_error, Qerror,
+			  "GNUTLS: certificate validation failed: %s",
+			  msg.data);
+	  gnutls_free(msg.data);
+	  errno = EACCES;
+	  return NULL;
+	}
+      else
+	{
+	  warn_when_safe (Qtls_error, Qerror,
+			  "GNUTLS: certificate validation failed with code %u",
+			  status);
+	  errno = EACCES;
+	  return NULL;
+	}
+    }
+
+#ifndef HAVE_GNUTLS_CERTIFICATE_VERIFY_PEERS3
+  /* Match the peer certificate against the host name */
+  err = gnutls_x509_crt_init (&cert);
+  if (err != GNUTLS_E_SUCCESS)
+    {
+      free (gnutls);
+      warn_when_safe (Qtls_error, Qerror,
+		      "GNUTLS error in gnutls_x509_crt_init: %s",
+		      gnutls_strerror (err));
+      errno = EACCES;
+      return NULL;
+    }
+
+  /* The peer certificate is the first certificate in the list */
+  err = gnutls_x509_crt_import (cert, certs, GNUTLS_X509_FMT_DER);
+  if (err != GNUTLS_E_SUCCESS)
+    {
+      free (gnutls);
+      warn_when_safe (Qtls_error, Qerror,
+		      "GNUTLS error in gnutls_x509_crt_import: %s",
+		      gnutls_strerror (err));
+      gnutls_x509_crt_deinit (cert);
+      errno = EACCES;
+      return NULL;
+    }
+  err = gnutls_x509_crt_check_hostname (cert, c_hostname);
+  if (err == 0)
+    {
+      free (gnutls);
+      warn_when_safe (Qtls_error, Qerror,
+		      "GNUTLS: hostname does not match certificate: %s",
+		      gnutls_strerror (err));
+      gnutls_x509_crt_deinit (cert);
+      errno = EACCES;
+      return NULL;
+    }
+  gnutls_x509_crt_deinit (cert);
+#endif /* HAVE_GNUTLS_CERTIFICATE_VERIFY_PEERS3 */
+
+  return gnutls;
+}
+
+/* Function that gathers PKCS #11 passwords. */
+static int
+gnutls_pk11_password (void * UNUSED (userdata), int UNUSED (attempt),
+		      const char *token_url, const char *token_label,
+		      unsigned int UNUSED (flags), char *pin, size_t pin_max)
+{
+  Lisp_Object lsp_password, args[5];
+  Extbyte *c_password;
+  size_t len;
+
+  /* Get the password from the user */
+  args[0] = prompt;
+  args[1] = build_extstring (token_label, Qnative);
+  args[2] = build_ascstring (" (");
+  args[3] = build_extstring (token_url, Qnative);
+  args[4] = build_ascstring (")");
+  lsp_password = call1 (Qread_password, Fconcat (5, args));
+  c_password = LISP_STRING_TO_EXTERNAL (lsp_password, Qnative);
+
+  /* Insert the password */
+  len = strlen (c_password);
+  if (len > pin_max)
+    len = pin_max;
+  memcpy (pin, c_password, len);
+  pin[len] = '\0';
+
+  /* Wipe out the password on the stack and in the Lisp string */
+  args[0] = lsp_password;
+  args[1] = make_char ('*');
+  Ffill (2, args);
+  memset (c_password, '*', strlen (c_password));
+  return GNUTLS_E_SUCCESS;
+}
+
+static void xfree_for_gnutls (void *ptr)
+{
+  /* GnuTLS sometimes tries to free NULL */
+  if (ptr != NULL)
+    xfree (ptr);
+}
+
+void
+init_tls (void)
+{
+  int err = GNUTLS_E_SUCCESS;
+
+  /* Tell gnutls to use our memory allocation functions */
+  gnutls_global_set_mem_functions ((void * (*)(size_t)) xmalloc,
+				   (void * (*)(size_t)) xmalloc,
+				   NULL,
+				   (void * (*)(void *, size_t)) xrealloc,
+				   xfree_for_gnutls);
+
+  /* Initialize the library */
+  err = gnutls_global_init ();
+  if (err != GNUTLS_E_SUCCESS)
+    signal_error (Qtls_error, "gnutls_global_init", GNUTLS_ERRSTR (err));
+
+  /* Load the trusted CA certificates */
+  err = gnutls_certificate_allocate_credentials (&global_cred);
+  if (err != GNUTLS_E_SUCCESS)
+    signal_error (Qtls_error, "gnutls_certificate_allocate_credentials",
+		  GNUTLS_ERRSTR (err));
+  err = gnutls_certificate_set_x509_system_trust (global_cred);
+  if (err == 0)
+    signal_error (Qtls_error, "gnutls: no system certificates found", Qnil);
+  if (err < 0)
+    signal_error (Qtls_error, "gnutls_certificate_set_x509_system_trust",
+		  GNUTLS_ERRSTR (err));
+
+  /* Setup password gathering */
+  gnutls_pkcs11_set_pin_function (gnutls_pk11_password, NULL);
+}
+#endif /* HAVE_GNUTLS */
+
+#ifdef HAVE_OPENSSL
+#include <unistd.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+
+/* The context used to create connections */
+static SSL_CTX *ssl_ctx;
+
+static Lisp_Object
+openssl_error_string (void)
+{
+  Lisp_Object args[5];
+  unsigned long err = ERR_get_error ();
+
+  args[0] = build_ascstring (ERR_lib_error_string (err));
+  args[1] = build_ascstring (":");
+  args[2] = build_ascstring (ERR_func_error_string (err));
+  args[3] = build_ascstring (":");
+  args[4] = build_ascstring (ERR_reason_error_string (err));
+  return Fconcat (5, args);
+}
+
+static unsigned long
+openssl_report_error_stack (const char *msg, const SSL *ssl)
+{
+  unsigned long err = ERR_get_error ();
+  if (err > 0UL)
+    {
+      if (ERR_GET_LIB (err) == ERR_LIB_SSL &&
+	  ERR_GET_REASON (err) == SSL_R_CERTIFICATE_VERIFY_FAILED)
+	{
+	  long cert_err = SSL_get_verify_result (ssl);
+	  warn_when_safe (Qtls_error, Qerror, "%s:%s", msg,
+			  X509_verify_cert_error_string (cert_err));
+	}
+      else
+	{
+	  const char *lib = ERR_lib_error_string (err);
+	  const char *func = ERR_func_error_string (err);
+	  const char *reason = ERR_reason_error_string (err);
+	  warn_when_safe (Qtls_error, Qerror, "%s:%s:%s:%s", msg,
+			  lib == NULL ? "<unknown>" : lib,
+			  func == NULL ? "<unknown>" : func,
+			  reason == NULL ? "<unknown>" : reason);
+	}
+    }
+  return err;
+}
+
+/* Return values:
+ * -1 = fatal error, caller should exit
+ *  0 = no error, caller should continue
+ *  1 = nonfatal error, caller should retry
+ */
+static int
+openssl_report_error_num (const char *msg, const SSL *ssl, int ret, int retry)
+{
+  int errno_copy = errno;
+  int ssl_error = SSL_get_error (ssl, ret);
+  int err;
+
+  switch (ssl_error)
+    {
+    case SSL_ERROR_NONE:
+    case SSL_ERROR_ZERO_RETURN:
+      err = 0;
+      break;
+    case SSL_ERROR_WANT_READ:
+    case SSL_ERROR_WANT_WRITE:
+      err = retry;
+      break;
+    case SSL_ERROR_WANT_CONNECT:
+    case SSL_ERROR_WANT_ACCEPT:
+    case SSL_ERROR_WANT_X509_LOOKUP:
+      err = 1;
+      break;
+    case SSL_ERROR_SYSCALL:
+      if (openssl_report_error_stack (msg, ssl) == 0UL && ret < 0)
+	warn_when_safe (Qtls_error, Qerror, "%s: %s", msg,
+			strerror (errno_copy));
+      err = ret;
+      break;
+    case SSL_ERROR_SSL:
+      openssl_report_error_stack (msg, ssl);
+      err = -1;
+      break;
+    default:
+      warn_when_safe (Qtls_error, Qerror, "%s: error %d", msg, ssl_error);
+      err = -1;
+      break;
+    }
+  errno = errno_copy;
+  return err;
+}
+
+int
+tls_get_fd (tls_state_t *state)
+{
+  return SSL_get_fd (state->tls_connection);
+}
+
+Bytecount
+tls_read (tls_state_t *state, unsigned char *data, Bytecount size,
+	  unsigned int allow_quit)
+{
+  int action, bytes;
+
+  if (SSL_get_shutdown (state->tls_connection))
+    return 0;
+
+  bytes = SSL_read (state->tls_connection, data, size);
+  action = (bytes > 0) ? 0
+    : openssl_report_error_num ("SSL_read", state->tls_connection, bytes, 0);
+  while (bytes <= 0 && action > 0)
+    {
+      if (allow_quit)
+	QUIT;
+      bytes = SSL_read (state->tls_connection, data, size);
+      action = (bytes > 0) ? 0
+	: openssl_report_error_num ("SSL_read", state->tls_connection,
+				    bytes, 0);
+    }
+  return (Bytecount) bytes;
+}
+
+Bytecount
+tls_write (tls_state_t *state, const unsigned char *data, Bytecount size,
+	   unsigned int allow_quit)
+{
+  int action, bytes;
+
+  if (SSL_get_shutdown (state->tls_connection))
+    return 0;
+
+  bytes = SSL_write (state->tls_connection, data, size);
+  action = (bytes > 0) ? 0
+    : openssl_report_error_num ("SSL_write", state->tls_connection, bytes, 0);
+  while (bytes <= 0 && action > 0)
+    {
+      if (allow_quit)
+	QUIT;
+      bytes = SSL_write (state->tls_connection, data, size);
+      action = (bytes > 0) ? 0
+	: openssl_report_error_num ("SSL_write", state->tls_connection,
+				    bytes, 0);
+    }
+  return (Bytecount) bytes;
+}
+
+int
+tls_close (tls_state_t *state)
+{
+  if (--state->tls_refcount == 0)
+    {
+      int err, fd;
+
+      fd = SSL_get_fd (state->tls_connection);
+      if (SSL_get_shutdown (state->tls_connection) == 0)
+	{
+	  err = SSL_shutdown (state->tls_connection);
+	  if (err < 0 && errno == EBADF)
+	    err = 0;
+	  if (err < 0)
+	    openssl_report_error_num ("SSL_shutdown failed",
+				      state->tls_connection, err, 0);
+	}
+      else
+	{
+	  err = 0;
+	}
+      close (fd);
+      SSL_free (state->tls_connection);
+      free (state);
+      return err > 0 ? 0 : err;
+     }
+  return 0;
+}
+
+tls_state_t *
+tls_open (int s, Lisp_Object hostname, struct sockaddr *UNUSED (addr))
+{
+  tls_state_t *openssl;
+  Extbyte *c_hostname;
+  X509 *peer_cert = NULL;
+  const int val = 1;
+  int err;
+  long cert_err;
+
+  /* Disable Nagle's algorithm */
+  setsockopt (s, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+
+  /* Convert the hostname to Lisp */
+  if (STRINGP (hostname))
+    c_hostname = LISP_STRING_TO_EXTERNAL (hostname, Qunix_host_name_encoding);
+  else
+    c_hostname = NULL;
+
+  /* Create the state object */
+  openssl = xmalloc (sizeof (*openssl));
+  openssl->tls_refcount = 2;
+
+  /* Create the connection object */
+  openssl->tls_connection = SSL_new (ssl_ctx);
+  if (openssl->tls_connection == NULL)
+    {
+      openssl_report_error_stack ("SSL_new failed", NULL);
+      goto error;
+    }
+  if (SSL_set_fd (openssl->tls_connection, s) == 0)
+    {
+      openssl_report_error_stack ("SSL_set_fd", openssl->tls_connection);
+      goto error;
+    }
+
+  /* Enable the ServerNameIndication extension */
+  if (c_hostname != NULL &&
+      !SSL_set_tlsext_host_name (openssl->tls_connection, c_hostname))
+    {
+      openssl_report_error_stack ("SSL_set_tlsext_host_name failed",
+				  openssl->tls_connection);
+      goto error;
+    }
+
+  /* Perform the handshake */
+  err = SSL_connect (openssl->tls_connection);
+  while (err != 1)
+    {
+      int action = openssl_report_error_num ("SSL_connect failed",
+					     openssl->tls_connection, err, 1);
+      if (action < 0)
+	goto error;
+      err = SSL_connect (openssl->tls_connection);
+    }
+
+  /* Get the server certificate */
+  peer_cert = SSL_get_peer_certificate (openssl->tls_connection);
+  if (peer_cert == NULL)
+    {
+      warn_when_safe (Qtls_error, Qerror,
+		      "Peer did not present a certificate");
+      goto error;
+    }
+
+  cert_err = SSL_get_verify_result (openssl->tls_connection);
+  if (cert_err != X509_V_OK)
+    {
+      warn_when_safe (Qtls_error, Qerror,
+		      "Peer certificate verification failure:%s",
+		      X509_verify_cert_error_string (cert_err));
+      goto error;
+    }
+
+#ifdef HAVE_X509_CHECK_HOST
+  err = X509_check_host (peer_cert, (const unsigned char *) c_hostname,
+			 strlen (c_hostname), 0);
+  if (err < 0)
+    {
+      warn_when_safe (Qtls_error, Qerror,
+		      "Out of memory while checking certificate");
+      goto error;
+    }
+  if (err == 0)
+    {
+      warn_when_safe (Qtls_error, Qerror,
+		      "Peer certificate verification failure");
+      goto error;
+    }
+#endif
+  X509_free (peer_cert);
+
+  return openssl;
+
+ error:
+  if (openssl->tls_connection != NULL)
+    SSL_free (openssl->tls_connection);
+  free (openssl);
+  errno = EACCES;
+  return NULL;
+}
+
+/* Function that gathers passwords for PKCS #11 tokens. */
+static int
+openssl_password (char *buf, int size, int UNUSED (rwflag),
+		  void *UNUSED (userdata))
+{
+  Lisp_Object lsp_password, args[2];
+  Extbyte *c_password;
+
+  lsp_password =
+    call1 (Qread_password, concat2 (prompt, build_ascstring ("PEM")));
+  c_password = LISP_STRING_TO_EXTERNAL (lsp_password, Qnative);
+  strncpy (buf, c_password, size);
+
+  /* Wipe out the password on the stack and in the Lisp string */
+  args[0] = lsp_password;
+  args[1] = make_char ('*');
+  Ffill (2, args);
+  memset (c_password, '*', strlen (c_password));
+  return (int) strlen (buf);
+}
+
+void
+init_tls (void)
+{
+  /* Load the default configuration */
+  OPENSSL_config (NULL);
+
+  /* Tell openssl to use our memory allocation functions */
+  CRYPTO_set_mem_functions ((void * (*)(size_t)) xmalloc,
+			    (void * (*)(void *, size_t)) xrealloc,
+			    xfree_1);
+
+  /* Load human-readable error messages */
+  SSL_load_error_strings ();
+
+  /* Initialize the library */
+  SSL_library_init ();
+
+  /* Configure a client connection context, and send a handshake for the
+   * highest supported TLS version. */
+  ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
+  if (ssl_ctx == NULL)
+    signal_error (Qtls_error, "SSL_CTX_new failed", openssl_error_string ());
+
+  /* Disallow SSLv2 and disable compression. */
+  SSL_CTX_set_options (ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION);
+
+  /* Set various useful mode bits */
+  SSL_CTX_set_mode (ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE |
+		    SSL_MODE_AUTO_RETRY | SSL_MODE_RELEASE_BUFFERS);
+
+  /* Enable all high strength ciphers */
+  if (SSL_CTX_set_cipher_list (ssl_ctx, "HIGH") != 1)
+    signal_error (Qtls_error, "SSL_CTX_set_cipher_list failed",
+		  openssl_error_string ());
+
+  /* Load the set of trusted root certificates. */
+  if (!SSL_CTX_set_default_verify_paths (ssl_ctx))
+    signal_error (Qtls_error, "SSL_CTX_set_default_verify_paths failed",
+		  openssl_error_string ());
+
+  /* Setup password gathering */
+  SSL_CTX_set_default_passwd_cb (ssl_ctx, openssl_password);
+}
+#endif /* HAVE_OPENSSL */
+
+#ifndef WITH_TLS
+void
+init_tls (void)
+{
+}
+#endif /* !WITH_TLS */
+
+void
+syms_of_tls (void)
+{
+#ifdef WITH_TLS
+  DEFSYMBOL (Qread_password);
+#endif
+  DEFERROR (Qtls_error, "TLS error", Qerror);
+}
+
+void
+vars_of_tls (void)
+{
+#ifdef WITH_TLS
+  staticpro (&prompt);
+  prompt = build_ascstring ("Password for ");
+  Fprovide (intern ("tls"));
+#ifdef HAVE_NSS
+  Fprovide (intern ("tls-nss"));
+#endif
+#ifdef HAVE_GNUTLS
+  Fprovide (intern ("tls-gnutls"));
+#endif
+#ifdef HAVE_OPENSSL
+  Fprovide (intern ("tls-openssl"));
+#endif
+#endif
+}
diff -r acf1c26e3019 src/tls.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tls.h	Thu May 15 13:23:32 2014 -0600
@@ -0,0 +1,96 @@
+/* Transport Layer Security implementation -- header file.
+   Copyright (C) 2014 Jerry James
+
+This file is part of XEmacs.
+
+XEmacs is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs.  If not, see <http://www.gnu.org/licenses/>. */
+
+/* Synched up with: Not in FSF. */
+
+/* Written by Jerry James. */
+
+#ifndef INCLUDED_tls_h_
+#define INCLUDED_tls_h_
+
+extern Lisp_Object Qtls_error;
+
+void syms_of_tls (void);
+void vars_of_tls (void);
+void init_tls (void);
+
+#ifdef WITH_TLS
+
+#ifdef HAVE_NSS
+#include <prio.h>
+
+#define TLS_SETUP_SOCK 0
+
+typedef struct tls_state
+{
+  PRFileDesc *tls_file_desc;
+  int tls_refcount;
+} tls_state_t;
+#endif
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+
+#define TLS_SETUP_SOCK 1
+
+typedef struct tls_state
+{
+  gnutls_session_t tls_session;
+  int tls_refcount;
+} tls_state_t;
+#endif
+
+#ifdef HAVE_OPENSSL
+# include <openssl/ssl.h>
+
+#define TLS_SETUP_SOCK 1
+
+typedef struct tls_state
+{
+  SSL *tls_connection;
+  int tls_refcount;
+} tls_state_t;
+#endif
+
+struct sockaddr;
+
+tls_state_t *tls_open (int, Lisp_Object, struct sockaddr *);
+void tls_close_connection (tls_state_t *);
+Lisp_Object make_tls_output_stream (tls_state_t *);
+Lisp_Object make_tls_input_stream (tls_state_t *);
+int tls_get_fd (tls_state_t *);
+Bytecount tls_read (tls_state_t *, unsigned char *, Bytecount, unsigned int);
+Bytecount tls_write (tls_state_t *, const unsigned char *, Bytecount,
+		     unsigned int);
+int tls_close (tls_state_t *state);
+#else /* WITH_TLS */
+typedef int tls_state_t;
+#define TLS_SETUP_SOCK 1
+#define tls_open(x,y,z)							\
+  signal_error (Qtls_error, "TLS support unavailable", Qnil), NULL
+#define make_tls_input_stream(x)					\
+  signal_error (Qtls_error, "TLS support unavailable", Qnil), NULL
+#define make_tls_output_stream(x)					\
+  signal_error (Qtls_error, "TLS support unavailable", Qnil), NULL
+#define tls_get_fd(x, y)	-1
+#define tls_read(w,x,y,z)	-1
+#define tls_write(w,x,y,z)	-1
+#define tls_close(x)		-1
+#endif /* WITH_TLS */
+
+#endif /* INCLUDED_tls_h_ */
