SSL support for Lynx 2.8.3 (SSL-MM 1.4.1)

Lynx, in its unmodified form, will not allow you to make secure socket
layer (SSL) connections.  SSL is used for the secure transfer of
information over the Internet.  Many sites are now requiring SSL to ensure
security for themselves and their users.  With a version of Lynx modified
to support SSL, Lynx users can now visit these sites with ease as well.

This SSL patch package for Lynx provides the ability to make use of SSL
over HTTP for secure access to web sites (HTTPS) and over NNTP for secure
access to news servers (SNEWS).  SSL is handled transparently, allowing
users to continue accessing web sites and news services from within Lynx
through the same interface for both secure and standard transfers.

These patches are based on, and require, the OpenSSL library.  OpenSSL's
distribution and use may be restricted by licenses and laws.  For
information on obtaining OpenSSL, as well as information on its
distribution, see http://www.openssl.org/.  The main distribution site is
ftp://ftp.openssl.org/.

OpenSSL is required to be installed for these patches to Lynx to work.  
This patch set is intended for the April 23, 2000 release of Lynx 2.8.3,
and was prepared against a 2.8.3rel1 source tree.  It is guaranteed to
work with this version and only this version of Lynx.  As Lynx evolves,
new versions of this patch will be made available.  This patch should work
with any release version of OpenSSL, although newer versions are generally
preferrable.

This adaptation of the patches was done by Mark Mentovai
(mark@moxienet.com).  The history of Lynx with SSL support is too detailed
to mention here, for more information on this, see the Lynx SSL home page
at http://www.moxienet.com/lynx/.

To patch your version of Lynx to cooperate with SSL, first be sure to have
OpenSSL installed.  Then, you must apply these patches to the source.  If
you have the single-file patch version, decompress it in the same
directory you unpacked Lynx 2.8.3 (the parent directory of lynx2-8-3) and
apply it using the command "patch -p0 < lynx-283-ssl.patch".  If you do
not have the patch command, or if this does not work for you, use one of
the versions of the patch containing the whole files: decompress and
unpack these files in the same directory you decompressed and unpacked
Lynx 2.8.3 (the parent directory of lynx2-8-3); the newer files in the
update should overwrite those of Lynx 2.8.3.

Changes to four source files in the WWW/Library/Implementation directory
are made by applying the patch: HTAAUtil.c, HTFormat.c, HTNews.c, and
HTTP.c.  LYMain.c in the src directory is updated for identification
purposes.  The makefile.in file in the top-level source directory is also
updated to enable SSL support and link with the OpenSSL libraries.  These
patches should work for VMS, although I am no longer supplying VMS build
commands, as I have no way to test them.

Once the patch has been applied, the configure command should be run, and
Lynx should be compiled and installed as normal.  Before running make, you
may wish to check the generated makefile to ensure that the location of
the OpenSSL library is set correctly.  (It's a good idea to review the
makefile created by configure from makefile.in anyway.)  After running
make, your version of Lynx should contain SSL support.  If you come across
any problems making Lynx with SSL that you can't solve (or that you can
solve but think I might like to know about), please contact me.  I would
also like to hear from people that are using my patch in interesting
settings.

To test your version of Lynx for its SSL support, try it out with an SSL
site.  http://www.moxienet.com/lynx/ssl-test will redirect you to a secure
(https) page which will load if your browser contains SSL support, and
give you some information about the connection.  Note that the server that
you are redirected to may not have a valid certificate.  Lynx will not
complain, as it does not yet support certificates, but other browsers may.  
Since you will not be sending any sensitive data to the test page, this
should not present a problem.

The distribution of the code contained in this patch may be restricted,
although technically, these patches contain no cryptographic code, merely
the hooks needed to allow Lynx to make use of cryptographic code provided
in the SSL libraries.  You can read about my opinion on the matter at
http://www.moxienet.com/crippled-cryptography.html.  Export restrictions
on cryptographic code have been declared unconstitutional by the 9th
Circuit Court of Appeals, this may mean that in the future, these SSL
patches may be included in the mainstream Lynx distribution.  See
http://www.eff.org/bernstein/ for more information.

It is the user of this patch's responsibility to ensure that all patent
laws, export restrictions, and other considerations have been taken into
account before using this patch.  This software is provided on an as-is
basis only.

Enjoy!

Last updated: 2000 April 24
Original release: 1998 March 8

--
Mark Mentovai
mark@moxienet.com
http://www.moxienet.com/

diff -ur lynx2-8-3.dist/WWW/Library/Implementation/HTAAUtil.c lynx2-8-3/WWW/Library/Implementation/HTAAUtil.c
--- lynx2-8-3.dist/WWW/Library/Implementation/HTAAUtil.c	Mon Feb 14 23:07:39 2000
+++ lynx2-8-3/WWW/Library/Implementation/HTAAUtil.c	Sun Apr 23 22:53:28 2000
@@ -50,6 +50,13 @@
 #include <HTTCP.h>
 #include <HTTP.h>
 
+#ifdef USE_SSL
+#define free_func free__func
+#include <ssl.h>
+#undef free_func
+PRIVATE SSL * Handle = NULL;	/* The SSL Handle	*/
+#endif /* USE_SSL */
+
 #include <LYStrings.h>
 #include <LYLeaks.h>
 
@@ -555,7 +562,14 @@
 	/* Reading from socket */
 
 	if (start_pointer >= end_pointer) {/*Read the next block and continue*/
+#ifdef USE_SSL
+	    if (Handle)
+		count = SSL_read(Handle, buffer, BUFFER_SIZE);
+	    else
+		count = NETREAD(in_soc, buffer, BUFFER_SIZE);
+#else
 	    count = NETREAD(in_soc, buffer, BUFFER_SIZE);
+#endif /* USE_SSL */
 	    if (count <= 0) {
 		in_soc = -1;
 		return line;
diff -ur lynx2-8-3.dist/WWW/Library/Implementation/HTFormat.c lynx2-8-3/WWW/Library/Implementation/HTFormat.c
--- lynx2-8-3.dist/WWW/Library/Implementation/HTFormat.c	Fri Mar 31 19:33:40 2000
+++ lynx2-8-3/WWW/Library/Implementation/HTFormat.c	Sun Apr 23 22:53:28 2000
@@ -16,6 +16,12 @@
 */
 #include <HTFormat.h>
 
+#ifdef USE_SSL
+#define free_func free__func
+#include <ssl.h>
+#undef free_func
+#endif /* USE_SSL */
+
 PUBLIC float HTMaxSecs = 1e10;		/* No effective limit */
 PUBLIC float HTMaxLength = 1e10;	/* No effective limit */
 PUBLIC long int HTMaxBytes  = 0;	/* No effective limit */
@@ -259,6 +265,39 @@
     return FROMASCII((unsigned char)ch);
 }
 
+#ifdef USE_SSL
+PUBLIC char HTGetSSLCharacter ARGS1(void *, handle)
+{
+    char ch;
+    interrupted_in_htgetcharacter = 0;
+    if(!handle)
+	return (char)EOF;
+    do {
+	if (input_pointer >= input_limit) {
+	    int status = SSL_read((SSL *)handle,
+				 input_buffer, INPUT_BUFFER_SIZE);
+	    if (status <= 0) {
+		if (status == 0)
+		    return (char)EOF;
+		if (status == HT_INTERRUPTED) {
+		    CTRACE((tfp, "HTFormat: Interrupted in HTGetSSLCharacter\n"));
+		    interrupted_in_htgetcharacter = 1;
+		    return (char)EOF;
+		}
+		CTRACE((tfp, "HTFormat: SSL_read error %d\n", status));
+		return (char)EOF; /* -1 is returned by UCX
+				     at end of HTTP link */
+	    }
+	    input_pointer = input_buffer;
+	    input_limit = input_buffer + status;
+	}
+	ch = *input_pointer++;
+    } while (ch == (char) 13); /* Ignore ASCII carriage return */
+
+    return FROMASCII(ch);
+}
+#endif /* USE_SSL */
+
 /*  Match maintype to any MIME type starting with maintype,
  *  for example:  image/gif should match image
  */
@@ -641,7 +680,14 @@
 	    goto finished;
 	}
 
+#ifdef USE_SSL
+	if (handle)
+	    status = SSL_read((SSL *)handle, input_buffer, INPUT_BUFFER_SIZE);
+	else
+	    status = NETREAD(file_number, input_buffer, INPUT_BUFFER_SIZE);
+#else
 	status = NETREAD(file_number, input_buffer, INPUT_BUFFER_SIZE);
+#endif /* USE_SSL */
 
 	if (status <= 0) {
 	    if (status == 0) {
diff -ur lynx2-8-3.dist/WWW/Library/Implementation/HTNews.c lynx2-8-3/WWW/Library/Implementation/HTNews.c
--- lynx2-8-3.dist/WWW/Library/Implementation/HTNews.c	Sun Mar 26 22:14:00 2000
+++ lynx2-8-3/WWW/Library/Implementation/HTNews.c	Sun Apr 23 22:53:29 2000
@@ -34,9 +34,28 @@
 #define SERVER_FILE "/usr/local/lib/rn/server"
 #endif /* SERVER_FILE */
 
+#ifdef USE_SSL
+#define free_func free__func
+#include <ssl.h>
+#include <err.h>
+#undef free_func
+extern SSL_CTX * ssl_ctx;
+extern SSL * HTGetSSLHandle NOPARAMS;
+extern void HTSSLInitPRNG NOPARAMS;
+PRIVATE SSL * Handle = NULL;
+PRIVATE int channel_s = 1;
+#define NEWS_NETWRITE(sock, buff, size) \
+	(Handle ? SSL_write(Handle, buff, size) : NETWRITE(sock, buff, size))
+#define NEWS_NETCLOSE(sock) \
+	{ (void)NETCLOSE(sock); if (Handle) SSL_free(Handle); Handle = NULL; }
+extern char HTGetSSLCharacter PARAMS((void *handle));
+PRIVATE char HTNewsGetCharacter NOPARAMS;
+#define NEXT_CHAR HTNewsGetCharacter()
+#else
 #define NEWS_NETWRITE  NETWRITE
 #define NEWS_NETCLOSE  NETCLOSE
 #define NEXT_CHAR HTGetCharacter()
+#endif /* USE_SSL */
 
 #include <HTML.h>
 #include <HTParse.h>
@@ -2147,6 +2166,9 @@
     char *ProxyHost = NULL;
     char *ProxyHREF = NULL;
     char *postfile = NULL;
+#ifdef USE_SSL
+    char SSLprogress[256];
+#endif /* USE_SSL */
 
     diagnostic = (format_out == WWW_SOURCE ||	/* set global flag */
 		  format_out == HTAtom_for("www/download") ||
@@ -2195,11 +2217,13 @@
 			  group_wanted) &&
 			strchr(arg, '@') == NULL) && (strchr(arg, '*') != NULL));
 
+#ifndef USE_SSL
 	if (!strncasecomp(arg, "snewspost:", 10) ||
 	    !strncasecomp(arg, "snewsreply:", 11)) {
 	    HTAlert(FAILED_CANNOT_POST_SSL);
 	    return HT_NOT_LOADED;
 	}
+#endif /* !USE_SSL */
 	if (post_wanted || reply_wanted || spost_wanted || sreply_wanted) {
 	    /*
 	    **	Make sure we have a non-zero path for the newsgroup(s). - FM
@@ -2287,8 +2311,43 @@
 	    StrAllocCopy(NewsHREF, command);
 	}
 	else if (!strncasecomp(arg, "snews:", 6)) {
+#ifdef USE_SSL
+	    if (((*(arg + 6) == '\0') ||
+		 (!strcmp((arg + 6), "/") ||
+		  !strcmp((arg + 6), "//") ||
+		  !strcmp((arg + 6), "///"))) ||
+		((!strncmp((arg + 6), "//", 2)) &&
+		 (!(cp = strchr((arg + 8), '/')) || *(cp + 1) == '\0'))) {
+		p1 = "*";
+		group_wanted = FALSE;
+		list_wanted = TRUE;
+	    } else if (*(arg + 6) != '/') {
+		p1 = (arg + 6);
+	    } else if (*(arg + 6) == '/' && *(arg + 7) != '/') {
+		p1 = (arg + 7);
+	    } else {
+		p1 = (cp + 1);
+	    }
+	    if (!(cp = HTParse(arg, "", PARSE_HOST)) || *cp == '\0') {
+		if (s >= 0 && NewsHost && strcasecomp(NewsHost, HTNewsHost)) {
+		    NEWS_NETCLOSE(s);
+		    s = -1;
+		}
+		StrAllocCopy(NewsHost, HTNewsHost);
+	    } else {
+		if (s >= 0 && NewsHost && strcasecomp(NewsHost, cp)) {
+		    NEWS_NETCLOSE(s);
+		    s = -1;
+		}
+	    StrAllocCopy(NewsHost, cp);
+	    }
+	    FREE(cp);
+	    sprintf(command, "snews://%.250s/", NewsHost);
+	    StrAllocCopy(NewsHREF, command);
+#else
 	    HTAlert(gettext("This client does not contain support for SNEWS URLs."));
 	    return HT_NOT_LOADED;
+#endif /* USE_SSL */
 	}
 	else if (!strncasecomp (arg, "news:/", 6)) {
 	    if (((*(arg + 6) == '\0') ||
@@ -2526,7 +2585,18 @@
 
 	    _HTProgress(gettext("Connecting to NewsHost ..."));
 
+#ifdef USE_SSL
+	    if (!using_proxy &&
+		(!strncmp(arg, "snews:", 6) ||
+		 !strncmp(arg, "snewspost:", 10) ||
+		 !strncmp(arg, "snewsreply:", 11)))
+		status = HTDoConnect (url, "NNTPS", SNEWS_PORT, &s);
+	    else
+		status = HTDoConnect (url, "NNTP", NEWS_PORT, &s);
+#else
 	    status = HTDoConnect (url, "NNTP", NEWS_PORT, &s);
+#endif /* USE_SSL */
+
 	    if (status == HT_INTERRUPTED) {
 		/*
 		**  Interrupt cleanly.
@@ -2542,6 +2612,12 @@
 		FREE(ProxyHost);
 		FREE(ProxyHREF);
 		FREE(ListArg);
+#ifdef USE_SSL
+		if (Handle) {
+		    SSL_free(Handle);
+		    Handle = NULL;
+		}
+#endif /* USE_SSL */
 		if (postfile) {
 		    HTSYS_remove(postfile);
 		    FREE(postfile);
@@ -2572,6 +2648,54 @@
 	    } else {
 		CTRACE((tfp, "HTNews: Connected to news host %s.\n",
 			    NewsHost));
+#ifdef USE_SSL
+		/*
+		**  If this is an snews url,
+		**  then do the SSL stuff here
+		*/
+		if (!using_proxy &&
+		    (!strncmp(url, "snews", 5) ||
+		     !strncmp(url, "snewspost:", 10) ||
+		     !strncmp(url, "snewsreply:", 11))) {
+		    Handle = HTGetSSLHandle();
+		    SSL_set_fd(Handle, s);
+                    HTSSLInitPRNG();
+		    status = SSL_connect(Handle);
+
+		    if (status <= 0) {
+                        unsigned long SSLerror;
+                        CTRACE((tfp,"HTNews: Unable to complete SSL handshake for '%s', SSL_connect=%d, SSL error stack dump follows\n",url, status));
+                        SSL_load_error_strings();
+                        while((SSLerror=ERR_get_error())!=0) {
+                            CTRACE((tfp,"HTNews: SSL: %s\n",ERR_error_string(SSLerror,NULL)));
+                        }
+			HTAlert(
+			    "Unable to make secure connection to remote host.");
+			NEWS_NETCLOSE(s);
+			s = -1;
+			if (!(post_wanted || reply_wanted ||
+			      spost_wanted || sreply_wanted))
+			    (*targetClass._abort)(target, NULL);
+			FREE(NewsHost);
+			FREE(NewsHREF);
+			FREE(ProxyHost);
+			FREE(ProxyHREF);
+			FREE(ListArg);
+			if (postfile) {
+#ifdef VMS
+			    while (remove(postfile) == 0)
+			    ; /* loop through all versions */
+#else
+			    remove(postfile);
+#endif /* VMS */
+			    FREE(postfile);
+			}
+			return HT_NOT_LOADED;
+		    }
+                    sprintf(SSLprogress,"Secure %d-bit %s (%s) NNTP connection",SSL_get_cipher_bits(Handle,NULL),SSL_get_cipher_version(Handle),SSL_get_cipher(Handle));
+                    _HTProgress(SSLprogress);
+		}
+#endif /* USE_SSL */
 		HTInitInput(s);		/* set up buffering */
 		if (proxycmd[0]) {
 		    status = NEWS_NETWRITE(s, proxycmd, strlen(proxycmd));
@@ -2921,6 +3045,51 @@
     */
     free_NNTP_AuthInfo();
 }
+
+#ifdef USE_SSL
+PRIVATE char HTNewsGetCharacter NOARGS
+{
+    if (!Handle)
+        return HTGetCharacter();
+    else
+        return HTGetSSLCharacter((void *)Handle);
+}
+
+PUBLIC int HTNewsProxyConnect ARGS5 (int, sock, CONST char *, url, 
+				     HTParentAnchor *, anAnchor,
+				     HTFormat, format_out,
+				     HTStream *, sink)
+{
+    int status;
+    CONST char * arg = url;
+    char SSLprogress[256];
+
+    s = channel_s = sock;
+    Handle = HTGetSSLHandle();
+    SSL_set_fd(Handle, s);
+    HTSSLInitPRNG();
+    status = SSL_connect(Handle);
+
+    if (status <= 0) {
+        unsigned long SSLerror;
+        channel_s = -1;
+        CTRACE((tfp,"HTNews: Unable to complete SSL handshake for '%s', SSL_connect=%d, SSL error stack dump follows\n",url, status));
+        SSL_load_error_strings();
+        while((SSLerror=ERR_get_error())!=0) {
+            CTRACE((tfp,"HTNews: SSL: %s\n",ERR_error_string(SSLerror,NULL)));
+        }
+	HTAlert("Unable to make secure connection to remote host.");
+	NEWS_NETCLOSE(s);
+	s = -1;
+	return HT_NOT_LOADED;
+    }
+    sprintf(SSLprogress,"Secure %d-bit %s (%s) NNTP connection",SSL_get_cipher_bits(Handle,NULL),SSL_get_cipher_version(Handle),SSL_get_cipher(Handle));
+    _HTProgress(SSLprogress);
+    status = HTLoadNews(arg, anAnchor, format_out, sink);
+    channel_s = -1;
+    return status;
+}
+#endif /* USE_SSL */
 
 #ifdef GLOBALDEF_IS_MACRO
 #define _HTNEWS_C_1_INIT { "news", HTLoadNews, NULL }
diff -ur lynx2-8-3.dist/WWW/Library/Implementation/HTTP.c lynx2-8-3/WWW/Library/Implementation/HTTP.c
--- lynx2-8-3.dist/WWW/Library/Implementation/HTTP.c	Thu Apr 13 22:39:31 2000
+++ lynx2-8-3/WWW/Library/Implementation/HTTP.c	Mon Apr 24 20:47:14 2000
@@ -13,6 +13,15 @@
 #include <HTTP.h>
 #include <LYUtils.h>
 
+#ifdef USE_SSL
+#define free_func free__func
+#include <ssl.h>
+#include <crypto.h>
+#include <rand.h>
+#include <err.h>
+#undef free_func
+#endif /* USE_SSL */
+
 #define HTTP_VERSION	"HTTP/1.0"
 
 #define HTTP_PORT   80
@@ -67,9 +76,88 @@
 extern BOOL traversal;		 /* TRUE if we are doing a traversal */
 extern BOOL dump_output_immediately;  /* TRUE if no interactive user */
 
+#ifdef USE_SSL
+PUBLIC SSL_CTX * ssl_ctx = NULL;	/* SSL ctx */
+
+PRIVATE void free_ssl_ctx NOARGS
+{
+    if (ssl_ctx != NULL)
+        SSL_CTX_free(ssl_ctx);
+}
+
+PUBLIC SSL * HTGetSSLHandle NOARGS
+{
+    if (ssl_ctx == NULL) {
+        /*
+	 *  First time only.
+	 */
+#if SSLEAY_VERSION_NUMBER < 0x0800
+        ssl_ctx = SSL_CTX_new();
+	X509_set_default_verify_paths(ssl_ctx->cert);
+#else
+	SSLeay_add_ssl_algorithms();
+	ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+	SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL);
+	SSL_CTX_set_default_verify_paths(ssl_ctx);
+#endif /* SSLEAY_VERSION_NUMBER < 0x0800 */
+	atexit(free_ssl_ctx);
+    }
+    return(SSL_new(ssl_ctx));
+}
+
+PUBLIC void HTSSLInitPRNG NOARGS {
+#if SSLEAY_VERSION_NUMBER >= 0x00905100
+  if(RAND_status()==0) {
+    char rand_file[256];
+    time_t t;
+    pid_t pid;
+    long l,seed;
+
+    t=time(NULL);
+    pid=getpid();
+    RAND_file_name((char *)&rand_file,256);
+    CTRACE((tfp,"HTTP: Seeding PRNG\n"));
+    if(rand_file!=NULL) {
+      /* Seed as much as 1024 bytes from RAND_file_name */
+      RAND_load_file(rand_file,1024);
+    }
+    /* Seed in time (mod_ssl does this) */
+    RAND_seed((unsigned char *)&t,sizeof(time_t));
+    /* Seed in pid (mod_ssl does this) */
+    RAND_seed((unsigned char *)&pid,sizeof(pid_t));
+    /* Initialize system's random number generator */
+    RAND_bytes((unsigned char *)&seed,sizeof(long));
+    srand48(seed);
+    while(RAND_status()==0) {
+      /* Repeatedly seed the PRNG using the system's random number generator until it has been seeded with enough data */
+      l=lrand48();
+      RAND_seed((unsigned char *)&l,sizeof(long));
+    }
+    if(rand_file!=NULL) {
+      /* Write a rand_file */
+      RAND_write_file(rand_file);
+    }
+  }
+#endif /* SSLEAY_VERSION_NUMBER >= 0x00905100 */
+  return;
+}
+
+#define HTTP_NETREAD(sock, buff, size, handle) \
+	(handle ? SSL_read(handle, buff, size) : NETREAD(sock, buff, size))
+#define HTTP_NETWRITE(sock, buff, size, handle) \
+	(handle ? SSL_write(handle, buff, size) : NETWRITE(sock, buff, size))
+#define HTTP_NETCLOSE(sock, handle)  \
+	{ (void)NETCLOSE(sock); if (handle) SSL_free(handle); handle = NULL; }
+
+extern int HTNewsProxyConnect PARAMS (( int sock, CONST char *url, 
+					HTParentAnchor *anAnchor,
+					HTFormat format_out,
+					HTStream *sink ));
+#else
 #define HTTP_NETREAD(a, b, c, d)   NETREAD(a, b, c)
 #define HTTP_NETWRITE(a, b, c, d)  NETWRITE(a, b, c)
 #define HTTP_NETCLOSE(a, b)  (void)NETCLOSE(a)
+#endif /* USE_SSL */
 
 #ifdef _WINDOWS		/* 1997/11/06 (Thu) 13:00:08 */
 
@@ -299,7 +387,19 @@
   BOOL doing_redirect, already_retrying = FALSE;
   int len = 0;
 
+#ifdef USE_SSL
+  BOOL do_connect = FALSE;    /* ARE WE going to use a proxy tunnel ? */
+  BOOL did_connect = FALSE;   /* ARE WE actually using a proxy tunnel ? */
+  CONST char *connect_url = NULL; /* The URL being proxied */
+  char *connect_host = NULL;  /* The host being proxied */
+  SSL * handle = NULL;                /* The SSL handle */
+  char SSLprogress[256];      /* progress bar message */
+#if SSLEAY_VERSION_NUMBER >= 0x0900
+  BOOL try_tls = TRUE;
+#endif /* SSLEAY_VERSION_NUMBER >= 0x0900 */
+#else
   void * handle = NULL;
+#endif /* USE_SSL */
 
   if (anAnchor->isHEAD)
       do_head = TRUE;
@@ -317,6 +417,30 @@
       goto done;
   }
 
+#ifdef USE_SSL
+  if (using_proxy && !strncmp(url, "http://", 7)) {
+      if ((connect_url = strstr((url+7), "https://"))) {
+	  do_connect = TRUE;
+	  connect_host = HTParse(connect_url, "https", PARSE_HOST);
+	  if (!strchr(connect_host, ':')) {
+	      sprintf(temp, ":%d", HTTPS_PORT);
+	      StrAllocCat(connect_host, temp);
+	  }
+	  CTRACE((tfp, "HTTP: connect_url = '%s'\n", connect_url));
+	  CTRACE((tfp, "HTTP: connect_host = '%s'\n", connect_host));
+      } else if ((connect_url = strstr((url+7), "snews://"))) {
+	  do_connect = TRUE;
+	  connect_host = HTParse(connect_url, "snews", PARSE_HOST);
+	  if (!strchr(connect_host, ':')) {
+	      sprintf(temp, ":%d", SNEWS_PORT);
+	      StrAllocCat(connect_host, temp);
+	  }
+	  CTRACE((tfp, "HTTP: connect_url = '%s'\n", connect_url));
+	  CTRACE((tfp, "HTTP: connect_host = '%s'\n", connect_host));
+      }
+  }
+#endif /* USE_SSL */
+
   sprintf(crlf, "%c%c", CR, LF);
 
   /*
@@ -340,12 +464,18 @@
   line_kept_clean = NULL;
 
   if (!strncmp(url, "https", 5))
+#ifdef USE_SSL
+    status = HTDoConnect (url, "HTTPS", HTTPS_PORT, &s);
+  else
+    status = HTDoConnect (url, "HTTP", HTTP_PORT, &s);
+#else
     {
       HTAlert(gettext("This client does not contain support for HTTPS URLs."));
       status = HT_NOT_LOADED;
       goto done;
     }
   status = HTDoConnect (arg, "HTTP", HTTP_PORT, &s);
+#endif /* USE_SSL */
   if (status == HT_INTERRUPTED) {
       /*
       **  Interrupt cleanly.
@@ -375,12 +505,91 @@
  * This is a nice long function as well.  *sigh*  -RJP
  */
 
+#ifdef USE_SSL
+use_tunnel:
+  /*
+  ** If this is an https document
+  ** then do the SSL stuff here
+  */
+  if (did_connect || !strncmp(url, "https", 5)) {
+      handle = HTGetSSLHandle();
+      SSL_set_fd(handle, s);
+#if SSLEAY_VERSION_NUMBER >= 0x0900
+      if (!try_tls)
+          handle->options|=SSL_OP_NO_TLSv1;
+#endif /* SSLEAY_VERSION_NUMBER >= 0x0900 */
+      HTSSLInitPRNG();
+      status = SSL_connect(handle);
+
+      if (status <= 0) {
+#if SSLEAY_VERSION_NUMBER >= 0x0900
+	  if (try_tls) {
+              CTRACE((tfp, "HTTP: Retrying connection without TLS\n"));
+	      _HTProgress("Retrying connection.");
+	      try_tls = FALSE;
+	      if (did_connect)
+	          HTTP_NETCLOSE(s, handle);
+      	      goto try_again;
+	  } else {
+              unsigned long SSLerror;
+              CTRACE((tfp,
+"HTTP: Unable to complete SSL handshake for '%s', SSL_connect=%d, SSL error stack dump follows\n",
+				url, status));
+              SSL_load_error_strings();
+              while((SSLerror=ERR_get_error())!=0) {
+                  CTRACE((tfp,"HTTP: SSL: %s\n",ERR_error_string(SSLerror,NULL)));
+              }
+      	      HTAlert("Unable to make secure connection to remote host.");
+	      if (did_connect)
+	          HTTP_NETCLOSE(s, handle);
+      	      status = HT_NOT_LOADED;
+      	      goto done;
+	  }
+#else
+          unsigned long SSLerror;
+          CTRACE((tfp,
+"HTTP: Unable to complete SSL handshake for '%s', SSL_connect=%d, SSL error stack dump follows\n",
+				url, status));
+          SSL_load_error_strings();
+          while((SSLerror=ERR_get_error())!=0) {
+              CTRACE((tfp,"HTTP: SSL: %s\n",ERR_error_string(SSLerror,NULL)));
+          }
+      	  HTAlert("Unable to make secure connection to remote host.");
+	  if (did_connect)
+	      HTTP_NETCLOSE(s, handle);
+      	  status = HT_NOT_LOADED;
+      	  goto done;
+#endif /* SSLEAY_VERSION_NUMBER >= 0x0900 */
+      }
+      sprintf(SSLprogress,"Secure %d-bit %s (%s) HTTP connection",SSL_get_cipher_bits(handle,NULL),SSL_get_cipher_version(handle),SSL_get_cipher(handle));
+      _HTProgress(SSLprogress);
+
+#ifdef NOTDEFINED
+      if (strcmp(HTParse(url, "", PARSE_HOST),
+      		 strstr(X509_NAME_oneline(
+		 	X509_get_subject_name(
+				handle->session->peer)),"/CN=")+4)) {
+	  HTAlert("Certificate is for different host name");
+	  HTAlert(strstr(X509_NAME_oneline(
+	  		 X509_get_subject_name(
+			 	handle->session->peer)),"/CN=")+4);
+      }
+#endif /* NOTDEFINED */
+  }
+#endif /* USE_SSL */
+
   /*	Ask that node for the document,
   **	omitting the host name & anchor
   */
   {
     char * p1 = (HTParse(url, "", PARSE_PATH|PARSE_PUNCTUATION));
 
+#ifdef USE_SSL
+    if (do_connect) {
+	METHOD = "CONNECT";
+	StrAllocCopy(command, "CONNECT ");
+    } else
+#endif /* USE_SSL */
     if (do_post) {
 	METHOD = "POST";
 	StrAllocCopy(command, "POST ");
@@ -397,8 +606,17 @@
     **	of say: /gopher://a;lkdjfl;ajdf;lkj/;aldk/adflj
     **	so that just gopher://.... is sent.
     */
+#ifdef USE_SSL
+    if (using_proxy && !did_connect) {
+	if (do_connect)
+	    StrAllocCat(command, connect_host);
+      else
+	StrAllocCat(command, p1+1);
+    }
+#else
     if (using_proxy)
 	StrAllocCat(command, p1+1);
+#endif /* USE_SSL */
     else
 	StrAllocCat(command, p1);
     FREE(p1);
@@ -638,6 +856,10 @@
 		} else {
 		    if (traversal || dump_output_immediately)
 			HTAlert(FAILED_NEED_PASSWD);
+#ifdef USE_SSL
+		    if(did_connect)
+			HTTP_NETCLOSE(s, handle);
+#endif /* USE_SSL */
 		    FREE(command);
 		    FREE(hostname);
 		    FREE(docname);
@@ -752,7 +974,11 @@
       auth_proxy = NO;
   }
 
+#ifdef USE_SSL
+    if (!do_connect && do_post) {
+#else
     if (do_post) {
+#endif /* USE_SSL */
 	CTRACE((tfp, "HTTP: Doing post, content-type '%s'\n",
 		     anAnchor->post_content_type ? anAnchor->post_content_type
 						 : "lose"));
@@ -778,9 +1004,15 @@
     else
         StrAllocCat(command, crlf);	/* Blank line means "end" of headers */
 
+#ifdef USE_SSL
+  CTRACE((tfp, "Writing:\n%s%s----------------------------------\n",
+	       command,
+	       (anAnchor->post_data && !do_connect ? crlf : "")));
+#else
   CTRACE((tfp, "Writing:\n%s%s----------------------------------\n",
 	       command,
 	       (anAnchor->post_data ? crlf : "")));
+#endif /* USE_SSL */
 
   _HTProgress (gettext("Sending HTTP request."));
 
@@ -1143,6 +1375,35 @@
 		 *  > 206 is unknown.
 		 *  All should return something to display.
 		 */
+#ifdef USE_SSL
+	        if (do_connect) {
+		    CTRACE((tfp, "HTTP: Proxy tunnel to '%s' established.\n",
+				connect_host));
+		    do_connect = FALSE;
+		    url = connect_url;
+		    FREE(line_buffer);
+		    FREE(line_kept_clean);
+		    if (!strncmp(connect_url, "snews", 5)) {
+			CTRACE((tfp,
+			"      Will attempt handshake and snews connection.\n"));
+			status = HTNewsProxyConnect(s, url, anAnchor,
+						    format_out, sink);
+			goto done;
+		    }
+		    did_connect = TRUE;
+		    already_retrying = TRUE;
+		    eol = 0;
+		    bytes_already_read = 0;
+		    had_header = NO;
+		    length = 0;
+		    doing_redirect = FALSE;
+	            permanent_redirection = FALSE;
+		    target = NULL;
+		    CTRACE((tfp,
+			"      Will attempt handshake and resubmit headers.\n"));
+		    goto use_tunnel;
+		}
+#endif /* USE_SSL */
 		HTProgress(line_buffer);
 	    } /* case 2 switch */
 	    break;
@@ -1337,6 +1598,13 @@
 			gettext("Retrying with access authorization information."));
 		    FREE(line_buffer);
 		    FREE(line_kept_clean);
+#ifdef USE_SSL
+		    if (using_proxy && !strncmp(url, "https://", 8)) {
+			url = arg;
+			do_connect = TRUE;
+			did_connect = FALSE;
+		    }
+#endif /* USE_SSL */
 		    goto try_again;
 		} else if (!(traversal || dump_output_immediately) &&
 			   HTConfirm(gettext("Show the 401 message body?"))) {
@@ -1771,6 +2039,15 @@
   do_head = FALSE;
   do_post = FALSE;
   reloading = FALSE;
+#ifdef USE_SSL
+  do_connect = FALSE;
+  did_connect = FALSE;
+  FREE(connect_host);
+  if (handle) {
+    SSL_free(handle);
+    handle = NULL;
+  }
+#endif /* USE_SSL */
   return status;
 }
 
diff -ur lynx2-8-3.dist/makefile.in lynx2-8-3/makefile.in
--- lynx2-8-3.dist/makefile.in	Fri Mar 31 19:33:40 2000
+++ lynx2-8-3/makefile.in	Sun Apr 23 22:53:29 2000
@@ -70,6 +70,24 @@
 COMPRESS_PROG=@COMPRESS_PROG@
 COMPRESS_EXT=@COMPRESS_EXT@
 
+# !!!!!!!!!! SSL Support (HTTPS connections) !!!!!!!!!!!!!!!!!!!!!!!!!!!
+# To build a Lynx binary which supports the Secure Sockets Layer (SSL), you
+# must compile in the crypto and SSL libraries from the OpenSSL library,
+# available at http://www.openssl.org/ .  Once you have installed OpenSSL
+# change the location of the crypto and SSL libraries in SSL_LIBS and the
+# location of ssl.h and crypto.h in SSL_DEFINES if necessary.  USE_SSL,
+# defined below, enables Lynx to use the SSL and crypto libraries for
+# handling "https" and "snews" URLs.
+#
+# This feature is added by a patch to Lynx (which has been applied,
+# otherwise you wouldn't be seeing this message).  For more information
+# about the SSL patch for Lynx, please see http://www.moxienet.com/lynx/.  
+# This page also contains links which enable you to test your copy of Lynx'
+# ability to make SSL connections.
+SSL_DIR= /usr/local/ssl
+SSL_LIBS= -L$(SSL_DIR)/lib -lssl -lcrypto
+SSL_DEFINES= -DUSE_SSL -I$(SSL_DIR)/include/openssl -I$(SSL_DIR)/include
+
 # !!!!!!!!!!! SUN resolv LIBRARY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 # To include resolv in the LIBS="" list for SUN 3, 4 or Solaris OS,
 # point RESOLVLIB to that library.  You need this if you get the message
@@ -104,13 +122,13 @@
 
 # If you apply patches which require linking to site-specific libraries, set
 # SITE_LIBS to those libraries.
-SITE_LIBS= # Your libraries here
+SITE_LIBS= $(SSL_LIBS) # Your libraries here
 
 # Set SITE_LYDEFS to one or more of the defines for the WWW Library:
-SITE_LYDEFS = # Your defines here
+SITE_LYDEFS = $(SSL_DEFINES) # Your defines here
 
 # Set SITE_DEFS to one or more of the defines for lynx below:
-SITE_DEFS = # Your defines here
+SITE_DEFS = $(SSL_DEFINES) # Your defines here
 
 # defines for which there are no configure options:
 # -DHP_TERMINAL    For DIM workaround to REVERSE problems on HP terminals.
diff -ur lynx2-8-3.dist/src/LYMain.c lynx2-8-3/src/LYMain.c
--- lynx2-8-3.dist/src/LYMain.c	Sun Apr 23 21:44:03 2000
+++ lynx2-8-3/src/LYMain.c	Mon Apr 24 20:48:18 2000
@@ -1,3 +1,7 @@
+#ifdef USE_SSL
+#include <ssl.h>
+#endif /* USE_SSL */
+
 #include <HTUtils.h>
 #include <HTTP.h>
 #include <HTParse.h>
@@ -819,6 +823,10 @@
 #ifdef _WINDOWS
     WSADATA WSAData;
 #endif /* _WINDOWS */
+#ifdef USE_SSL
+    char SSLLibraryVersion[256];
+    char *SSLcp;
+#endif /* USE_SSL */
 
     /*
      * Just in case someone has the idea to install lynx set-uid, let's try
@@ -1002,6 +1010,22 @@
 	StrAllocCat(LYUserAgent, " libwww-FM/");
 	StrAllocCat(LYUserAgent, HTLibraryVersion);
     }
+#ifdef USE_SSL
+    StrAllocCat(LYUserAgent," SSL-MM/1.4.1");
+#ifdef OPENSSL_VERSION_TEXT
+    strncpy(SSLLibraryVersion,OPENSSL_VERSION_TEXT,255);
+    SSLLibraryVersion[255]='\0';
+    if((SSLcp=strchr(SSLLibraryVersion,' '))!=NULL) {
+      *SSLcp='/';
+      SSLcp++;
+      if((SSLcp=strchr(SSLcp,' '))!=NULL) {
+        *SSLcp='\0';
+        StrAllocCat(LYUserAgent," ");
+        StrAllocCat(LYUserAgent,SSLLibraryVersion);
+      }
+    }
+#endif /* OPENSSL_VERSION_TEXT */
+#endif /* USE_SSL */
     StrAllocCopy(LYUserAgentDefault, LYUserAgent);
 #ifdef VMS
     Define_VMSLogical("LYNX_VERSION", LYNX_VERSION);
@@ -3026,12 +3050,32 @@
 static int version_fun ARGS1(
 	char *,			next_arg GCC_UNUSED)
 {
+#ifdef USE_SSL
+    char SSLLibraryVersion[256];
+    char *SSLcp;
+#endif
     SetOutputMode( O_TEXT );
 
     printf("\n");
     printf(gettext("\n%s Version %s (%s)\n"),
 	  LYNX_NAME, LYNX_VERSION,
 	  LYVersionDate());
+#ifdef USE_SSL
+    printf("libwww-FM %s, SSL-MM 1.4.1",HTLibraryVersion);
+#ifdef OPENSSL_VERSION_TEXT
+    strncpy(SSLLibraryVersion,OPENSSL_VERSION_TEXT,255);
+    SSLLibraryVersion[255]='\0';
+    if((SSLcp=strchr(SSLLibraryVersion,' '))!=NULL) {
+      *SSLcp=' ';
+      SSLcp++;
+      if((SSLcp=strchr(SSLcp,' '))!=NULL) {
+        *SSLcp='\0';
+        printf(", %s",SSLLibraryVersion);
+      }
+    }
+#endif /* OPENSSL_VERSION_TEXT */
+    printf("\n");
+#endif /* USE_SSL */
 #ifdef SYSTEM_NAME
 #ifndef __DATE__
 #define __DATE__ ""
@@ -3049,6 +3093,13 @@
     printf(gettext(
 	  "See http://lynx.browser.org/ and the online help for more information.\n\n"
 	  ));
+#ifdef USE_SSL
+    printf("See http://www.moxienet.com/lynx/ for information about SSL for Lynx.\n");
+#ifdef OPENSSL_VERSION_TEXT
+    printf("See http://www.openssl.org/ for information about OpenSSL.\n");
+#endif /* OPENSSL_VERSION_TEXT */
+    printf("\n");
+#endif /* USE_SSL */
 
 #ifdef SH_EX
 #ifdef __CYGWIN__
