VYPR
Unrated severityNVD Advisory· Published Apr 16, 2010· Updated Apr 29, 2026

CVE-2010-1155

CVE-2010-1155

Description

Irssi before 0.8.15, when SSL is used, does not verify that the server hostname matches a domain name in the subject's Common Name (CN) field or a Subject Alternative Name field of the X.509 certificate, which allows man-in-the-middle attackers to spoof IRC servers via an arbitrary certificate.

Affected products

24
  • Irssi/Irssi24 versions
    cpe:2.3:a:irssi:irssi:0.8.0:*:*:*:*:*:*:*+ 23 more
    • cpe:2.3:a:irssi:irssi:0.8.0:*:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.1:*:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.10:*:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.10:rc5:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.10:rc6:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.10:rc7:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.10:rc8:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.11:*:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.11:rc1:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.11:rc2:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.12:*:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.12:rc1:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.13:*:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.13:rc1:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.14:*:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.2:*:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.3:*:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.4:*:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.5:*:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.6:*:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.7:*:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.8:*:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:0.8.9:*:*:*:*:*:*:*
    • cpe:2.3:a:irssi:irssi:*:rc1:*:*:*:*:*:*range: <=0.8.15

Patches

1
85bbc05b2167

Check if an SSL certificate matches the hostname of the server we are connecting to

https://github.com/ensc/irssi-proxycoekieDec 28, 2009via osv
3 files changed · +154 7
  • src/core/network.h+1 1 modified
    @@ -47,7 +47,7 @@ int net_ip_compare(IPADDR *ip1, IPADDR *ip2);
     /* Connect to socket */
     GIOChannel *net_connect(const char *addr, int port, IPADDR *my_ip);
     /* Connect to socket with ip address and SSL*/
    -GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, const char *cert, const char *pkey, const char *cafile, const char *capath, gboolean verify);
    +GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, const char* hostname, IPADDR *my_ip, const char *cert, const char *pkey, const char *cafile, const char *capath, gboolean verify);
     int irssi_ssl_handshake(GIOChannel *handle);
     /* Connect to socket with ip address */
     GIOChannel *net_connect_ip(IPADDR *ip, int port, IPADDR *my_ip);
    
  • src/core/network-openssl.c+152 5 modified
    @@ -26,6 +26,7 @@
     
     #include <openssl/crypto.h>
     #include <openssl/x509.h>
    +#include <openssl/x509v3.h>
     #include <openssl/pem.h>
     #include <openssl/ssl.h>
     #include <openssl/err.h>
    @@ -39,6 +40,7 @@ typedef struct
     	SSL *ssl;
     	SSL_CTX *ctx;
     	unsigned int verify:1;
    +	const char *hostname;
     } GIOSSLChannel;
     
     static SSL_CTX *ssl_ctx = NULL;
    @@ -53,7 +55,149 @@ static void irssi_ssl_free(GIOChannel *handle)
     	g_free(chan);
     }
     
    -static gboolean irssi_ssl_verify(SSL *ssl, SSL_CTX *ctx, X509 *cert)
    +/* Checks if the given string has internal NUL characters. */
    +static gboolean has_internal_nul(const char* str, int len) {
    +	/* Remove trailing nul characters. They would give false alarms */
    +	while (len > 0 && str[len-1] == 0)
    +		len--;
    +	return strlen(str) != len;
    +}
    +
    +/* tls_dns_name - Extract valid DNS name from subjectAltName value */
    +static const char *tls_dns_name(const GENERAL_NAME * gn)
    +{
    +	const char *dnsname;
    +
    +	/* We expect the OpenSSL library to construct GEN_DNS extension objects as
    +	   ASN1_IA5STRING values. Check we got the right union member. */
    +	if (ASN1_STRING_type(gn->d.ia5) != V_ASN1_IA5STRING) {
    +		g_warning("Invalid ASN1 value type in subjectAltName");
    +		return NULL;
    +	}
    +
    +	/* Safe to treat as an ASCII string possibly holding a DNS name */
    +	dnsname = (char *) ASN1_STRING_data(gn->d.ia5);
    +
    +	if (has_internal_nul(dnsname, ASN1_STRING_length(gn->d.ia5))) {
    +		g_warning("Internal NUL in subjectAltName");
    +		return NULL;
    +	}
    +
    +	return dnsname;
    +}
    +
    +/* tls_text_name - extract certificate property value by name */
    +static char *tls_text_name(X509_NAME *name, int nid)
    +{
    +	int     pos;
    +	X509_NAME_ENTRY *entry;
    +	ASN1_STRING *entry_str;
    +	int     utf8_length;
    +	unsigned char *utf8_value;
    +	char *result;
    +
    +	if (name == 0 || (pos = X509_NAME_get_index_by_NID(name, nid, -1)) < 0) {
    +		return NULL;
    +    }
    +
    +    entry = X509_NAME_get_entry(name, pos);
    +    g_return_val_if_fail(entry != NULL, NULL);
    +    entry_str = X509_NAME_ENTRY_get_data(entry);
    +    g_return_val_if_fail(entry_str != NULL, NULL);
    +
    +    /* Convert everything into UTF-8. It's up to OpenSSL to do something
    +	   reasonable when converting ASCII formats that contain non-ASCII
    +	   content. */
    +    if ((utf8_length = ASN1_STRING_to_UTF8(&utf8_value, entry_str)) < 0) {
    +    	g_warning("Error decoding ASN.1 type=%d", ASN1_STRING_type(entry_str));
    +    	return NULL;
    +    }
    +
    +    if (has_internal_nul((char *)utf8_value, utf8_length)) {
    +    	g_warning("NUL character in hostname in certificate");
    +    	OPENSSL_free(utf8_value);
    +    	return NULL;
    +    }
    +
    +    result = g_strdup((char *) utf8_value);
    +	OPENSSL_free(utf8_value);
    +	return result;
    +}
    +
    +
    +/** check if a hostname in the certificate matches the hostname we used for the connection */
    +static gboolean match_hostname(const char *cert_hostname, const char *hostname)
    +{
    +	const char *hostname_left;
    +
    +	if (!strcasecmp(cert_hostname, hostname)) { /* exact match */
    +		return TRUE;
    +	} else if (cert_hostname[0] == '*' && cert_hostname[1] == '.' && cert_hostname[2] != 0) { /* wildcard match */
    +		/* The initial '*' matches exactly one hostname component */
    +		hostname_left = strchr(hostname, '.');
    +		if (hostname_left != NULL && ! strcasecmp(hostname_left + 1, cert_hostname + 2)) {
    +			return TRUE;
    +		}
    +	}
    +	return FALSE;
    +}
    +
    +/* based on verify_extract_name from tls_client.c in postfix */
    +static gboolean irssi_ssl_verify_hostname(X509 *cert, const char *hostname)
    +{
    +	int gen_index, gen_count;
    +	gboolean matched = FALSE, has_dns_name = FALSE;
    +	const char *cert_dns_name;
    +	char *cert_subject_cn;
    +	const GENERAL_NAME *gn;
    +	STACK_OF(GENERAL_NAME) * gens;
    +
    +	/* Verify the dNSName(s) in the peer certificate against the hostname. */
    +	gens = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
    +	if (gens) {
    +		gen_count = sk_GENERAL_NAME_num(gens);
    +		for (gen_index = 0; gen_index < gen_count && !matched; ++gen_index) {
    +			gn = sk_GENERAL_NAME_value(gens, gen_index);
    +			if (gn->type != GEN_DNS)
    +				continue;
    +
    +			/* Even if we have an invalid DNS name, we still ultimately
    +			   ignore the CommonName, because subjectAltName:DNS is
    +			   present (though malformed). */
    +			has_dns_name = TRUE;
    +			cert_dns_name = tls_dns_name(gn);
    +			if (cert_dns_name && *cert_dns_name) {
    +				matched = match_hostname(cert_dns_name, hostname);
    +			}
    +    	}
    +
    +	    /* Free stack *and* member GENERAL_NAME objects */
    +	    sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
    +	}
    +
    +	if (has_dns_name) {
    +		if (! matched) {
    +			/* The CommonName in the issuer DN is obsolete when SubjectAltName is available. */
    +			g_warning("None of the Subject Alt Names in the certificate match hostname '%s'", hostname);
    +		}
    +		return matched;
    +	} else { /* No subjectAltNames, look at CommonName */
    +		cert_subject_cn = tls_text_name(X509_get_subject_name(cert), NID_commonName);
    +	    if (cert_subject_cn && *cert_subject_cn) {
    +	    	matched = match_hostname(cert_subject_cn, hostname);
    +	    	if (! matched) {
    +				g_warning("SSL certificate common name '%s' doesn't match host name '%s'", cert_subject_cn, hostname);
    +	    	}
    +	    } else {
    +	    	g_warning("No subjectAltNames and no valid common name in certificate");
    +	    }
    +	    free(cert_subject_cn);
    +	}
    +
    +	return matched;
    +}
    +
    +static gboolean irssi_ssl_verify(SSL *ssl, SSL_CTX *ctx, const char* hostname, X509 *cert)
     {
     	if (SSL_get_verify_result(ssl) != X509_V_OK) {
     		unsigned char md[EVP_MAX_MD_SIZE];
    @@ -89,6 +233,8 @@ static gboolean irssi_ssl_verify(SSL *ssl, SSL_CTX *ctx, X509 *cert)
     			}
     		}
     		return FALSE;
    +	} else if (! irssi_ssl_verify_hostname(cert, hostname)){
    +		return FALSE;
     	}
     	return TRUE;
     }
    @@ -241,7 +387,7 @@ static gboolean irssi_ssl_init(void)
     
     }
     
    -static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, const char *mycert, const char *mypkey, const char *cafile, const char *capath, gboolean verify)
    +static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, const char *hostname, const char *mycert, const char *mypkey, const char *cafile, const char *capath, gboolean verify)
     {
     	GIOSSLChannel *chan;
     	GIOChannel *gchan;
    @@ -326,6 +472,7 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, const char *mycer
     	chan->ssl = ssl;
     	chan->ctx = ctx;
     	chan->verify = verify;
    +	chan->hostname = hostname;
     
     	gchan = (GIOChannel *)chan;
     	gchan->funcs = &irssi_ssl_channel_funcs;
    @@ -336,14 +483,14 @@ static GIOChannel *irssi_ssl_get_iochannel(GIOChannel *handle, const char *mycer
     	return gchan;
     }
     
    -GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, IPADDR *my_ip, const char *cert, const char *pkey, const char *cafile, const char *capath, gboolean verify)
    +GIOChannel *net_connect_ip_ssl(IPADDR *ip, int port, const char* hostname, IPADDR *my_ip, const char *cert, const char *pkey, const char *cafile, const char *capath, gboolean verify)
     {
     	GIOChannel *handle, *ssl_handle;
     
     	handle = net_connect_ip(ip, port, my_ip);
     	if (handle == NULL)
     		return NULL;
    -	ssl_handle  = irssi_ssl_get_iochannel(handle, cert, pkey, cafile, capath, verify);
    +	ssl_handle  = irssi_ssl_get_iochannel(handle, hostname, cert, pkey, cafile, capath, verify);
     	if (ssl_handle == NULL)
     		g_io_channel_unref(handle);
     	return ssl_handle;
    @@ -385,7 +532,7 @@ int irssi_ssl_handshake(GIOChannel *handle)
     		g_warning("SSL server supplied no certificate");
     		return -1;
     	}
    -	ret = !chan->verify || irssi_ssl_verify(chan->ssl, chan->ctx, cert);
    +	ret = !chan->verify || irssi_ssl_verify(chan->ssl, chan->ctx, chan->hostname, cert);
     	X509_free(cert);
     	return ret ? 0 : -1;
     }
    
  • src/core/servers.c+1 1 modified
    @@ -224,7 +224,7 @@ static void server_real_connect(SERVER_REC *server, IPADDR *ip,
     		port = server->connrec->proxy != NULL ?
     			server->connrec->proxy_port : server->connrec->port;
     		handle = server->connrec->use_ssl ?
    -			net_connect_ip_ssl(ip, port, own_ip, server->connrec->ssl_cert, server->connrec->ssl_pkey,
    +			net_connect_ip_ssl(ip, port, server->connrec->address, own_ip, server->connrec->ssl_cert, server->connrec->ssl_pkey,
     server->connrec->ssl_cafile, server->connrec->ssl_capath, server->connrec->ssl_verify) :
     			net_connect_ip(ip, port, own_ip);
     	} else {
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

19

News mentions

0

No linked articles in our index yet.