#
# 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
/* 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);