diff options
Diffstat (limited to 'WWW/Library/Implementation/HTTP.c')
-rw-r--r-- | WWW/Library/Implementation/HTTP.c | 98 |
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 |