[prev in list] [next in list] [prev in thread] [next in thread] 

List:       oss-security
Subject:    [oss-security] Re: GnuTLS CVE-2009-2730 Patches (Was Re: GnuTLS 2.8.2)
From:       Jamie Strandboge <jamie () canonical ! com>
Date:       2009-08-17 23:29:45
Message-ID: 20090817232945.GC6531 () severus ! strandboge ! com
[Download RAW message or body]

[Attachment #2 (multipart/mixed)]


On Fri, 14 Aug 2009, Jamie Strandboge wrote:

> 1.2.9 does not pass the CN test yet, though
> at first glance certtool output looks comparable to the others.

1.2.9 also needed:
http://git.savannah.gnu.org/cgit/gnutls.git/patch/?id=7b80620f99f4d43f5eda692eefc5c969bb4263c0

Attached is an updated patch for 1.2.9 (still only lightly tested, but
verified to pass the test program). This and the 2.0.4 patch previously
posted now behave the same, but different from 2.4 and higher.
Specifically, when using:

$ certtool -i --infile /tmp/badguy-nul-cn.crt

We have:
|<1>| Found OID: '2.5.4.3' with value '13187777772e62616e6b2e636f6d002e6261646775792e636f6d'
X.509 Certificate Information:
	Version: 3
	Serial Number (hex): 01
	Issuer: C=GB,ST=Berkshire,L=Newbury,O=My Company Ltd,OU=CA,CN=NULL-friendly CA
	Validity:
		Not Before: Tue Aug  4 07:33:43 UTC 2009
		Not After: Fri Aug  2 07:33:43 UTC 2019
error: get_dn: ASN1 parser: Error in DER parsing.
...


This is in contrast to 2.4 and higher which has:
X.509 Certificate Information:
	Version: 3
	Serial Number (hex): 01
	Issuer: C=GB,ST=Berkshire,L=Newbury,O=My Company Ltd,OU=CA,CN=NULL-friendly CA
	Validity:
		Not Before: Tue Aug 04 07:33:43 UTC 2009
		Not After: Fri Aug 02 07:33:43 UTC 2019
	Subject: CN=#13187777772e62616e6b2e636f6d002e6261646775792e636f6
...


Jamie

-- 
Jamie Strandboge             | http://www.canonical.com

["CVE-2009-2730_1.2.9.patch" (text/x-diff)]

#
# Upstream: http://lists.gnu.org/archive/html/help-gnutls/2009-08/msg00011.html
# Patch: adapted from upstream commits:
#        http://git.savannah.gnu.org/cgit/gnutls.git/patch/?id=177e7ddb761999cd8b439e14a2bf43590756e230
 #        http://git.savannah.gnu.org/cgit/gnutls.git/patch/?id=7b80620f99f4d43f5eda692eefc5c969bb4263c0
 #        http://git.savannah.gnu.org/cgit/gnutls.git/commit/?h=gnutls_2_8_x&id=a431be86124f900c4082e82d32917f86fcce461a
 #        http://git.savannah.gnu.org/cgit/gnutls.git/commit/?h=gnutls_2_8_x&id=74b6d92f9675ce4e03642c4d6ced4a3a614b07f6
 #        http://git.savannah.gnu.org/cgit/gnutls.git/commit/?h=gnutls_2_8_x&id=40081594e3de518b998f3e5177ed5a9f7707f2e8
 #        http://git.savannah.gnu.org/cgit/gnutls.git/patch/?id=5a58e9d33448235377afd5fbfcee1683dc70eae3
 #        http://git.savannah.gnu.org/cgit/gnutls.git/patch/?id=1ea190d216767dd4ab93b87361cbcb9d4fb3aafc
 # Description: fix improper handling of '\0' in Common Name (CN) and Subject
#              Alternative Name (SAN) in X.509 certificates. This required
#              7b80620f99f4d43f5eda692eefc5c969bb4263c0 to function properly.
#              Also backported 177e7ddb761999cd8b439e14a2bf43590756e230 for
#              added wide wildcard hostname matching so
#              _gnutls_hostname_compare() is up to date with upstream GnuTLS.
#
diff -Nur -x '*.orig' -x '*~' gnutls12-1.2.9/lib/x509/common.c \
                gnutls12-1.2.9.new/lib/x509/common.c
--- gnutls12-1.2.9/lib/x509/common.c	2005-05-26 10:21:36.000000000 -0500
+++ gnutls12-1.2.9.new/lib/x509/common.c	2009-08-17 17:44:51.932843548 -0500
@@ -220,6 +220,10 @@
     if (CHOICE == 0) {
 	str[len] = 0;
 
+	/* Refuse to deal with strings containing NULs. */
+	if (strlen (str) != len)
+	    return GNUTLS_E_ASN1_DER_ERROR;
+
 	if (res)
 	    _gnutls_str_cpy(res, *res_size, str);
 	*res_size = len;
@@ -265,20 +269,23 @@
 		non_printable = 0;
 	}
 
-	if (res) {
-	    if (non_printable == 0) {
-		str[len] = 0;
-		_gnutls_str_cpy(res, *res_size, str);
-		*res_size = len;
-	    } else {
-		result = _gnutls_x509_data2hex(str, len, res, res_size);
-		if (result < 0) {
-		    gnutls_assert();
-		    return result;
-		}
+	if (non_printable == 0) {
+	    str[len] = 0;
+
+	    /* Refuse to deal with strings containing NULs. */
+	    if (strlen (str) != len)
+		return GNUTLS_E_ASN1_DER_ERROR;
+
+	    if (res)
+		_gnutls_str_cpy (res, *res_size, str);
+	    *res_size = len;
+	} else {
+	    result = _gnutls_x509_data2hex (str, len, res, res_size);
+	    if (result < 0) {
+		gnutls_assert();
+		return result;
 	    }
 	}
-
     }
 
     return 0;
diff -Nur -x '*.orig' -x '*~' gnutls12-1.2.9/lib/x509/rfc2818.h \
                gnutls12-1.2.9.new/lib/x509/rfc2818.h
--- gnutls12-1.2.9/lib/x509/rfc2818.h	2005-05-26 10:21:36.000000000 -0500
+++ gnutls12-1.2.9.new/lib/x509/rfc2818.h	2009-08-17 17:44:51.957341882 -0500
@@ -22,5 +22,5 @@
  *
  */
 
-int _gnutls_hostname_compare(const char *certname, const char *hostname);
+int _gnutls_hostname_compare(const char *certname, size_t certnamesize, const char *hostname);
 #define MAX_CN 256
diff -Nur -x '*.orig' -x '*~' gnutls12-1.2.9/lib/x509/rfc2818_hostname.c \
                gnutls12-1.2.9.new/lib/x509/rfc2818_hostname.c
--- gnutls12-1.2.9/lib/x509/rfc2818_hostname.c	2005-05-26 10:21:36.000000000 -0500
+++ gnutls12-1.2.9.new/lib/x509/rfc2818_hostname.c	2009-08-17 17:45:34.556842923 -0500
@@ -30,39 +30,43 @@
 #include <gnutls_errors.h>
 
 /* compare hostname against certificate, taking account of wildcards
- * return 1 on success or 0 on error 
+ * return 1 on success or 0 on error
+ *
+ * note: certnamesize is required as X509 certs can contain embedded NULs in
+ * the strings such as CN or subjectAltName
  */
-int _gnutls_hostname_compare(const char *certname, const char *hostname)
+_gnutls_hostname_compare (const char *certname,
+			  size_t certnamesize,
+			  const char *hostname)
 {
-    const char *cmpstr1, *cmpstr2;
+    /* find the first different character */
+    for (; *certname && *hostname && toupper(*certname) == toupper(*hostname); certname++, \
hostname++, certnamesize--) +      ;
+
+    /* the strings are the same */
+    if (certnamesize == 0 && *hostname == '\0')
+      return 1;
 
-    if (strlen(certname) == 0 || strlen(hostname) == 0)
-	return 0;
-
-    if (strlen(certname) > 2 && strncmp(certname, "*.", 2) == 0) {
+    if (*certname == '*') {
 	/* a wildcard certificate */
 
-	cmpstr1 = certname + 1;
-
-	/* find the first dot in hostname, compare from there on */
-	cmpstr2 = strchr(hostname, '.');
-
-	if (cmpstr2 == NULL) {
-	    /* error, the hostname we're connecting to is only a local part */
-	    return 0;
-	}
+	certname++;
+	certnamesize--;
 
-	if (strcasecmp(cmpstr1, cmpstr2) == 0) {
+	while (1) {
+	  if (_gnutls_hostname_compare (certname, certnamesize, hostname))
 	    return 1;
+
+	  /* wildcards are only allowed to match a single domain
+	     component or component fragment */
+	  if (*hostname == '\0' || *hostname == '.')
+	    break;
+	  hostname++;
 	}
 
 	return 0;
     }
 
-    if (strcasecmp(certname, hostname) == 0) {
-	return 1;
-    }
-
     return 0;
 }
 
@@ -113,7 +117,7 @@
 
 	if (ret == GNUTLS_SAN_DNSNAME) {
 	    found_dnsname = 1;
-	    if (_gnutls_hostname_compare(dnsname, hostname)) {
+	    if (_gnutls_hostname_compare(dnsname, dnsnamesize, hostname)) {
 		return 1;
 	    }
 	}
@@ -128,10 +132,10 @@
 					  0, dnsname, &dnsnamesize) < 0) {
 	    /* got an error, can't find a name 
 	     */
-	    return 1;
+	    return 0;
 	}
 
-	if (_gnutls_hostname_compare(dnsname, hostname)) {
+	if (_gnutls_hostname_compare(dnsname, dnsnamesize, hostname)) {
 	    return 1;
 	}
     }
diff -Nur -x '*.orig' -x '*~' gnutls12-1.2.9/libextra/openpgp/pgp.c \
                gnutls12-1.2.9.new/libextra/openpgp/pgp.c
--- gnutls12-1.2.9/libextra/openpgp/pgp.c	2005-05-26 10:18:38.000000000 -0500
+++ gnutls12-1.2.9.new/libextra/openpgp/pgp.c	2009-08-17 17:44:51.965341542 -0500
@@ -498,7 +498,7 @@
 	dnsnamesize = sizeof(dnsname);
 	ret = gnutls_openpgp_key_get_name(key, i, dnsname, &dnsnamesize);
 
-	if (_gnutls_hostname_compare(dnsname, hostname)) {
+	if (_gnutls_hostname_compare(dnsname, dnsnamesize, hostname)) {
 	    return 1;
 	}
     }
diff -Nur -x '*.orig' -x '*~' gnutls12-1.2.9/src/certtool.c gnutls12-1.2.9.new/src/certtool.c
--- gnutls12-1.2.9/src/certtool.c	2005-11-07 12:52:12.000000000 -0600
+++ gnutls12-1.2.9.new/src/certtool.c	2009-08-17 17:44:51.965341542 -0500
@@ -1155,6 +1155,15 @@
 	if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
 	    fprintf(out, "\t\tFound unsupported alternative name.\n");
 	} else
+	    if ((ret == GNUTLS_SAN_DNSNAME
+		 || ret == GNUTLS_SAN_RFC822NAME
+		 || ret == GNUTLS_SAN_URI) &&
+		strlen (buffer) != size) {
+		    fprintf(out, "\nwarning: SAN contains an embedded NUL, "
+				   "replacing with '!'\n");
+		while (strlen (buffer) < size)
+		    buffer[strlen (buffer)] = '!';
+	    }
 	    switch (ret) {
 	    case GNUTLS_SAN_DNSNAME:
 		fprintf(out, "\t\tDNSname: %s\n", buffer);
@@ -1190,6 +1199,15 @@
 	if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
 	    fprintf(out, "\t\tError decoding: %s\n", gnutls_strerror(ret));
 	} else
+	    if ((ret == GNUTLS_SAN_DNSNAME
+		 || ret == GNUTLS_SAN_RFC822NAME
+		 || ret == GNUTLS_SAN_URI) &&
+		strlen (buffer) != size) {
+		    fprintf(out, "\nwarning: distributionPoint contains an embedded NUL, "
+				   "replacing with '!'\n");
+		while (strlen (buffer) < size)
+		    buffer[strlen (buffer)] = '!';
+	    }
 	    switch (ret) {
 	    case GNUTLS_SAN_DNSNAME:
 		fprintf(out, "\t\tDNSname: %s\n", buffer);


["signature.asc" (application/pgp-signature)]

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic