--- /dev/null
+http://cve.mitre.org/cgi-bin/cvename.cgi?name=2008-4989
+
+--- a/lib/x509/verify.c
++++ b/lib/x509/verify.c
+@@ -42,17 +42,47 @@ static int _gnutls_verify_certificate2 (
+ const gnutls_x509_crt_t * trusted_cas,
+ int tcas_size, unsigned int flags,
+ unsigned int *output);
+-int _gnutls_x509_verify_signature (const gnutls_datum_t * signed_data,
+- const gnutls_datum_t * signature,
+- gnutls_x509_crt_t issuer);
+
+-static
+- int is_crl_issuer (gnutls_x509_crl_t crl, gnutls_x509_crt_t issuer_cert);
++static int is_crl_issuer (gnutls_x509_crl_t crl,
++ gnutls_x509_crt_t issuer_cert);
++
+ static int _gnutls_verify_crl2 (gnutls_x509_crl_t crl,
+ const gnutls_x509_crt_t * trusted_cas,
+ int tcas_size, unsigned int flags,
+ unsigned int *output);
+
++/* Checks if two certs are identical. Return 0 onn match. */
++static int
++check_if_same_cert (gnutls_x509_crt_t cert1, gnutls_x509_crt_t cert2)
++{
++ gnutls_datum_t cert1bin = { NULL, 0 }, cert2bin = { NULL, 0 };
++ int result;
++
++ result = _gnutls_x509_der_encode (cert1->cert, "", &cert1bin, 0);
++ if (result < 0)
++ {
++ gnutls_assert ();
++ goto cleanup;
++ }
++
++ result = _gnutls_x509_der_encode (cert2->cert, "", &cert2bin, 0);
++ if (result < 0)
++ {
++ gnutls_assert ();
++ goto cleanup;
++ }
++
++ if ((cert1bin.size == cert2bin.size) &&
++ (memcmp (cert1bin.data, cert2bin.data, cert1bin.size) == 0))
++ result = 0;
++ else
++ result = 1;
++
++ cleanup:
++ _gnutls_free_datum (&cert1bin);
++ _gnutls_free_datum (&cert2bin);
++ return result;
++}
+
+ /* Checks if the issuer of a certificate is a
+ * Certificate Authority, or if the certificate is the same
+@@ -127,8 +157,20 @@ check_if_ca (gnutls_x509_crt_t cert, gnu
+ }
+ }
+
+- if (gnutls_x509_crt_get_ca_status (issuer, NULL) == 1)
++ result = gnutls_x509_crt_get_ca_status (issuer, NULL);
++ if (result == 1)
++ {
++ result = 1;
++ goto cleanup;
++ }
++ /* Handle V1 CAs that do not have a basicConstraint, but accept
++ these certs only if the appropriate flags are set. */
++ else if ((result == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) &&
++ ((flags & GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT) ||
++ ((flags & GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT) &&
++ (gnutls_x509_crt_check_issuer (issuer, issuer) == 1))))
+ {
++ gnutls_assert ();
+ result = 1;
+ goto cleanup;
+ }
+@@ -322,6 +364,7 @@ _gnutls_verify_certificate2 (gnutls_x509
+ {
+ if (output)
+ *output |= GNUTLS_CERT_INSECURE_ALGORITHM | GNUTLS_CERT_INVALID;
++ ret = 0;
+ }
+ }
+
+@@ -354,16 +397,12 @@ gnutls_x509_crt_check_issuer (gnutls_x50
+ }
+
+
+-/* The algorithm used is:
+- * 1. Check last certificate in the chain. If it is not verified return.
+- * 2. Check if any certificates in the chain are revoked. If yes return.
+- * 3. Try to verify the rest of certificates in the chain. If not verified return.
+- * 4. Return 0.
++/* Verify X.509 certificate chain.
+ *
+ * Note that the return value is an OR of GNUTLS_CERT_* elements.
+ *
+- * This function verifies a X.509 certificate list. The certificate list should
+- * lead to a trusted CA in order to be trusted.
++ * This function verifies a X.509 certificate list. The certificate
++ * list should lead to a trusted certificate in order to be trusted.
+ */
+ static unsigned int
+ _gnutls_x509_verify_certificate (const gnutls_x509_crt_t * certificate_list,
+@@ -376,16 +415,56 @@ _gnutls_x509_verify_certificate (const g
+ int i = 0, ret;
+ unsigned int status = 0, output;
+
++ if (clist_size > 1)
++ {
++ /* Check if the last certificate in the path is self signed.
++ * In that case ignore it (a certificate is trusted only if it
++ * leads to a trusted party by us, not the server's).
++ *
++ * This prevents from verifying self signed certificates against
++ * themselves. This (although not bad) caused verification
++ * failures on some root self signed certificates that use the
++ * MD2 algorithm.
++ */
++ if (gnutls_x509_crt_check_issuer (certificate_list[clist_size - 1],
++ certificate_list[clist_size - 1]) > 0)
++ {
++ clist_size--;
++ }
++ }
++
++ /* We want to shorten the chain by removing the cert that matches
++ * one of the certs we trust and all the certs after that i.e. if
++ * cert chain is A signed-by B signed-by C signed-by D (signed-by
++ * self-signed E but already removed above), and we trust B, remove
++ * B, C and D. We must leave the first cert on chain. */
++ if (clist_size > 1 && !(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME))
++ {
++ for (i = 1; i < clist_size; i++)
++ {
++ int j;
++
++ for (j = 0; j < tcas_size; j++)
++ {
++ if (check_if_same_cert (certificate_list[i],
++ trusted_cas[j]) == 0)
++ {
++ clist_size = i;
++ break;
++ }
++ }
++ /* clist_size may have been changed which gets out of loop */
++ }
++ }
++
+ /* Verify the last certificate in the certificate path
+ * against the trusted CA certificate list.
+ *
+ * If no CAs are present returns CERT_INVALID. Thus works
+ * in self signed etc certificates.
+ */
+- ret =
+- _gnutls_verify_certificate2 (certificate_list[clist_size - 1],
+- trusted_cas, tcas_size, flags, &output);
+-
++ ret = _gnutls_verify_certificate2 (certificate_list[clist_size - 1],
++ trusted_cas, tcas_size, flags, &output);
+ if (ret == 0)
+ {
+ /* if the last certificate in the certificate
+@@ -414,18 +493,7 @@ _gnutls_x509_verify_certificate (const g
+ }
+ #endif
+
+- /* Check if the last certificate in the path is self signed.
+- * In that case ignore it (a certificate is trusted only if it
+- * leads to a trusted party by us, not the server's).
+- */
+- if (gnutls_x509_crt_check_issuer (certificate_list[clist_size - 1],
+- certificate_list[clist_size - 1]) > 0
+- && clist_size > 0)
+- {
+- clist_size--;
+- }
+-
+- /* Verify the certificate path (chain)
++ /* Verify the certificate path (chain)
+ */
+ for (i = clist_size - 1; i > 0; i--)
+ {
+@@ -1031,6 +1099,7 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t c
+ {
+ if (output)
+ *output |= GNUTLS_CERT_INSECURE_ALGORITHM | GNUTLS_CERT_INVALID;
++ ret = 0;
+ }
+ }
+
--- /dev/null
+http://cve.mitre.org/cgi-bin/cvename.cgi?name=2009-2730
+
+--- a/lib/gnutls_str.c
++++ b/lib/gnutls_str.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2002, 2004, 2005, 2007, 2008 Free Software Foundation
++ * Copyright (C) 2002, 2004, 2005, 2007, 2008, 2009 Free Software Foundation
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+@@ -331,16 +331,21 @@ _gnutls_hex2bin (const opaque * hex_data
+
+ /* compare hostname against certificate, taking account of wildcards
+ * 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)
+ {
+ /* find the first different character */
+- for (; *certname && *hostname && toupper(*certname) == toupper(*hostname); certname++, hostname++)
++ for (; *certname && *hostname && toupper(*certname) == toupper(*hostname); certname++, hostname++, certnamesize--)
+ ;
+
+ /* the strings are the same */
+- if (strlen (certname) == 0 && strlen (hostname) == 0)
++ if (certnamesize == 0 && *hostname == '\0')
+ return 1;
+
+ if (*certname == '*')
+@@ -348,15 +353,16 @@ _gnutls_hostname_compare (const char *ce
+ /* a wildcard certificate */
+
+ certname++;
+-
++ certnamesize--;
++
+ while (1)
+ {
+ /* Use a recursive call to allow multiple wildcards */
+- if (_gnutls_hostname_compare (certname, hostname))
+- {
+- return 1;
+- }
+- /* wildcards are only allowed to match a single domain component or component fragment */
++ 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++;
+--- a/lib/gnutls_str.h
++++ b/lib/gnutls_str.h
+@@ -62,7 +62,7 @@ char *_gnutls_bin2hex (const void *old,
+ int _gnutls_hex2bin (const opaque * hex_data, int hex_size, opaque * bin_data,
+ size_t * bin_size);
+
+-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
+
+ #endif
+--- a/lib/openpgp/pgp.c
++++ b/lib/openpgp/pgp.c
+@@ -566,7 +566,7 @@ gnutls_openpgp_crt_check_hostname (gnutl
+
+ if (ret == 0)
+ {
+- if (_gnutls_hostname_compare (dnsname, hostname))
++ if (_gnutls_hostname_compare (dnsname, dnsnamesize, hostname))
+ return 1;
+ }
+ }
+--- a/lib/x509/common.c
++++ b/lib/x509/common.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation
++ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+@@ -241,6 +241,10 @@ _gnutls_x509_oid_data2string (const char
+ {
+ 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;
+@@ -291,25 +295,27 @@ _gnutls_x509_oid_data2string (const char
+ non_printable = 0;
+ }
+
+- if (res)
++ if (non_printable == 0)
+ {
+- if (non_printable == 0)
+- {
+- str[len] = 0;
+- _gnutls_str_cpy (res, *res_size, str);
+- *res_size = len;
+- }
+- else
++ 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)
+ {
+- result = _gnutls_x509_data2hex (str, len, res, res_size);
+- if (result < 0)
+- {
+- gnutls_assert ();
+- return result;
+- }
++ gnutls_assert ();
++ return result;
+ }
+ }
+-
+ }
+
+ return 0;
+--- a/lib/x509/output.c
++++ b/lib/x509/output.c
+@@ -272,6 +272,17 @@ print_crldist (gnutls_string * str, gnut
+ return;
+ }
+
++ if ((err == GNUTLS_SAN_DNSNAME
++ || err == GNUTLS_SAN_RFC822NAME
++ || err == GNUTLS_SAN_URI) &&
++ strlen (buffer) != size)
++ {
++ adds (str, _("warning: distributionPoint contains an embedded NUL, "
++ "replacing with '!'\n"));
++ while (strlen (buffer) < size)
++ buffer[strlen (buffer)] = '!';
++ }
++
+ switch (err)
+ {
+ case GNUTLS_SAN_DNSNAME:
+@@ -423,6 +434,17 @@ print_san (gnutls_string * str, gnutls_x
+ return;
+ }
+
++ if ((err == GNUTLS_SAN_DNSNAME
++ || err == GNUTLS_SAN_RFC822NAME
++ || err == GNUTLS_SAN_URI) &&
++ strlen (buffer) != size)
++ {
++ adds (str, _("warning: SAN contains an embedded NUL, "
++ "replacing with '!'\n"));
++ while (strlen (buffer) < size)
++ buffer[strlen (buffer)] = '!';
++ }
++
+ switch (err)
+ {
+ case GNUTLS_SAN_DNSNAME:
+@@ -481,7 +503,17 @@ print_san (gnutls_string * str, gnutls_x
+ }
+
+ if (err == GNUTLS_SAN_OTHERNAME_XMPP)
+- addf (str, _("\t\t\tXMPP Address: %.*s\n"), size, buffer);
++ {
++ if (strlen (buffer) != size)
++ {
++ adds (str, _("warning: SAN contains an embedded NUL, "
++ "replacing with '!'\n"));
++ while (strlen (buffer) < size)
++ buffer[strlen (buffer)] = '!';
++ }
++
++ addf (str, _("\t\t\tXMPP Address: %.*s\n"), size, buffer);
++ }
+ else
+ {
+ addf (str, _("\t\t\totherName OID: %.*s\n"), oidsize, oid);
+--- a/lib/x509/rfc2818_hostname.c
++++ b/lib/x509/rfc2818_hostname.c
+@@ -74,7 +74,7 @@ gnutls_x509_crt_check_hostname (gnutls_x
+ if (ret == GNUTLS_SAN_DNSNAME)
+ {
+ found_dnsname = 1;
+- if (_gnutls_hostname_compare (dnsname, hostname))
++ if (_gnutls_hostname_compare (dnsname, dnsnamesize, hostname))
+ {
+ return 1;
+ }
+@@ -84,7 +84,7 @@ gnutls_x509_crt_check_hostname (gnutls_x
+ found_dnsname = 1; /* RFC 2818 is unclear whether the CN
+ should be compared for IP addresses
+ too, but we won't do it. */
+- if (_gnutls_hostname_compare (dnsname, hostname))
++ if (_gnutls_hostname_compare (dnsname, dnsnamesize, hostname))
+ {
+ return 1;
+ }
+@@ -104,7 +104,7 @@ gnutls_x509_crt_check_hostname (gnutls_x
+ return 0;
+ }
+
+- if (_gnutls_hostname_compare (dnsname, hostname))
++ if (_gnutls_hostname_compare (dnsname, dnsnamesize, hostname))
+ {
+ return 1;
+ }