Commit message: Better fix for the double free in dist point parsing
CVE: CVE-2015-3308
CWE: NVD-CWE-Other
Vulnerability description: Double free vulnerability in lib/x509/x509_ext.c in GnuTLS before 3.3.14 allows remote attackers to cause a denial of service or possibly have unspecified other impact via a crafted CRL distribution point.

Project: gnutls
File: x509_ext.c

int gnutls_x509_aki_set_cert_issuer(gnutls_x509_aki_t aki,
				    unsigned int san_type,
				    const gnutls_datum_t * san,
				    const char *othername_oid,
				    const gnutls_datum_t * serial)
{
	int ret;
	gnutls_datum_t t_san, t_othername_oid = { NULL, 0 };

	ret = _gnutls_set_datum(&aki->serial, serial->data, serial->size);
	if (ret < 0)
		return gnutls_assert_val(ret);

	aki->cert_issuer.names[aki->cert_issuer.size].type = san_type;

	ret = _gnutls_set_strdatum(&t_san, san->data, san->size);
	if (ret < 0)
		return gnutls_assert_val(ret);

	if (othername_oid) {
		t_othername_oid.data = (uint8_t *) gnutls_strdup(othername_oid);
		if (t_othername_oid.data == NULL) {
			gnutls_free(t_san.data);
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
		}
		t_othername_oid.size = strlen(othername_oid);
	}

	ret =
	    subject_alt_names_set(&aki->cert_issuer.names,
				  &aki->cert_issuer.size, san_type, &t_san,
				  (char *)t_othername_oid.data);
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	return 0;
}

Project: gnutls
File: x509_ext.c

int gnutls_x509_ext_import_crl_dist_points(const gnutls_datum_t * ext,
					gnutls_x509_crl_dist_points_t cdp,
					unsigned int flags)
{
	int result;
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
	char name[ASN1_MAX_NAME_SIZE];
	int len, ret;
	uint8_t reasons[2];
	unsigned i, type, rflags, j;
	gnutls_datum_t san = {NULL, 0};

	result = asn1_create_element
	    (_gnutls_get_pkix(), "PKIX1.CRLDistributionPoints", &c2);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(result);
	}

	result = asn1_der_decoding(&c2, ext->data, ext->size, NULL);

	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(result);
		goto cleanup;
	}

	/* Return the different names from the first CRLDistr. point.
	 * The whole thing is a mess.
	 */

	i = 0;
	do {
		snprintf(name, sizeof(name), "?%u.reasons", (unsigned)i + 1);

		len = sizeof(reasons);
		result = asn1_read_value(c2, name, reasons, &len);

		if (result != ASN1_VALUE_NOT_FOUND &&
		    result != ASN1_ELEMENT_NOT_FOUND &&
		    result != ASN1_SUCCESS) {
			gnutls_assert();
			ret = _gnutls_asn2err(result);
			break;
		}

		if (result == ASN1_VALUE_NOT_FOUND
		    || result == ASN1_ELEMENT_NOT_FOUND)
			rflags = 0;
		else
			rflags = reasons[0] | (reasons[1] << 8);

		snprintf(name, sizeof(name),
			 "?%u.distributionPoint.fullName", (unsigned)i + 1);

		j = 0;
		do {
			san.data = NULL;
			san.size = 0;

			ret =
			    _gnutls_parse_general_name2(c2, name, j, &san,
							&type, 0);
			if (j > 0
			    && ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
				ret = 0;
				break;
			}
			if (ret < 0)
				break;

			ret = crl_dist_points_set(cdp, type, &san, rflags);
			if (ret < 0)
				break;
			san.data = NULL; /* it is now in cdp */

			j++;
		} while (ret >= 0);

		i++;
	} while (ret >= 0);

	if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
		gnutls_assert();
		gnutls_free(san.data);
		goto cleanup;
	}

	ret = 0;
 cleanup:
	asn1_delete_structure(&c2);
	return ret;
}

Project: gnutls
File: x509_ext.c

int gnutls_subject_alt_names_set(gnutls_subject_alt_names_t sans,
				 unsigned int san_type,
				 const gnutls_datum_t * san,
				 const char *othername_oid)
{
	int ret;
	gnutls_datum_t copy;
	char *ooc;

	ret = _gnutls_set_strdatum(&copy, san->data, san->size);
	if (ret < 0)
		return gnutls_assert_val(ret);

	if (othername_oid != NULL)
		ooc = gnutls_strdup(othername_oid);
	else
		ooc = NULL;
	ret = subject_alt_names_set(&sans->names, &sans->size,
				    san_type, &copy, ooc);
	if (ret < 0) {
		gnutls_free(copy.data);
		return gnutls_assert_val(ret);
	}

	return 0;
}