about summary refs log tree commit diff stats
path: root/WWW
diff options
context:
space:
mode:
authorThomas E. Dickey <dickey@invisible-island.net>2007-05-13 23:54:37 -0400
committerThomas E. Dickey <dickey@invisible-island.net>2007-05-13 23:54:37 -0400
commitcdf342faa36bbeea0fe2d8519d5b17f4b072f7f6 (patch)
treea84d747c5ffecaf8cda6424d36583905f42eda99 /WWW
parent741e82fc69b69a3bfc14f33f33766a89cea4df42 (diff)
downloadlynx-snapshots-cdf342faa36bbeea0fe2d8519d5b17f4b072f7f6.tar.gz
snapshot of project "lynx", label v2-8-7dev_4e
Diffstat (limited to 'WWW')
-rw-r--r--WWW/Library/Implementation/HTFile.c7
-rw-r--r--WWW/Library/Implementation/HTString.c66
-rw-r--r--WWW/Library/Implementation/HTTP.c142
-rw-r--r--WWW/Library/Implementation/HTTelnet.c9
4 files changed, 172 insertions, 52 deletions
diff --git a/WWW/Library/Implementation/HTFile.c b/WWW/Library/Implementation/HTFile.c
index b15c0448..f0fcdbc3 100644
--- a/WWW/Library/Implementation/HTFile.c
+++ b/WWW/Library/Implementation/HTFile.c
@@ -1,4 +1,7 @@
-/*			File Access				HTFile.c
+/*
+ * $LynxId: HTFile.c,v 1.102 2007/05/13 17:29:41 tom Exp $
+ *
+ *			File Access				HTFile.c
  *			===========
  *
  *	This is unix-specific code in general, with some VMS bits.
@@ -2250,7 +2253,9 @@ static int decompressAndParse(HTParentAnchor *anchor,
 	     * this is a compressed file, no need to look at the filename
 	     * again.  - kw
 	     */
+#if defined(USE_ZLIB) || defined(USE_BZLIB)
 	    CompressFileType method = HTEncodingToCompressType(HTAtom_name(myEncoding));
+#endif
 
 #define isDOWNLOAD(m) (strcmp(format_out->name, "www/download") && (method == m))
 #ifdef USE_ZLIB
diff --git a/WWW/Library/Implementation/HTString.c b/WWW/Library/Implementation/HTString.c
index e212c6f1..9728e549 100644
--- a/WWW/Library/Implementation/HTString.c
+++ b/WWW/Library/Implementation/HTString.c
@@ -1,4 +1,7 @@
-/*		Case-independent string comparison		HTString.c
+/*
+ * $LynxId: HTString.c,v 1.48 2007/05/13 19:08:59 tom Exp $
+ *
+ *	Case-independent string comparison		HTString.c
  *
  *	Original version came with listserv implementation.
  *	Version TBL Oct 91 replaces one which modified the strings.
@@ -129,53 +132,48 @@ int strncasecomp(const char *a,
     }
     /*NOTREACHED */
 }
+#endif /* VM */
+
+#define end_component(p) (*(p) == '.' || *(p) == '\0')
 
 /*
- * Compare strings, ignoring case.  If either begins with an asterisk, treat
- * that as a wildcard to match zero-or-more characters.  This does not test
- * for embedded wildcards.
+ * Compare names as described in RFC 2818: ignore case, allow wildcards. 
+ * Return zero on a match, nonzero on mismatch.
+ *
+ * From RFC 2818:
+ * Names may contain the wildcard character * which is considered to match any
+ * single domain name component or component fragment.  E.g., *.a.com matches
+ * foo.a.com but not bar.foo.a.com.  f*.com matches foo.com but not bar.com.
  */
 int strcasecomp_asterisk(const char *a, const char *b)
 {
-    unsigned const char *us1 = (unsigned const char *) a;
-    unsigned const char *us2 = (unsigned const char *) b;
+    const char *p;
     int result = 0;
 
-    if ((*a != '*') && (*b != '*')) {
-	result = strcasecomp(a, b);
-    } else {
-	int dir = 1;
-
-	if (*b == '*') {
-	    us1 = us2;
-	    us2 = (unsigned const char *) a;
-	    dir = -1;
-	}
-
-	if (strlen((const char *) us2) < (strlen((const char *) us1) - 1)) {
-	    result = 1;
-	} else {
-	    while (*++us1 != '\0') ;
-	    while (*++us2 != '\0') ;
-
-	    while (1) {
-		unsigned char a1 = TOLOWER(*us1);
-		unsigned char b1 = TOLOWER(*us2);
-
-		if (a1 != b1) {
-		    result = (a1 > b1) ? dir : -dir;
-		    break;
-		} else if ((*--us1) == '*') {
-		    result = 0;
+    while (!result && *a != '\0' && *b != '\0') {
+	if (*a == '*') {
+	    p = b;
+	    ++a;
+	    for (;;) {
+		if (strcasecomp_asterisk(a, p) && !end_component(p)) {
+		    ++p;
+		    result = 1;	/* could not match */
+		} else {
+		    b = p;
+		    result = 0;	/* found a match starting here */
 		    break;
 		}
-		--us2;
 	    }
+	} else if (*b == '*') {
+	    result = strcasecomp_asterisk(b, a);
+	} else if (TOLOWER(UCH(*a)) != TOLOWER(UCH(*b))) {
+	    result = 1;
 	}
+	++a;
+	++b;
     }
     return result;
 }
-#endif /* VM */
 
 #ifdef NOT_ASCII
 
diff --git a/WWW/Library/Implementation/HTTP.c b/WWW/Library/Implementation/HTTP.c
index a4f490f4..c0cd6e76 100644
--- a/WWW/Library/Implementation/HTTP.c
+++ b/WWW/Library/Implementation/HTTP.c
@@ -1,5 +1,8 @@
-/*	HyperText Tranfer Protocol	- Client implementation		HTTP.c
- *	==========================
+/*
+ * $LynxId: HTTP.c,v 1.85 2007/05/13 21:08:19 tom Exp $
+ *
+ * HyperText Tranfer Protocol	- Client implementation		HTTP.c
+ * ==========================
  * Modified:
  * 27 Jan 1994	PDM  Added Ari Luotonen's Fix for Reload when using proxy
  *		     servers.
@@ -42,6 +45,15 @@
 #include <LYrcFile.h>
 #include <LYLeaks.h>
 
+#ifdef USE_SSL
+#ifdef USE_OPENSSL_INCL
+#include <openssl/x509v3.h>
+#endif
+#ifdef USE_GNUTLS_INCL
+#include <gnutls/x509.h>
+#endif
+#endif
+
 struct _HTStream {
     HTStreamClass *isa;
 };
@@ -419,6 +431,23 @@ static BOOL acceptEncoding(int code)
     return result;
 }
 
+#ifdef USE_SSL
+static void show_cert_issuer(X509 * peer_cert)
+{
+#if defined(USE_OPENSSL_INCL)
+    char ssl_dn[1024];
+    char *msg = NULL;
+
+    X509_NAME_oneline(X509_get_issuer_name(peer_cert), ssl_dn, sizeof(ssl_dn));
+    HTSprintf0(&msg, gettext("Certificate issued by: %s"), ssl_dn);
+    _HTProgress(msg);
+    FREE(msg);
+#elif defined(USE_GNUTLS_INCL)
+    /* the OpenSSL code compiles but dumps core with GNU TLS */
+#endif
+}
+#endif
+
 /*		Load Document from HTTP Server			HTLoadHTTP()
  *		==============================
  *
@@ -479,6 +508,7 @@ static int HTLoadHTTP(const char *arg,
     const char *connect_url = NULL;	/* The URL being proxied */
     char *connect_host = NULL;	/* The host being proxied */
     SSL *handle = NULL;		/* The SSL handle */
+    X509 *peer_cert;		/* The peer certificate */
     char ssl_dn[1024];
     char *cert_host;
     char *ssl_host;
@@ -486,7 +516,7 @@ static int HTLoadHTTP(const char *arg,
     char *msg = NULL;
     int status_sslcertcheck;
     char *ssl_dn_start;
-    char *ssl_all_cns;
+    char *ssl_all_cns = NULL;
 
 #ifdef USE_GNUTLS_INCL
     int ret;
@@ -689,7 +719,8 @@ static int HTLoadHTTP(const char *arg,
 	}
 #endif
 
-	X509_NAME_oneline(X509_get_subject_name(SSL_get_peer_certificate(handle)),
+	peer_cert = SSL_get_peer_certificate(handle);
+	X509_NAME_oneline(X509_get_subject_name(peer_cert),
 #ifndef USE_GNUTLS_INCL
 			  ssl_dn, sizeof(ssl_dn));
 #else
@@ -719,13 +750,16 @@ static int HTLoadHTTP(const char *arg,
 	/* initialise status information */
 	status_sslcertcheck = 0;	/* 0 = no CN found in DN */
 	ssl_dn_start = ssl_dn;
-	ssl_all_cns = NULL;
 	/* get host we're connecting to */
 	ssl_host = HTParse(url, "", PARSE_HOST);
-	/* strip port number */
-	if ((p = strchr(ssl_host, ':')) != NULL)
+	/* strip port number or extract hostname component */
+	if ((p = strchr(ssl_host, (ssl_host[0] == '[') ? ']' : ':')) != NULL)
 	    *p = '\0';
+	if (ssl_host[0] == '[')
+	    ssl_host++;
+
 	/* validate all CNs found in DN */
+	CTRACE((tfp, "Validating CNs in '%s'\n", ssl_dn_start));
 	while ((cert_host = strstr(ssl_dn_start, "/CN=")) != NULL) {
 	    status_sslcertcheck = 1;	/* 1 = could not verify CN */
 	    /* start of CommonName */
@@ -736,28 +770,36 @@ static int HTLoadHTTP(const char *arg,
 		ssl_dn_start = p;	/* yes this points to the NUL byte */
 	    } else
 		ssl_dn_start = NULL;
-	    /* strip port number */
-	    if ((p = strchr(cert_host, ':')) != NULL)
+	    /* strip port number (XXX [ip]:port encap here too? -TG) */
+	    if ((p = strchr(cert_host,
+			    (cert_host[0] == '[') ? ']' : ':')) != NULL)
 		*p = '\0';
+	    if (cert_host[0] == '[')
+		cert_host++;
+
 	    /* verify this CN */
+	    CTRACE((tfp, "Matching\n\tssl_host  '%s'\n\tcert_host '%s'\n",
+		    ssl_host, cert_host));
 	    if (!strcasecomp_asterisk(ssl_host, cert_host)) {
 		status_sslcertcheck = 2;	/* 2 = verified peer */
-		/* I think this is cool to have in the logs --mirabilos */
+		/* I think this is cool to have in the logs -TG */
 		HTSprintf0(&msg,
 			   gettext("Verified connection to %s (cert=%s)"),
 			   ssl_host, cert_host);
 		_HTProgress(msg);
 		FREE(msg);
+		show_cert_issuer(SSL_get_peer_certificate(handle));
 		/* no need to continue the verification loop */
 		break;
 	    }
+
 	    /* add this CN to list of failed CNs */
-	    if (ssl_all_cns == NULL) {
-		StrAllocCopy(ssl_all_cns, cert_host);
-	    } else {
-		StrAllocCat(ssl_all_cns, ":");
-		StrAllocCat(ssl_all_cns, cert_host);
-	    }
+	    if (ssl_all_cns == NULL)
+		StrAllocCopy(ssl_all_cns, "CN<");
+	    else
+		StrAllocCat(ssl_all_cns, ":CN<");
+	    StrAllocCat(ssl_all_cns, cert_host);
+	    StrAllocCat(ssl_all_cns, ">");
 	    /* if we cannot retry, don't try it */
 	    if (ssl_dn_start == NULL)
 		break;
@@ -765,6 +807,67 @@ static int HTLoadHTTP(const char *arg,
 	    *ssl_dn_start = '/';	/* formerly NUL byte */
 	}
 
+	/* check the X.509v3 Subject Alternative Name */
+#ifdef USE_OPENSSL_INCL
+	if (status_sslcertcheck < 2) {
+	    STACK_OF(GENERAL_NAME) * gens;
+	    int i, numalts;
+	    const GENERAL_NAME *gn;
+
+	    if ((gens = X509_get_ext_d2i(peer_cert, NID_subject_alt_name,
+					 NULL, NULL)) != NULL) {
+		numalts = sk_GENERAL_NAME_num(gens);
+		for (i = 0; i < numalts; ++i) {
+		    gn = sk_GENERAL_NAME_value(gens, i);
+		    if (gn->type == GEN_DNS)
+			cert_host = (char *) ASN1_STRING_data(gn->d.ia5);
+		    else if (gn->type == GEN_IPADD) {
+			/* XXX untested -TG */
+			size_t j = ASN1_STRING_length(gn->d.ia5);
+
+			cert_host = malloc(j + 1);
+			memcpy(cert_host, ASN1_STRING_data(gn->d.ia5), j);
+			cert_host[j] = '\0';
+		    } else
+			continue;
+		    status_sslcertcheck = 1;	/* got at least one */
+		    /* verify this SubjectAltName (see above) */
+		    if ((p = strchr(cert_host,
+				    (cert_host[0] == '[') ? ']' : ':')) != NULL)
+			*p = '\0';
+		    if (cert_host[0] == '[')
+			cert_host++;
+		    if (!(gn->type == GEN_IPADD ? strcasecomp :
+			  strcasecomp_asterisk) (ssl_host, cert_host)) {
+			status_sslcertcheck = 2;
+			HTSprintf0(&msg,
+				   gettext("Verified connection to %s (subj=%s)"),
+				   ssl_host, cert_host);
+			_HTProgress(msg);
+			FREE(msg);
+			if (gn->type == GEN_IPADD)
+			    free(cert_host);
+			break;
+		    }
+		    /* add to list of failed CNs */
+		    if (ssl_all_cns == NULL)
+			StrAllocCopy(ssl_all_cns, "SAN<");
+		    else
+			StrAllocCat(ssl_all_cns, ":SAN<");
+		    if (gn->type == GEN_DNS)
+			StrAllocCat(ssl_all_cns, "DNS=");
+		    else if (gn->type == GEN_IPADD)
+			StrAllocCat(ssl_all_cns, "IP=");
+		    StrAllocCat(ssl_all_cns, cert_host);
+		    StrAllocCat(ssl_all_cns, ">");
+		    if (gn->type == GEN_IPADD)
+			free(cert_host);
+		}
+		sk_GENERAL_NAME_free(gens);
+	    }
+	}
+#endif /* USE_OPENSSL_INCL */
+
 	/* if an error occurred, format the appropriate message */
 	if (status_sslcertcheck == 0) {
 	    HTSprintf0(&msg, SSL_FORCED_PROMPT,
@@ -783,8 +886,15 @@ static int HTLoadHTTP(const char *arg,
 		FREE(ssl_all_cns);
 		goto done;
 	    }
+	    HTSprintf0(&msg,
+		       gettext("UNVERIFIED connection to %s (cert=%s)"),
+		       ssl_host, ssl_all_cns ? ssl_all_cns : "NONE");
+	    _HTProgress(msg);
+	    FREE(msg);
 	}
 
+	show_cert_issuer(peer_cert);
+
 	HTSprintf0(&msg,
 		   gettext("Secure %d-bit %s (%s) HTTP connection"),
 		   SSL_get_cipher_bits(handle, NULL),
diff --git a/WWW/Library/Implementation/HTTelnet.c b/WWW/Library/Implementation/HTTelnet.c
index 2260f6c0..c1ac3150 100644
--- a/WWW/Library/Implementation/HTTelnet.c
+++ b/WWW/Library/Implementation/HTTelnet.c
@@ -1,4 +1,7 @@
-/*		Telnet Acees, Roligin, etc			HTTelnet.c
+/*
+ * $LynxId: HTTelnet.c,v 1.37 2007/05/13 16:27:23 tom Exp $
+ *
+ *		Telnet Access, Rlogin, etc			HTTelnet.c
  *		==========================
  *
  * Authors
@@ -35,6 +38,10 @@
 #include <LYClean.h>
 #include <LYLeaks.h>
 
+#ifdef __GNUC__
+static void do_system(char *) GCC_UNUSED;
+#endif
+
 static void do_system(char *command)
 {
     if (!isEmpty(command)) {