diff options
Diffstat (limited to '')
| -rw-r--r-- | ChangeLog | 16 | ||||
| -rw-r--r-- | NEWS | 1 | ||||
| -rw-r--r-- | istream.c | 85 | ||||
| -rw-r--r-- | istream.h | 4 | ||||
| -rw-r--r-- | url.c | 66 | 
5 files changed, 156 insertions, 16 deletions
| @@ -1,3 +1,17 @@ +2001-12-26  Fumitoshi UKAI  <ukai@debian.or.jp> + +	* [w3m-dev 02743] RFC2818 server identity check +	* NEWS: RFC2818 server identity check +	* istream.c (ssl_check_cert_ident): added +	* istream.h (ssl_check_cert_ident): ditto +	* istream.h: #include <x509v3.h> +	* url.c (free_ssl_ctx): ssl_ctx = NULL +	* url.c (openSSLHandle): arg hostname to check cert id +	* url.c (openSSLHandle): check SSL_get_verify_result  +			if ssl_verify_server +	* url.c (openSSLHandle): check server identity by ssl_check_cert_ident +	* url.c (openURL): openSSLHandle with pu->host +  2001-12-26  Hironori Sakamoto <hsaka@mth.biglobe.ne.jp>  	* [w3m-dev 02715] bugfix in scripts/multipart/multipart.cgi.in @@ -1599,4 +1613,4 @@  	* release-0-2-1  	* import w3m-0.2.1 -$Id: ChangeLog,v 1.178 2001/12/26 01:57:19 ukai Exp $ +$Id: ChangeLog,v 1.179 2001/12/26 12:18:06 ukai Exp $ @@ -1,5 +1,6 @@  w3m 0.2.4? 0.3? +* RFC2818 server identity check  * incremental search (C-s, C-r)  * linux/ia64 support (?) @@ -1,4 +1,4 @@ -/* $Id: istream.c,v 1.6 2001/11/24 02:01:26 ukai Exp $ */ +/* $Id: istream.c,v 1.7 2001/12/26 12:18:06 ukai Exp $ */  #include "fm.h"  #include "istream.h"  #include <signal.h> @@ -378,6 +378,89 @@ ssl_get_certificate(InputStream stream)      BIO_free_all(bp);      return s;  } + +Str +ssl_check_cert_ident(SSL *handle, char *hostname) +{ +    X509 *x; +    int i; +    Str ret = Strnew_charp("SSL error: failed to check certificate chain"); +    /* +     * All we need to do here is check that the CN matches. +     * +     * From RFC2818 3.1 Server Identity: +     * If a subjectAltName extension of type dNSName is present, that MUST +     * be used as the identity. Otherwise, the (most specific) Common Name +     * field in the Subject field of the certificate MUST be used. Although +     * the use of the Common Name is existing practice, it is deprecated and +     * Certification Authorities are encouraged to use the dNSName instead. +     */ +    x = SSL_get_peer_certificate(handle); +    if (!x) {    +	ret = Strnew_charp("Unable to get peer certificate"); +	return ret; +    } + +    i = X509_get_ext_by_NID(x, NID_subject_alt_name, -1); +    if (i >= 0) {    +        X509_EXTENSION *ex; +        STACK_OF(GENERAL_NAME) *alt; + +        ex = X509_get_ext(x, i); +        alt = X509V3_EXT_d2i(ex); +        if (alt) {    +            int n, len1, len2 = 0; +            char *domain; +            GENERAL_NAME *gn; +            X509V3_EXT_METHOD *method; + +            len1 = strlen(hostname); +            n = sk_GENERAL_NAME_num(alt); +            domain = strchr(hostname, '.'); +            if (domain) +                len2 = len1 - (domain - hostname); +            for (i = 0; i < n; i++) { +                gn = sk_GENERAL_NAME_value(alt, i); +                if (gn->type == GEN_DNS) { +                    char *sn = ASN1_STRING_data(gn->d.ia5); +                    int sl = ASN1_STRING_length(gn->d.ia5); + +                    /* Is this an exact match? */ +                    if ((len1 == sl) && !strncasecmp(hostname, sn, len1)) +                        break; + +                    /* Is this a wildcard match? */ +                    if ((*sn == '*') && domain && (len2 == sl-1) && +                        !strncasecmp(domain, sn+1, len2)) +                        break; +                } +            } +            method = X509V3_EXT_get(ex); +            method->ext_free(alt); +            if (i < n)  /* Found a match */ +                ret = NULL; +        } +    } + +    if (ret != NULL) { +        X509_NAME *xn; +        char buf[2048]; + +        xn = X509_get_subject_name(x); + +        if (X509_NAME_get_text_by_NID(xn, NID_commonName,  +				      buf, sizeof(buf)) == -1) { +	    ret = Strnew_charp("Unable to get common name from peer cert"); +	    return ret; +        } +	else if (strcasecmp(hostname, buf)) +	    ret = Sprintf("Bad cert ident %s from %s", buf, hostname); +	else +	    ret = NULL; +    } +    X509_free(x); +    return ret; +}  #endif  /* Raw level input stream functions */ @@ -1,4 +1,4 @@ -/* $Id: istream.h,v 1.4 2001/11/24 02:01:26 ukai Exp $ */ +/* $Id: istream.h,v 1.5 2001/12/26 12:18:06 ukai Exp $ */  #ifndef IO_STREAM_H  #define IO_STREAM_H @@ -6,6 +6,7 @@  #ifdef USE_SSL  #include <bio.h>  #include <x509.h> +#include <x509v3.h>  #include <ssl.h>  #endif  #include "Str.h" @@ -126,6 +127,7 @@ extern int ISfileno(InputStream stream);  extern int ISeos(InputStream stream);  #ifdef USE_SSL  extern Str ssl_get_certificate(InputStream stream); +extern Str ssl_check_cert_ident(SSL *handle, char *hostname);  #endif  #define IST_BASIC	0 @@ -1,4 +1,4 @@ -/* $Id: url.c,v 1.22 2001/12/07 07:58:07 ukai Exp $ */ +/* $Id: url.c,v 1.23 2001/12/26 12:18:06 ukai Exp $ */  #include "fm.h"  #include <sys/types.h>  #include <sys/socket.h> @@ -239,6 +239,7 @@ free_ssl_ctx()  {      if (ssl_ctx != NULL)  	SSL_CTX_free(ssl_ctx); +    ssl_ctx = NULL;  }  #if SSLEAY_VERSION_NUMBER >= 0x00905100 @@ -272,10 +273,12 @@ init_PRNG()  #endif				/* SSLEAY_VERSION_NUMBER >= 0x00905100 */  static SSL * -openSSLHandle(int sock) +openSSLHandle(int sock, char *hostname)  {      SSL *handle; -    char *emsg; +    Str emsg; +    Str amsg = NULL; +    char *ans;      static char *old_ssl_forbid_method = NULL;  #ifdef USE_SSL_VERIFY      static int old_ssl_verify_server = -1; @@ -288,7 +291,6 @@ openSSLHandle(int sock)  	ssl_path_modified = 1;  #else  	free_ssl_ctx(); -	ssl_ctx = NULL;  #endif      }  #ifdef USE_SSL_VERIFY @@ -298,7 +300,6 @@ openSSLHandle(int sock)      }      if (ssl_path_modified) {  	free_ssl_ctx(); -	ssl_ctx = NULL;  	ssl_path_modified = 0;      }  #endif				/* defined(USE_SSL_VERIFY) */ @@ -350,9 +351,6 @@ openSSLHandle(int sock)  #endif				/* defined(USE_SSL_VERIFY) */  	    SSL_CTX_set_default_verify_paths(ssl_ctx);  #endif				/* SSLEAY_VERSION_NUMBER >= 0x0800 */ -/*** by inu -        atexit(free_ssl_ctx); -*/      }      handle = SSL_new(ssl_ctx);      SSL_set_fd(handle, sock); @@ -361,11 +359,53 @@ openSSLHandle(int sock)  #endif				/* SSLEAY_VERSION_NUMBER >= 0x00905100 */      if (SSL_connect(handle) <= 0)  	goto eend; +#ifdef USE_SSL_VERIFY +    /* check the cert chain. +     * The chain length is automatically checked by OpenSSL when we +     * set the verify depth in the ctx. +     */ +    if (ssl_verify_server && (SSL_get_verify_result(handle) != X509_V_OK)) { +	emsg = Strnew_charp("Accept SSL session " +			    "which certificate doesn't verify (y/n)?"); +	term_raw(); +	ans = inputChar(emsg->ptr); +	if (tolower(*ans) == 'y') { +	    amsg = Strnew_charp("Accept unsecure SSL session: " +				"unverified certificate"); +	} else { +	    char *e = "This SSL session was rejected " +		"to prevent security violation"; +	    disp_err_message(e, FALSE); +	    free_ssl_ctx(); +	    return NULL; +	} +    } +#endif +     +    emsg = ssl_check_cert_ident(handle, hostname); +    if (emsg != NULL) { +	if (emsg->length > COLS - 16) +	    Strshrink(emsg, emsg->length - (COLS - 16)); +	term_raw(); +	Strcat_charp(emsg, ": accept(y/n)?"); +	ans = inputChar(emsg->ptr); +	if (tolower(*ans) == 'y') { +	    amsg = Strnew_charp("Accept unsecure SSL session:" +		"certificate ident mismatch"); +	} else { +	    char *e = "This SSL session was rejected " +		"to prevent security violation"; +	    disp_err_message(e, FALSE); +	    free_ssl_ctx(); +	    return NULL; +	} +    } +    if (amsg) +	disp_err_message(amsg->ptr, FALSE);      return handle;    eend: -    emsg = -	Sprintf("SSL error: %s", ERR_error_string(ERR_get_error(), NULL))->ptr; -    disp_err_message(emsg, FALSE); +    emsg = Sprintf("SSL error: %s", ERR_error_string(ERR_get_error(), NULL)); +    disp_err_message(emsg->ptr, FALSE);      return NULL;  } @@ -1522,7 +1562,7 @@ openURL(char *url, ParsedURL *pu, ParsedURL *current,  #ifdef USE_SSL  	    if (pu->scheme == SCM_HTTPS && *status == HTST_CONNECT) {  		sock = ssl_socket_of(ouf->stream); -		if (!(sslh = openSSLHandle(sock))) { +		if (!(sslh = openSSLHandle(sock, pu->host))) {  		    *status = HTST_MISSING;  		    return uf;  		} @@ -1576,7 +1616,7 @@ openURL(char *url, ParsedURL *pu, ParsedURL *current,  	    }  #ifdef USE_SSL  	    if (pu->scheme == SCM_HTTPS) { -		if (!(sslh = openSSLHandle(sock))) { +		if (!(sslh = openSSLHandle(sock, pu->host))) {  		    *status = HTST_MISSING;  		    return uf;  		} | 
