Commit message: gnutls_x509_ext_import_proxy: fix issue reading the policy language

If the language was set but the policy wasn't, that could lead to
a double free, as the value returned to the user was freed.
CVE: CVE-2017-5334
CWE: CWE-415
Vulnerability description: Double free vulnerability in the gnutls_x509_ext_import_proxy function in GnuTLS before 3.3.26 and 3.5.x before 3.5.8 allows remote attackers to have unspecified impact via crafted policy language information in an X.509 certificate with a Proxy Certificate Information extension.

Project: gnutls
File: x509_ext.c

int subject_alt_names_set(struct name_st **names,
			  unsigned int *size,
			  unsigned int san_type,
			  gnutls_datum_t * san, char *othername_oid,
			  unsigned raw)
{
	void *tmp;
	int ret;

	tmp = gnutls_realloc(*names, (*size + 1) * sizeof((*names)[0]));
	if (tmp == NULL) {
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
	}
	*names = tmp;

	ret = _gnutls_alt_name_assign_virt_type(&(*names)[*size], san_type, san, othername_oid, raw);
	if (ret < 0)
		return gnutls_assert_val(ret);

	(*size)++;
	return 0;
}

Project: gnutls
File: x509_ext.c

int _gnutls_alt_name_process(gnutls_datum_t *out, unsigned type, const gnutls_datum_t *san, unsigned raw)
{
	int ret;
	if (type == GNUTLS_SAN_DNSNAME && !raw) {
		ret = gnutls_idna_map((char*)san->data, san->size, out, 0);
		if (ret < 0) {
			return gnutls_assert_val(ret);
		}
	} else if (type == GNUTLS_SAN_RFC822NAME && !raw) {
		ret = _gnutls_idna_email_map((char*)san->data, san->size, out);
		if (ret < 0) {
			return gnutls_assert_val(ret);
		}
	} else if (type == GNUTLS_SAN_URI && !raw) {
		if (!_gnutls_str_is_print((char*)san->data, san->size)) {
			_gnutls_debug_log("non-ASCII URIs are not supported\n");
			return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
		} else {
			ret = _gnutls_set_strdatum(out, san->data, san->size);
			if (ret < 0)
				return gnutls_assert_val(ret);
		}
	} else {
		ret = _gnutls_set_strdatum(out, san->data, san->size);
		if (ret < 0)
			return gnutls_assert_val(ret);
	}

	return 0;
}

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, 0);
	if (ret < 0) {
		gnutls_free(copy.data);
		return gnutls_assert_val(ret);
	}

	return 0;
}

Project: gnutls
File: x509_ext.c

int gnutls_x509_ext_import_authority_key_id(const gnutls_datum_t * ext,
					 gnutls_x509_aki_t aki,
					 unsigned int flags)
{
	int ret;
	unsigned i;
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
	gnutls_datum_t san, othername_oid;
	unsigned type;

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

	ret = _asn1_strict_der_decode(&c2, ext->data, ext->size, NULL);
	if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(ret);
		goto cleanup;
	}

	/* Read authorityCertIssuer */
	i = 0;
	do {
		san.data = NULL;
		san.size = 0;
		othername_oid.data = NULL;

		ret = _gnutls_parse_general_name2(c2, "authorityCertIssuer", i,
						  &san, &type, 0);
		if (ret < 0)
			break;

		if (type == GNUTLS_SAN_OTHERNAME) {
			ret =
			    _gnutls_parse_general_name2(c2,
							"authorityCertIssuer",
							i,
							&othername_oid,
							NULL, 1);
			if (ret < 0)
				break;
		}

		ret = subject_alt_names_set(&aki->cert_issuer.names,
					    &aki->cert_issuer.size,
					    type, &san,
					    (char *)othername_oid.data, 1);
		if (ret < 0)
			break;

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

	aki->cert_issuer.size = i;
	if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
	    && ret != GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) {
		gnutls_assert();
		gnutls_free(san.data);
		gnutls_free(othername_oid.data);
		goto cleanup;
	}

	/* Read the serial number */
	ret =
	    _gnutls_x509_read_value(c2, "authorityCertSerialNumber",
				    &aki->serial);
	if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
	    && ret != GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) {
		gnutls_assert();
		goto cleanup;
	}

	/* Read the key identifier */
	ret = _gnutls_x509_read_value(c2, "keyIdentifier", &aki->id);
	if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
	    && ret != GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) {
		gnutls_assert();
		goto cleanup;
	}

	ret = 0;

 cleanup:
	asn1_delete_structure(&c2);

	return ret;
}

Project: gnutls
File: x509_ext.c

int gnutls_x509_ext_export_tlsfeatures(gnutls_x509_tlsfeatures_t f,
					  gnutls_datum_t * ext)
{
	if (f == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
	int ret;
	unsigned i;

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

	for (i = 0; i < f->size; ++i) {

		ret = asn1_write_value(c2, "", "NEW", 1);
		if (ret != ASN1_SUCCESS) {
			gnutls_assert();
			ret = _gnutls_asn2err(ret);
			goto cleanup;
		}

		ret = _gnutls_x509_write_uint32(c2, "?LAST", f->feature[i]);
		if (ret != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			goto cleanup;
		}
	}

	ret = _gnutls_x509_der_encode(c2, "", ext, 0);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	ret = 0;

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

Project: gnutls
File: x509_ext.c

int gnutls_x509_ext_import_policies(const gnutls_datum_t * ext,
				 gnutls_x509_policies_t policies,
				 unsigned int flags)
{
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
	char tmpstr[128];
	char tmpoid[MAX_OID_SIZE];
	gnutls_datum_t tmpd = { NULL, 0 };
	int ret, len;
	unsigned i, j, current = 0;

	ret = asn1_create_element
	    (_gnutls_get_pkix(), "PKIX1.certificatePolicies", &c2);
	if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(ret);
		goto cleanup;
	}

	ret = _asn1_strict_der_decode(&c2, ext->data, ext->size, NULL);
	if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(ret);
		goto cleanup;
	}

	for (j = 0;; j++) {
		if (j >= MAX_ENTRIES)
			break;

		memset(&policies->policy[j], 0,
		       sizeof(struct gnutls_x509_policy_st));

		/* create a string like "?1"
		 */
		snprintf(tmpstr, sizeof(tmpstr), "?%u.policyIdentifier", j + 1);
		current = j;

		ret = _gnutls_x509_read_value(c2, tmpstr, &tmpd);
		if (ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
			break;

		if (ret < 0) {
			gnutls_assert();
			goto full_cleanup;
		}

		policies->policy[j].oid = (void *)tmpd.data;
		tmpd.data = NULL;

		for (i = 0; i < GNUTLS_MAX_QUALIFIERS; i++) {
			gnutls_datum_t td;

			snprintf(tmpstr, sizeof(tmpstr),
				 "?%u.policyQualifiers.?%u.policyQualifierId",
				 j + 1, i + 1);

			len = sizeof(tmpoid);
			ret = asn1_read_value(c2, tmpstr, tmpoid, &len);

			if (ret == ASN1_ELEMENT_NOT_FOUND)
				break;	/* finished */

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

			if (strcmp(tmpoid, "1.3.6.1.5.5.7.2.1") == 0) {
				snprintf(tmpstr, sizeof(tmpstr),
					 "?%u.policyQualifiers.?%u.qualifier",
					 j + 1, i + 1);

				ret =
				    _gnutls_x509_read_string(c2, tmpstr, &td,
							     ASN1_ETYPE_IA5_STRING, 0);
				if (ret < 0) {
					gnutls_assert();
					goto full_cleanup;
				}

				policies->policy[j].qualifier[i].data =
				    (void *)td.data;
				policies->policy[j].qualifier[i].size = td.size;
				td.data = NULL;
				policies->policy[j].qualifier[i].type =
				    GNUTLS_X509_QUALIFIER_URI;
			} else if (strcmp(tmpoid, "1.3.6.1.5.5.7.2.2") == 0) {
				gnutls_datum_t txt = {NULL, 0};

				snprintf(tmpstr, sizeof(tmpstr),
					 "?%u.policyQualifiers.?%u.qualifier",
					 j + 1, i + 1);

				ret = _gnutls_x509_read_value(c2, tmpstr, &td);
				if (ret < 0) {
					gnutls_assert();
					goto full_cleanup;
				}

				ret =
				    decode_user_notice(td.data, td.size, &txt);
				gnutls_free(td.data);
				td.data = NULL;

				if (ret < 0) {
					gnutls_assert();
					goto full_cleanup;
				}

				policies->policy[j].qualifier[i].data =
				    (void *)txt.data;
				policies->policy[j].qualifier[i].size =
				    txt.size;
				policies->policy[j].qualifier[i].type =
				    GNUTLS_X509_QUALIFIER_NOTICE;
			} else
				policies->policy[j].qualifier[i].type =
				    GNUTLS_X509_QUALIFIER_UNKNOWN;

			policies->policy[j].qualifiers++;
		}

	}

	policies->size = j;

	ret = 0;
	goto cleanup;

 full_cleanup:
	for (j = 0; j < current; j++)
		gnutls_x509_policy_release(&policies->policy[j]);

 cleanup:
	_gnutls_free_datum(&tmpd);
	asn1_delete_structure(&c2);
	return ret;

}

Project: gnutls
File: x509_ext.c

int gnutls_x509_ext_import_name_constraints(const gnutls_datum_t * ext,
					 gnutls_x509_name_constraints_t nc,
					 unsigned int flags)
{
	int result, ret;
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
	gnutls_x509_name_constraints_t nc2 = NULL;

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

	result = _asn1_strict_der_decode(&c2, ext->data, ext->size, NULL);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(result);
		goto cleanup;
	}

	if (flags & GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND &&
	    (nc->permitted != NULL || nc->excluded != NULL)) {
		ret = gnutls_x509_name_constraints_init (&nc2);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		ret =
		    _gnutls_extract_name_constraints(c2, "permittedSubtrees",
						     &nc2->permitted);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		ret =
		    _gnutls_extract_name_constraints(c2, "excludedSubtrees",
						     &nc2->excluded);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		ret = _gnutls_x509_name_constraints_merge(nc, nc2);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}
	} else {
		_gnutls_name_constraints_node_free(nc->permitted);
		_gnutls_name_constraints_node_free(nc->excluded);

		ret =
		    _gnutls_extract_name_constraints(c2, "permittedSubtrees",
						     &nc->permitted);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		ret =
		    _gnutls_extract_name_constraints(c2, "excludedSubtrees",
						     &nc->excluded);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}
	}

	ret = 0;

 cleanup:
	asn1_delete_structure(&c2);
	if (nc2)
		gnutls_x509_name_constraints_deinit (nc2);

	return ret;
}

Project: gnutls
File: x509_ext.c

int gnutls_x509_tlsfeatures_add(gnutls_x509_tlsfeatures_t f, unsigned int feature)
{
	if (f == NULL) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	if (feature > UINT16_MAX)
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

	if (f->size >= sizeof(f->feature)/sizeof(f->feature[0]))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	f->feature[f->size++] = feature;

	return 0;
}

Project: gnutls
File: x509_ext.c

int gnutls_x509_ext_import_subject_alt_names(const gnutls_datum_t * ext,
					  gnutls_subject_alt_names_t sans,
					  unsigned int flags)
{
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
	int result, ret;
	unsigned int i;
	gnutls_datum_t san, othername_oid;
	unsigned type;

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

	result = _asn1_strict_der_decode(&c2, ext->data, ext->size, NULL);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(result);
		goto cleanup;
	}

	i = 0;
	do {
		san.data = NULL;
		san.size = 0;
		othername_oid.data = NULL;

		ret = _gnutls_parse_general_name2(c2, "", i, &san, &type, 0);
		if (ret < 0)
			break;

		if (type == GNUTLS_SAN_OTHERNAME) {
			ret =
			    _gnutls_parse_general_name2(c2, "", i,
							&othername_oid,
							NULL, 1);
			if (ret < 0)
				break;

		} else if (san.size == 0 || san.data == NULL) {
			ret = gnutls_assert_val(GNUTLS_E_X509_UNKNOWN_SAN);
			break;
		}

		ret = subject_alt_names_set(&sans->names, &sans->size,
					    type, &san,
					    (char *)othername_oid.data, 1);
		if (ret < 0)
			break;

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

	sans->size = i;
	if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
		gnutls_free(san.data);
		gnutls_free(othername_oid.data);
		gnutls_assert();
		goto cleanup;
	}

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

Project: gnutls
File: x509_ext.c

int gnutls_x509_ext_import_tlsfeatures(const gnutls_datum_t * ext,
				       gnutls_x509_tlsfeatures_t f,
				       unsigned int flags)
{
	int ret;
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;

	if (ext->size == 0 || ext->data == NULL) {
		gnutls_assert();
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
	}

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

	ret = _asn1_strict_der_decode(&c2, ext->data, ext->size, NULL);
	if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(ret);
		goto cleanup;
	}

	ret = parse_tlsfeatures(c2, f, flags);
	if (ret < 0) {
		gnutls_assert();
	}

 cleanup:
	asn1_delete_structure(&c2);

	return ret;
}

Project: gnutls
File: x509_ext.c

int gnutls_x509_ext_import_proxy(const gnutls_datum_t * ext, int *pathlen,
			      char **policyLanguage, char **policy,
			      size_t * sizeof_policy)
{
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
	int result;
	gnutls_datum_t value1 = { NULL, 0 };
	gnutls_datum_t value2 = { NULL, 0 };

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

	result = _asn1_strict_der_decode(&c2, ext->data, ext->size, NULL);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		result = _gnutls_asn2err(result);
		goto cleanup;
	}

	if (pathlen) {
		result = _gnutls_x509_read_uint(c2, "pCPathLenConstraint",
						(unsigned int *)
						pathlen);
		if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
			*pathlen = -1;
		else if (result != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			result = _gnutls_asn2err(result);
			goto cleanup;
		}
	}

	result = _gnutls_x509_read_value(c2, "proxyPolicy.policyLanguage",
					 &value1);
	if (result < 0) {
		gnutls_assert();
		goto cleanup;
	}

	if (policyLanguage) {
		*policyLanguage = (char *)value1.data;
		value1.data = NULL;
	}

	result = _gnutls_x509_read_value(c2, "proxyPolicy.policy", &value2);
	if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) {
		if (policy)
			*policy = NULL;
		if (sizeof_policy)
			*sizeof_policy = 0;
	} else if (result < 0) {
		gnutls_assert();
		goto cleanup;
	} else {
		if (policy) {
			*policy = (char *)value2.data;
			value2.data = NULL;
		}
		if (sizeof_policy)
			*sizeof_policy = value2.size;
	}

	result = 0;
 cleanup:
	gnutls_free(value1.data);
	gnutls_free(value2.data);
	asn1_delete_structure(&c2);

	return result;
}

Project: gnutls
File: x509_ext.c

int _gnutls_x509_decode_ext(const gnutls_datum_t *der, gnutls_x509_ext_st *out)
{
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
	char str_critical[10];
	char oid[MAX_OID_SIZE];
	int result, len, ret;

	memset(out, 0, sizeof(*out));

	/* decode der */
	result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.Extension", &c2);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		return _gnutls_asn2err(result);
	}

	result = _asn1_strict_der_decode(&c2, der->data, der->size, NULL);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(result);
		goto cleanup;
	}

	len = sizeof(oid)-1;
	result = asn1_read_value(c2, "extnID", oid, &len);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(result);
		goto cleanup;
	}

	len = sizeof(str_critical)-1;
	result = asn1_read_value(c2, "critical", str_critical, &len);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(result);
		goto cleanup;
	}

	if (str_critical[0] == 'T')
		out->critical = 1;
	else
		out->critical = 0;

	ret = _gnutls_x509_read_value(c2, "extnValue", &out->data);
	if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE || ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) {
		out->data.data = NULL;
		out->data.size = 0;
	} else if (ret < 0) {
		gnutls_assert();
		goto fail;
	}

	out->oid = gnutls_strdup(oid);
	if (out->oid == NULL) {
		ret = GNUTLS_E_MEMORY_ERROR;
		goto fail;
	}

	ret = 0;
	goto cleanup;
 fail:
	memset(out, 0, sizeof(*out));
 cleanup:
	asn1_delete_structure(&c2);
	return ret;
	
}

Project: gnutls
File: x509_ext.c

int gnutls_x509_ext_import_private_key_usage_period(const gnutls_datum_t * ext,
						 time_t * activation,
						 time_t * expiration)
{
	int result, ret;
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;

	result = asn1_create_element
	    (_gnutls_get_pkix(), "PKIX1.PrivateKeyUsagePeriod", &c2);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(result);
		goto cleanup;
	}

	result = _asn1_strict_der_decode(&c2, ext->data, ext->size, NULL);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(result);
		goto cleanup;
	}

	if (activation)
		*activation = _gnutls_x509_get_time(c2, "notBefore", 1);

	if (expiration)
		*expiration = _gnutls_x509_get_time(c2, "notAfter", 1);

	ret = 0;

 cleanup:
	asn1_delete_structure(&c2);

	return ret;
}

Project: gnutls
File: x509_ext.c

int gnutls_x509_ext_import_basic_constraints(const gnutls_datum_t * ext,
					  unsigned int *ca, int *pathlen)
{
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
	char str[128]="";
	int len, result;

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

	result = _asn1_strict_der_decode(&c2, ext->data, ext->size, NULL);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		result = _gnutls_asn2err(result);
		goto cleanup;
	}

	if (pathlen) {
		result = _gnutls_x509_read_uint(c2, "pathLenConstraint",
						(unsigned int *)
						pathlen);
		if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
			*pathlen = -1;
		else if (result != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			result = _gnutls_asn2err(result);
			goto cleanup;
		}
	}

	/* the default value of cA is false.
	 */
	len = sizeof(str) - 1;
	result = asn1_read_value(c2, "cA", str, &len);
	if (result == ASN1_SUCCESS && strcmp(str, "TRUE") == 0)
		*ca = 1;
	else
		*ca = 0;

	result = 0;
 cleanup:
	asn1_delete_structure(&c2);

	return result;

}

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_strict_der_decode(&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_x509_ext_export_subject_alt_names(gnutls_subject_alt_names_t sans,
					  gnutls_datum_t * ext)
{
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
	int result, ret;
	unsigned i;

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

	for (i = 0; i < sans->size; i++) {
		if (sans->names[i].type == GNUTLS_SAN_OTHERNAME) {
			ret = _gnutls_write_new_othername(c2, "", (char*)sans->names[i].othername_oid.data,
					      sans->names[i].san.data, sans->names[i].san.size);
		} else {
			ret =
			    _gnutls_write_new_general_name(c2, "", sans->names[i].type,
							   sans->names[i].san.data,
							   sans->names[i].san.size);
		}

		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}
	}

	ret = _gnutls_x509_der_encode(c2, "", ext, 0);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	ret = 0;

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

Project: gnutls
File: x509_ext.c

int gnutls_x509_ext_export_key_usage(unsigned int usage, gnutls_datum_t * ext)
{
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
	int result;
	uint8_t str[2];

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

	str[0] = usage & 0xff;
	str[1] = usage >> 8;

	/* Since KeyUsage is a BIT STRING, the input to asn1_write_value
	 * is the number of bits to be read. */
	result = asn1_write_value(c2, "", str, 9);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		asn1_delete_structure(&c2);
		return _gnutls_asn2err(result);
	}

	result = _gnutls_x509_der_encode(c2, "", ext, 0);

	asn1_delete_structure(&c2);

	if (result < 0) {
		gnutls_assert();
		return result;
	}

	return 0;
}

Project: gnutls
File: x509_ext.c

int gnutls_x509_ext_import_subject_key_id(const gnutls_datum_t * ext,
				       gnutls_datum_t * id)
{
	int result, ret;
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;

	if (ext->size == 0 || ext->data == NULL) {
		gnutls_assert();
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
	}

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

	result = _asn1_strict_der_decode(&c2, ext->data, ext->size, NULL);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(result);
		goto cleanup;
	}

	ret = _gnutls_x509_read_value(c2, "", id);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

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

	return ret;

}

Project: gnutls
File: x509_ext.c

int gnutls_x509_ext_import_key_purposes(const gnutls_datum_t * ext,
				     gnutls_x509_key_purposes_t p,
				     unsigned int flags)
{
	char tmpstr[ASN1_MAX_NAME_SIZE];
	int result, ret;
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
	gnutls_datum_t oid = {NULL, 0};
	unsigned i;

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

	result = _asn1_strict_der_decode(&c2, ext->data, ext->size, NULL);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(result);
		goto cleanup;
	}

	key_purposes_deinit(p);
	i = 0;
	p->size = 0;

	for (;i<MAX_ENTRIES;i++) {
		/* create a string like "?1"
		 */
		snprintf(tmpstr, sizeof(tmpstr), "?%u", i+1);

		ret = _gnutls_x509_read_value(c2, tmpstr, &oid);
		if (ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) {
			ret = 0;
			break;
		}

		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		p->oid[i].data = oid.data;
		p->oid[i].size = oid.size;

		oid.data = NULL;
		oid.size = 0;
		p->size++;
	}

	ret = 0;
 cleanup:
	gnutls_free(oid.data);
	asn1_delete_structure(&c2);

	return ret;

}

Project: gnutls
File: x509_ext.c

static int parse_tlsfeatures(ASN1_TYPE c2, gnutls_x509_tlsfeatures_t f, unsigned flags)
{
	char nptr[ASN1_MAX_NAME_SIZE];
	int result;
	unsigned i, indx, j;
	unsigned int feature;

	if (!(flags & GNUTLS_EXT_FLAG_APPEND))
		f->size = 0;

	for (i = 1;; i++) {
		unsigned skip = 0;
		snprintf(nptr, sizeof(nptr), "?%u", i);

		result = _gnutls_x509_read_uint(c2, nptr, &feature);

		if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND || result == GNUTLS_E_ASN1_VALUE_NOT_FOUND) {
			break;
		}
		else if (result != GNUTLS_E_SUCCESS) {
			gnutls_assert();
			return _gnutls_asn2err(result);
		}

		if (feature > UINT16_MAX) {
			gnutls_assert();
			return GNUTLS_E_CERTIFICATE_ERROR;
		}

		/* skip duplicates */
		for (j=0;j<f->size;j++) {
			if (f->feature[j] == feature) {
				skip = 1;
				break;
			}
		}

		if (!skip) {
			if (f->size >= sizeof(f->feature)/sizeof(f->feature[0])) {
				gnutls_assert();
				return GNUTLS_E_INTERNAL_ERROR;
			}

			indx = f->size;
			f->feature[indx] = feature;
			f->size++;
		}
	}

	return 0;
}

Project: gnutls
File: x509_ext.c

static int decode_user_notice(const void *data, size_t size,
			      gnutls_datum_t * txt)
{
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
	int ret, len;
	char choice_type[64];
	char name[128];
	gnutls_datum_t td, utd;

	ret = asn1_create_element(_gnutls_get_pkix(), "PKIX1.UserNotice", &c2);
	if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		ret = GNUTLS_E_PARSING_ERROR;
		goto cleanup;
	}

	ret = _asn1_strict_der_decode(&c2, data, size, NULL);
	if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		ret = GNUTLS_E_PARSING_ERROR;
		goto cleanup;
	}

	len = sizeof(choice_type);
	ret = asn1_read_value(c2, "explicitText", choice_type, &len);
	if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		ret = GNUTLS_E_PARSING_ERROR;
		goto cleanup;
	}

	if (strcmp(choice_type, "utf8String") != 0
	    && strcmp(choice_type, "ia5String") != 0
	    && strcmp(choice_type, "bmpString") != 0
	    && strcmp(choice_type, "visibleString") != 0) {
		gnutls_assert();
		ret = GNUTLS_E_PARSING_ERROR;
		goto cleanup;
	}

	snprintf(name, sizeof(name), "explicitText.%s", choice_type);

	ret = _gnutls_x509_read_value(c2, name, &td);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	if (strcmp(choice_type, "bmpString") == 0) {	/* convert to UTF-8 */
		ret = _gnutls_ucs2_to_utf8(td.data, td.size, &utd, 1);
		_gnutls_free_datum(&td);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		td.data = utd.data;
		td.size = utd.size;
	} else {
		/* _gnutls_x509_read_value allows that */
		td.data[td.size] = 0;
	}

	txt->data = (void *)td.data;
	txt->size = td.size;
	ret = 0;

 cleanup:
	asn1_delete_structure(&c2);
	return ret;

}

Project: gnutls
File: x509_ext.c

int gnutls_x509_ext_import_key_usage(const gnutls_datum_t * ext,
				  unsigned int *key_usage)
{
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
	int len, result;
	uint8_t str[2];

	str[0] = str[1] = 0;
	*key_usage = 0;

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

	result = _asn1_strict_der_decode(&c2, ext->data, ext->size, NULL);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		asn1_delete_structure(&c2);
		return _gnutls_asn2err(result);
	}

	len = sizeof(str);
	result = asn1_read_value(c2, "", str, &len);
	if (result != ASN1_SUCCESS) {
		gnutls_assert();
		asn1_delete_structure(&c2);
		return 0;
	}

	*key_usage = str[0] | (str[1] << 8);

	asn1_delete_structure(&c2);

	return 0;
}

Project: gnutls
File: x509_ext.c

int gnutls_x509_aia_set(gnutls_x509_aia_t aia,
			const char *oid,
			unsigned san_type,
			const gnutls_datum_t * san)
{
	int ret;
	void *tmp;
	unsigned indx;

	tmp = gnutls_realloc(aia->aia, (aia->size + 1) * sizeof(aia->aia[0]));
	if (tmp == NULL) {
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
	}
	aia->aia = tmp;
	indx = aia->size;
	
	aia->aia[indx].san_type = san_type;
	if (oid) {
		aia->aia[indx].oid.data = (void*)gnutls_strdup(oid);
		aia->aia[indx].oid.size = strlen(oid);
	} else {
		aia->aia[indx].oid.data = NULL;
		aia->aia[indx].oid.size = 0;
	}

	ret = _gnutls_alt_name_process(&aia->aia[indx].san, san_type, san, 0);
	if (ret < 0)
		return gnutls_assert_val(ret);

	aia->size++;

	return 0;	
}

Project: gnutls
File: x509_ext.c

int gnutls_x509_ext_import_aia(const gnutls_datum_t * ext,
					      gnutls_x509_aia_t aia,
					      unsigned int flags)
{
	int ret;
	ASN1_TYPE c2 = ASN1_TYPE_EMPTY;

	if (ext->size == 0 || ext->data == NULL) {
		gnutls_assert();
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
	}

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

	ret = _asn1_strict_der_decode(&c2, ext->data, ext->size, NULL);
	if (ret != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(ret);
		goto cleanup;
	}

	ret = parse_aia(c2, aia);
	if (ret < 0) {
		gnutls_assert();
	}

 cleanup:
	asn1_delete_structure(&c2);

	return ret;

}

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, 0);
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	return 0;
}