about summary refs log tree commit diff stats
path: root/WWW/Library/Implementation/HTTP.c
diff options
context:
space:
mode:
Diffstat (limited to 'WWW/Library/Implementation/HTTP.c')
-rw-r--r--WWW/Library/Implementation/HTTP.c98
1 files changed, 73 insertions, 25 deletions
diff --git a/WWW/Library/Implementation/HTTP.c b/WWW/Library/Implementation/HTTP.c
index 7ced53bf..687bab83 100644
--- a/WWW/Library/Implementation/HTTP.c
+++ b/WWW/Library/Implementation/HTTP.c
@@ -451,11 +451,14 @@ 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 */
-    char ssl_dn[256];
+    char ssl_dn[1024];
     char *cert_host;
     char *ssl_host;
     char *p;
     char *msg = NULL;
+    int status_sslcertcheck;
+    char *ssl_dn_start;
+    char *ssl_all_cns;
 
 #if SSLEAY_VERSION_NUMBER >= 0x0900
     BOOL try_tls = TRUE;
@@ -621,34 +624,79 @@ static int HTLoadHTTP(const char *arg,
 
 	X509_NAME_oneline(X509_get_subject_name(SSL_get_peer_certificate(handle)),
 			  ssl_dn, sizeof(ssl_dn));
-	if ((cert_host = strstr(ssl_dn, "/CN=")) == NULL) {
+
+	/*
+	 * X.509 DN validation taking ALL CN fields into account
+	 * (c) 2006 Thorsten Glaser <tg@mirbsd.de>
+	 */
+
+	/* 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)
+	    *p = '\0';
+	/* validate all CNs found in DN */
+	while ((cert_host = strstr(ssl_dn_start, "/CN=")) != NULL) {
+	    status_sslcertcheck = 1;	/* 1 = could not verify CN */
+	    /* start of CommonName */
+	    cert_host += 4;
+	    /* find next part of DistinguishedName */
+	    if ((p = strchr(cert_host, '/')) != NULL) {
+		*p = '\0';
+		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)
+		*p = '\0';
+	    /* verify this CN */
+	    if (!strcasecomp_asterisk(ssl_host, cert_host)) {
+		status_sslcertcheck = 2;	/* 2 = verified peer */
+		/* I think this is cool to have in the logs --mirabilos */
+		HTSprintf0(&msg,
+			   gettext("Verified connection to %s (cert=%s)"),
+			   ssl_host, cert_host);
+		_HTProgress(msg);
+		FREE(msg);
+		/* 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 we cannot retry, don't try it */
+	    if (ssl_dn_start == NULL)
+		break;
+	    /* now retry next CN found in DN */
+	    *ssl_dn_start = '/';	/* formerly NUL byte */
+	}
+
+	/* if an error occurred, format the appropriate message */
+	if (status_sslcertcheck == 0) {
 	    HTSprintf0(&msg,
 		       gettext("SSL error:Can't find common name in certificate-Continue?"));
+	} else if (status_sslcertcheck == 1) {
+	    HTSprintf0(&msg,
+		       gettext("SSL error:host(%s)!=cert(%s)-Continue?"),
+		       ssl_host, ssl_all_cns);
+	}
+
+	/* if an error occurred, let the user decide how much he trusts */
+	if (status_sslcertcheck < 2) {
 	    if (!HTForcedPrompt(ssl_noprompt, msg, YES)) {
 		status = HT_NOT_LOADED;
 		FREE(msg);
+		FREE(ssl_all_cns);
 		goto done;
 	    }
-	} else {
-	    cert_host += 4;
-	    if ((p = strchr(cert_host, '/')) != NULL)
-		*p = '\0';
-	    if ((p = strchr(cert_host, ':')) != NULL)
-		*p = '\0';
-	    ssl_host = HTParse(url, "", PARSE_HOST);
-	    if ((p = strchr(ssl_host, ':')) != NULL)
-		*p = '\0';
-	    if (strcasecomp(ssl_host, cert_host)) {
-		HTSprintf0(&msg,
-			   gettext("SSL error:host(%s)!=cert(%s)-Continue?"),
-			   ssl_host,
-			   cert_host);
-		if (!HTForcedPrompt(ssl_noprompt, msg, YES)) {
-		    status = HT_NOT_LOADED;
-		    FREE(msg);
-		    goto done;
-		}
-	    }
 	}
 
 	HTSprintf0(&msg,
@@ -834,7 +882,7 @@ static int HTLoadHTTP(const char *arg,
 	 *
 	 * If there ever is a need to send "Negotiate:  trans" and really mean
 	 * it, we should send "Negotiate:  trans,trans" or similar, since that
-	 * is semantically equivalent and some servers may ignore "Negotiate: 
+	 * is semantically equivalent and some servers may ignore "Negotiate:
 	 * trans" as a special case when it comes from Lynx (to work around the
 	 * old faulty behavior).  - kw
 	 *
@@ -957,7 +1005,7 @@ static int HTLoadHTTP(const char *arg,
 		} else if (auth && *auth == '\0') {
 		    /*
 		     * If auth is a zero-length string, the user either
-		     * cancelled or goofed at the username and password prompt. 
+		     * cancelled or goofed at the username and password prompt.
 		     * - FM
 		     */
 		    if (!(traversal || dump_output_immediately) &&
@@ -1624,7 +1672,7 @@ static int HTLoadHTTP(const char *arg,
 		 * would include POST content, we seek confirmation from an
 		 * interactive user, with option to use 303 for 301 (but not
 		 * for 307), and otherwise refuse the redirection.  We also
-		 * don't allow permanent redirection if we keep POST content. 
+		 * don't allow permanent redirection if we keep POST content.
 		 * If we don't find the Location header or it's value is
 		 * zero-length, we display whatever the server returned, and
 		 * the user should RELOAD that to try again, or make a