/*
 *  Copyright 2014-2026 The GmSSL Project. All Rights Reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the License); you may
 *  not use this file except in compliance with the License.
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 */



#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <gmssl/rand.h>
#include <gmssl/x509.h>
#include <gmssl/error.h>
#include <gmssl/sm2.h>
#include <gmssl/sm3.h>
#include <gmssl/sm4.h>
#include <gmssl/pem.h>
#include <gmssl/tls.h>


int tls_ext_to_bytes(int ext_type, const uint8_t *ext_data, size_t ext_datalen,
	uint8_t **out, size_t *outlen)
{
	if (!tls_extension_name(ext_type)) {
		error_print();
		return -1;
	}

	if (!outlen) {
		error_print();
		return -1;
	}

	tls_uint16_to_bytes(ext_type, out, outlen);
	tls_uint16array_to_bytes(ext_data, ext_datalen, out, outlen);
	return 1;
}

int tls_ext_from_bytes(int *type, const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen)
{
	uint16_t ext_type;

	if (!type || !data || !datalen || !in || !(*in) || !inlen) {
		error_print();
		return -1;
	}
	if (tls_uint16_from_bytes(&ext_type, in, inlen) != 1
		|| tls_uint16array_from_bytes(data, datalen, in, inlen) != 1) {
		error_print();
		return -1;
	}
	if (!tls_extension_name(ext_type)) {
		warning_print();
	}
	*type = ext_type;
	return 1;
}

/*
3. trusted_ca_keys

struct {
	TrustedAuthority trusted_authorities_list<0..2^16-1>;
} TrustedAuthorities;

struct {
	IdentifierType identifier_type;
	select (identifier_type) {
	case pre_agreed: struct {};
	case key_sha1_hash: SHA1Hash;
	case x509_name: DistinguishedName;
	case cert_sha1_hash: SHA1Hash;
	} identifier;
} TrustedAuthority;

enum {
	pre_agreed(0), key_sha1_hash(1), x509_name(2),
	cert_sha1_hash(3), (255)
} IdentifierType;

opaque DistinguishedName<1..2^16-1>;
*/

const char *tls_trusted_authority_type_name(int type)
{
	switch (type) {
	case TLS_trusted_authority_pre_agreed: return "pre_agreed";
	case TLS_trusted_authority_key_sha1_hash: return "key_sha1_hash";
	case TLS_trusted_authority_x509_name: return "x509_name";
	case TLS_trusted_authority_cert_sha1_hash: return "cert_sha1_hash";
	default: return NULL;
	}
}

int tls_trusted_authority_to_bytes(int type, const uint8_t *data, size_t datalen,
	uint8_t **out, size_t *outlen)
{
	if (!outlen) {
		error_print();
		return -1;
	}
	if (!tls_trusted_authority_type_name(type)) {
		error_print();
		return -1;
	}

	switch (type) {
	case TLS_trusted_authority_pre_agreed:
		if (data || datalen) {
			error_print();
			return -1;
		}
		tls_uint8_to_bytes((uint8_t)type, out, outlen);
		break;

	case TLS_trusted_authority_key_sha1_hash:
	case TLS_trusted_authority_cert_sha1_hash:
		if (!data || datalen != 20) {
			error_print();
			return -1;
		}
		tls_uint8_to_bytes((uint8_t)type, out, outlen);
		tls_array_to_bytes(data, datalen, out, outlen);
		break;

	case TLS_trusted_authority_x509_name:
		if (!data || datalen < 1 || datalen > UINT16_MAX) {
			error_print();
			return -1;
		}
		tls_uint8_to_bytes((uint8_t)type, out, outlen);
		tls_uint16array_to_bytes(data, datalen, out, outlen);
		break;
	}

	return 1;
}

int tls_trusted_authority_from_bytes(int *type, const uint8_t **data, size_t *datalen,
	const uint8_t **in, size_t *inlen)
{
	uint8_t u8;

	if (!type || !data || !datalen || !in || !(*in) || !inlen) {
		error_print();
		return -1;
	}
	if (tls_uint8_from_bytes(&u8, in, inlen) != 1) {
		error_print();
		return -1;
	}
	if (!tls_trusted_authority_type_name(u8)) {
		error_print();
		return -1;
	}

	*type = u8;
	switch (u8) {
	case TLS_trusted_authority_pre_agreed:
		*data = NULL;
		*datalen = 0;
		break;

	case TLS_trusted_authority_key_sha1_hash:
	case TLS_trusted_authority_cert_sha1_hash:
		if (*inlen < 20) {
			error_print();
			return -1;
		}
		*data = *in;
		*datalen = 20;
		*in += 20;
		*inlen -= 20;
		break;

	case TLS_trusted_authority_x509_name:
		if (tls_uint16array_from_bytes(data, datalen, in, inlen) != 1) {
			error_print();
			return -1;
		}
		if (*datalen < 1) {
			error_print();
			return -1;
		}
		break;
	}

	return 1;
}

int tls_trusted_authorities_to_bytes(const uint8_t *authorities, size_t authorities_len,
	uint8_t **out, size_t *outlen)
{
	if (!outlen) {
		error_print();
		return -1;
	}
	if (!authorities && authorities_len) {
		error_print();
		return -1;
	}
	if (authorities_len > UINT16_MAX) {
		error_print();
		return -1;
	}
	tls_uint16array_to_bytes(authorities, authorities_len, out, outlen);
	return 1;
}

int tls_trusted_authorities_from_bytes(const uint8_t **authorities, size_t *authorities_len,
	const uint8_t *data, size_t datalen)
{
	const uint8_t *p;
	size_t len;

	if (!authorities || !authorities_len) {
		error_print();
		return -1;
	}
	if (tls_uint16array_from_bytes(&p, &len, &data, &datalen) != 1
		|| tls_length_is_zero(datalen) != 1) {
		error_print();
		return -1;
	}

	*authorities = p;
	*authorities_len = len;

	while (len) {
		int type;
		const uint8_t *d;
		size_t dlen;

		if (tls_trusted_authority_from_bytes(&type, &d, &dlen, &p, &len) != 1) {
			error_print();
			return -1;
		}
		if (type == TLS_trusted_authority_x509_name) {
			const uint8_t *name;
			size_t namelen;
			if (asn1_sequence_from_der(&name, &namelen, &d, &dlen) != 1
				|| asn1_length_is_zero(dlen) != 1) {
				error_print();
				return -1;
			}
		}
	}

	return 1;
}

int tls_trusted_ca_keys_ext_to_bytes(const uint8_t *authorities, size_t authorities_len,
	uint8_t **out, size_t *outlen)
{
	uint8_t ext_data[512];
	uint8_t *p = ext_data;
	size_t len = 0;

	if (authorities_len > sizeof(ext_data) - tls_uint16_size()) {
		error_print();
		return -1;
	}
	if (tls_trusted_authorities_to_bytes(authorities, authorities_len, &p, &len) != 1) {
		error_print();
		return -1;
	}
	if (tls_ext_to_bytes(TLS_extension_trusted_ca_keys, ext_data, len, out, outlen) != 1) {
		error_print();
		return -1;
	}
	return 1;
}

int tls_trusted_authorities_from_ca_names(uint8_t *authorities, size_t *authorities_len, size_t maxlen,
	const uint8_t *ca_names, size_t ca_names_len)
{
	uint8_t *p = authorities;

	if (!authorities || !authorities_len) {
		error_print();
		return -1;
	}
	if (!ca_names && ca_names_len) {
		error_print();
		return -1;
	}
	*authorities_len = 0;

	while (ca_names_len) {
		const uint8_t *name;
		size_t namelen;
		size_t len = 0;

		if (tls_uint16array_from_bytes(&name, &namelen, &ca_names, &ca_names_len) != 1) {
			error_print();
			return -1;
		}
		if (tls_trusted_authority_to_bytes(TLS_trusted_authority_x509_name,
			name, namelen, NULL, &len) != 1) {
			error_print();
			return -1;
		}
		if (*authorities_len + len > maxlen) {
			error_print();
			return -1;
		}
		if (tls_trusted_authority_to_bytes(TLS_trusted_authority_x509_name,
			name, namelen, &p, authorities_len) != 1) {
			error_print();
			return -1;
		}
	}

	return 1;
}

int tls_trusted_authorities_print(FILE *fp, int fmt, int ind, const uint8_t *ext_data, size_t ext_datalen)
{
	const uint8_t *authorities;
	size_t authorities_len;

	format_print(fp, fmt, ind, "trusted_authorities\n");
	ind += 4;

	if (tls_trusted_authorities_from_bytes(&authorities, &authorities_len, ext_data, ext_datalen) != 1) {
		error_print();
		return -1;
	}
	while (authorities_len) {
		int type;
		const uint8_t *data;
		size_t datalen;

		if (tls_trusted_authority_from_bytes(&type, &data, &datalen, &authorities, &authorities_len) != 1) {
			error_print();
			return -1;
		}
		format_print(fp, fmt, ind, "%s (%d)\n", tls_trusted_authority_type_name(type), type);
		switch (type) {
		case TLS_trusted_authority_pre_agreed:
			break;
		case TLS_trusted_authority_key_sha1_hash:
		case TLS_trusted_authority_cert_sha1_hash:
			format_bytes(fp, fmt, ind + 4, "sha1_hash", data, datalen);
			break;
		case TLS_trusted_authority_x509_name:
			{
				const uint8_t *name;
				size_t namelen;
				if (asn1_sequence_from_der(&name, &namelen, &data, &datalen) != 1
					|| asn1_length_is_zero(datalen) != 1) {
					error_print();
					return -1;
				}
				x509_name_print(fp, fmt, ind + 4, "DistinguishedName", name, namelen);
			}
			break;
		}
	}

	return 1;
}


/*
11. ec_point_formats

struct {
	ECPointFormat ec_point_format_list<1..2^8-1>
} ECPointFormatList;

Example:
	ext_type: 0x00,0x0B (ec_point_formats)
	ext_length: 0x00,0x02
	ec_point_format_list_len: 0x01
	ec_point_format_list: 0x00 (uncompressed)
*/

const int ec_point_formats[] = { TLS_point_uncompressed };
size_t ec_point_formats_cnt = sizeof(ec_point_formats)/sizeof(ec_point_formats[0]);

int tls_ec_point_formats_support_uncompressed(const uint8_t *ext_data, size_t ext_datalen)
{
	const uint8_t *formats;
	size_t formats_len;
	int uncompressed = 0;

	if (tls_uint8array_from_bytes(&formats, &formats_len, &ext_data, &ext_datalen) != 1
		|| tls_length_is_zero(ext_datalen) != 1) {
		error_print();
		return -1;
	}
	if (!formats_len) {
		error_print();
		return -1;
	}

	while (formats_len) {
		uint8_t format;
		if (tls_uint8_from_bytes(&format, &formats, &formats_len) != 1) {
			error_print();
			return -1;
		}
		if (!tls_ec_point_format_name(format)) {
			error_print();
			return -1;
		}
		if (format == TLS_point_uncompressed) {
			uncompressed = 1;
		}
	}

	if (!uncompressed) {
		error_print();
		return 0;
	}
	return 1;
}


int tls_ec_point_formats_print(FILE *fp, int fmt, int ind, const uint8_t *ext_data, size_t ext_datalen)
{
	const uint8_t *ec_point_format_list;
	size_t ec_point_format_list_len;
	size_t i;

	format_print(fp, fmt, ind, "ec_point_format_list\n");
	ind += 4;

	if (tls_uint8array_from_bytes(&ec_point_format_list, &ec_point_format_list_len, &ext_data, &ext_datalen) != 1) {
		error_print();
		return -1;
	}
	for (i = 0; i < ec_point_format_list_len; i++) {
		format_print(fp, fmt, ind, "%s (%d)\n",
			tls_ec_point_format_name(ec_point_format_list[i]), ec_point_format_list[i]);
	}
	return 1;
}

int tls_ec_point_formats_ext_to_bytes(const int *formats, size_t formats_cnt,
	uint8_t **out, size_t *outlen)
{
	uint16_t ext_type = TLS_extension_ec_point_formats;
	size_t ext_datalen;
	size_t ec_point_format_list_len;
	size_t i;

	if (!formats || !formats_cnt || !outlen) {
		error_print();
		return -1;
	}
	ec_point_format_list_len = tls_uint8_size() * formats_cnt;
	if (ec_point_format_list_len < 1 || ec_point_format_list_len > 255) {
		error_print();
		return -1;
	}
	ext_datalen = tls_uint8_size() + ec_point_format_list_len;

	tls_uint16_to_bytes(ext_type, out, outlen);
	tls_uint16_to_bytes((uint16_t)ext_datalen, out, outlen);
	tls_uint8_to_bytes((uint8_t)ec_point_format_list_len, out, outlen);
	for (i = 0; i < formats_cnt; i++) {
		if (!tls_ec_point_format_name(formats[i])) {
			error_print();
			return -1;
		}
		tls_uint8_to_bytes((uint8_t)formats[i], out, outlen);
	}
	return 1;
}

// 似乎不应该保留process函数
int tls_process_client_ec_point_formats(const uint8_t *ext_data, size_t ext_datalen,
	uint8_t **out, size_t *outlen)
{
	int shared_formats[] = { TLS_point_uncompressed };
	size_t shared_formats_cnt = 0;
	const uint8_t *p;
	size_t len;

	if (tls_uint8array_from_bytes(&p, &len, &ext_data, &ext_datalen) != 1
		|| tls_length_is_zero(ext_datalen) != 1) {
		error_print();
		return -1;
	}
	while (len) {
		uint8_t format;
		if (tls_uint8_from_bytes(&format, &p, &len) != 1) {
			error_print();
			return -1;
		}
		if (!tls_ec_point_format_name(format)) {
			error_print();
			return -1;
		}
		if (format == shared_formats[0]) {
			shared_formats_cnt = 1;
		}
	}
	if (!shared_formats_cnt) {
		error_print();
		return -1;
	}
	if (tls_ec_point_formats_ext_to_bytes(shared_formats, shared_formats_cnt, out, outlen) != 1) {
		error_print();
		return -1;
	}
	return 1;
}

int tls_process_server_ec_point_formats(const uint8_t *ext_data, size_t ext_datalen)
{
	const uint8_t *p;
	size_t len;
	uint8_t format;

	if (tls_uint8array_from_bytes(&p, &len, &ext_data, &ext_datalen) != 1
		|| tls_length_is_zero(ext_datalen) != 1) {
		error_print();
		return -1;
	}
	if (tls_uint8_from_bytes(&format, &p, &len) != 1
		|| tls_length_is_zero(len) != 1) {
		error_print();
		return -1;
	}
	if (format != TLS_point_uncompressed) {
		error_print();
		return -1;
	}
	return 1;
}

#define TLS_MAX_SUPPORTED_GROUPS_COUNT 64


/*
supported_groups

  struct {
	NamedGroup named_group_list<2..2^16-1>;
  } NamedGroupList;

Example:
	0x00,0x0A, // ext_type = supported_groups
	0x00,0x04, // ext_length
	0x00,0x02, // named_group_list_length
	0x00,0x30, // named_group_list = [ curveSM2 ]

*/
int tls_supported_groups_ext_to_bytes(const int *groups, size_t groups_cnt,
	uint8_t **out, size_t *outlen)
{
	uint16_t ext_type = TLS_extension_supported_groups;
	size_t ext_datalen;
	size_t named_group_list_len;
	size_t i;

	if (!groups || !groups_cnt) {
		error_print();
		return -1;
	}
	if (!outlen) {
		error_print();
		return -1;
	}

	if (groups_cnt > ((1<<16) - 1)/2) {
		error_print();
		return -1;
	}
	named_group_list_len = tls_uint16_size() * groups_cnt;
	ext_datalen = tls_uint16_size() + named_group_list_len;

	tls_uint16_to_bytes(ext_type, out, outlen);
	tls_uint16_to_bytes((uint16_t)ext_datalen, out, outlen);
	tls_uint16_to_bytes((uint16_t)named_group_list_len, out, outlen);
	for (i = 0; i < groups_cnt; i++) {
		if (!tls_named_curve_name(groups[i])) {
			error_print();
			return -1;
		}
		tls_uint16_to_bytes((uint16_t)groups[i], out, outlen);
	}
	return 1;
}

int tls_supported_groups_from_bytes(int *groups, size_t *groups_cnt, size_t max_cnt,
	const uint8_t *ext_data, size_t ext_datalen)
{
	const uint8_t *named_group_list;
	size_t named_group_list_len;
	size_t i = 0;

	if (tls_uint16array_from_bytes(&named_group_list, &named_group_list_len, &ext_data, &ext_datalen) != 1
		|| tls_length_is_zero(ext_datalen) != 1) {
		error_print();
		return -1;
	}
	if (named_group_list_len < 2) {
		error_print();
		return -1;
	}
	while (named_group_list_len) {
		uint16_t group;
		if (tls_uint16_from_bytes(&group, &named_group_list, &named_group_list_len) != 1) {
			error_print();
			return -1;
		}
		if (!tls_named_curve_name(group)) {
			warning_print();
		}
		if (i < max_cnt) {
			groups[i] = group;
			i++;
		}
	}
	*groups_cnt = i;
	return 1;
}

int tls_process_supported_groups(const uint8_t *ext_data, size_t ext_datalen,
	const int *local_groups, size_t local_groups_cnt,
	int *common_groups, size_t *common_groups_cnt, size_t max_cnt)
{
	const uint8_t *named_group_list;
	size_t named_group_list_len;
	const uint8_t *cp;
	size_t len;
	uint16_t group;
	size_t i, j = 0;

	if (tls_uint16array_from_bytes(&named_group_list, &named_group_list_len, &ext_data, &ext_datalen) != 1
		|| tls_length_is_zero(ext_datalen) != 1) {
		error_print();
		return -1;
	}

	cp = named_group_list;
	len = named_group_list_len;
	while (len) {
		if (tls_uint16_from_bytes(&group, &cp, &len) != 1) {
			error_print();
			return -1;
		}
		if (!tls_named_curve_name(group)) {
			warning_print();
			//return -1;
		}
		if (group == local_groups[0] && j < max_cnt) {
			common_groups[j++] = group;
		}
	}

	for (i = 1; i < local_groups_cnt && j < max_cnt; i++) {
		cp = named_group_list;
		len = named_group_list_len;
		while (len) {
			tls_uint16_from_bytes(&group, &cp, &len);
			if (group == local_groups[i]) {
				common_groups[j++] = group;
				break;
			}
		}
	}
	*common_groups_cnt = j;

	if (*common_groups_cnt == 0) {
		return 0;
	}
	return 1;
}

int tls_supported_groups_print(FILE *fp, int fmt, int ind, const uint8_t *d, size_t dlen)
{
	const uint8_t *groups;
	size_t groups_len;

	format_print(fp, fmt, ind, "named_group_list\n");
	ind += 4;

	if (tls_uint16array_from_bytes(&groups, &groups_len, &d, &dlen) != 1) {
		error_print();
		return -1;
	}
	while (groups_len) {
		uint16_t group;
		const char *name;
		if (tls_uint16_from_bytes(&group, &groups, &groups_len) != 1) {
			error_print();
			return -1;
		}
		name = tls_named_curve_name(group);
		if (!name) {
			name = "(unknown)";
		}
		format_print(fp, fmt, ind, "%s (%04x)\n", name, group);
	}
	if (dlen) {
		error_print();
		return -1;
	}
	return 1;
}




#define TLS_MAX_SIGNATURE_ALGORS_COUNT 64

/*
signature_algorithms
signature_algorithms_cert

  struct {
	SignatureScheme supported_signature_algorithms<2..2^16-2>;
  } SignatureSchemeList;

Example:
	0x00,0x0D, // ext_type = signature_algors
	0x00,0x04, // ext_length
	0x00,0x02, // supported_signature_algorithms_length
	0x07,0x07, // supported_signature_algorithms = [ sm2sig_sm3 ]


在tls12中，只有ClientHello可以包含这个扩展，ServerHello不允许包含这个扩展
服务器在接收到这个扩展之后，如果
在 TLS 1.2 中，如果服务器收到客户端的 signature_algorithms 扩展，但发现其中没有自己支持的算法
服务器必须中止握手，并返回一个致命的 handshake_failure 警报

*/

int tls_signature_algorithms_print(FILE *fp, int fmt, int ind, const uint8_t *d, size_t dlen)
{
	const uint8_t *sig_algs;
	size_t sig_algs_len;

	if (tls_uint16array_from_bytes(&sig_algs, &sig_algs_len, &d, &dlen) != 1) {
		error_print();
		return -1;
	}

	format_print(fp, fmt, ind, "supported_signature_algorithms\n");
	ind += 4;
	while (sig_algs_len) {
		uint16_t sig_alg;
		if (tls_uint16_from_bytes(&sig_alg, &sig_algs, &sig_algs_len) != 1) {
			error_print();
			return -1;
		}
		format_print(fp, fmt, ind, "%s (%04x)\n", tls_signature_scheme_name(sig_alg), sig_alg);
	}

	if (dlen) {
		error_print();
		return -1;
	}
	return 1;
}


int tls_enable_signature_algorithms_cert(TLS_CONNECT *conn, int enable)
{
	if (!conn) {
		error_print();
		return -1;
	}
	if (!conn->ctx->signature_algorithms_cnt) {
		error_print();
		return -1;
	}
	conn->signature_algorithms_cert = enable ? 1 : 0;
	return 1;
}

int tls_signature_algorithms_ext_to_bytes_ex(int ext_type, const int *algs, size_t algs_cnt,
	uint8_t **out, size_t *outlen)
{
	size_t ext_datalen;
	size_t supported_signature_algorithms_len;
	size_t i;

	if (!algs || !algs_cnt || !outlen) {
		error_print();
		return -1;
	}
	if (algs_cnt > ((1<<16) - 2)/2) {
		error_print();
		return -1;
	}
	supported_signature_algorithms_len = tls_uint16_size() * algs_cnt;
	ext_datalen = tls_uint16_size() + supported_signature_algorithms_len;

	tls_uint16_to_bytes((uint16_t)ext_type, out, outlen);
	tls_uint16_to_bytes((uint16_t)ext_datalen, out, outlen);
	tls_uint16_to_bytes((uint16_t)supported_signature_algorithms_len, out, outlen);
	for (i = 0; i < algs_cnt; i++) {
		if (!tls_signature_scheme_name(algs[i])) {
			error_print();
			return -1;
		}
		tls_uint16_to_bytes((uint16_t)algs[i], out, outlen);
	}
	return 1;
}

int tls_signature_algorithms_ext_to_bytes(const int *algs, size_t algs_cnt,
	uint8_t **out, size_t *outlen)
{
	int ext_type = TLS_extension_signature_algorithms;
	if (tls_signature_algorithms_ext_to_bytes_ex(ext_type, algs, algs_cnt, out, outlen) != 1) {
		error_print();
		return -1;
	}
	return 1;
}

int tls13_signature_algorithms_cert_ext_to_bytes(const int *algs, size_t algs_cnt,
	uint8_t **out, size_t *outlen)
{
	int ext_type = TLS_extension_signature_algorithms_cert;
	if (tls_signature_algorithms_ext_to_bytes_ex(ext_type, algs, algs_cnt, out, outlen) != 1) {
		error_print();
		return -1;
	}
	return 1;
}

int tls_process_signature_algorithms(const uint8_t *ext_data, size_t ext_datalen,
	const int *local_sig_algs, size_t local_sig_algs_cnt,
	int *common_sig_algs, size_t *common_sig_algs_cnt, size_t max_cnt)
{
	const uint8_t *supported_sig_algs;
	size_t supported_sig_algs_len;
	const uint8_t *cp;
	size_t len;
	uint16_t sig_alg;
	size_t i, j = 0;

	if (!common_sig_algs || !common_sig_algs_cnt || !max_cnt) {
		error_print();
		return -1;
	}
	if (tls_uint16array_from_bytes(&supported_sig_algs, &supported_sig_algs_len, &ext_data, &ext_datalen) != 1
		|| tls_length_is_zero(ext_datalen) != 1) {
		error_print();
		return -1;
	}
	if (supported_sig_algs_len < 2) {
		error_print();
		return -1;
	}

	cp = supported_sig_algs;
	len = supported_sig_algs_len;
	while (len) {
		if (tls_uint16_from_bytes(&sig_alg, &cp, &len) != 1) {
			error_print();
			return -1;
		}
		if (!tls_signature_scheme_name(sig_alg)) {
			warning_print(); // FIXME
			//return -1;
		}
		if (sig_alg == local_sig_algs[0] && j < max_cnt) {
			common_sig_algs[j++] = sig_alg;
		}
	}

	for (i = 1; i < local_sig_algs_cnt && j < max_cnt; i++) {
		cp = supported_sig_algs;
		len = supported_sig_algs_len;
		while (len) {
			tls_uint16_from_bytes(&sig_alg, &cp, &len);
			if (sig_alg == local_sig_algs[i]) {
				common_sig_algs[j++] = sig_alg;
				break;
			}
		}
	}
	*common_sig_algs_cnt = j;

	if (!(*common_sig_algs_cnt)) {
		warning_print();
		return 0;
	}
	return 1;
}

int tls_signature_algorithms_ext_from_bytes(int *algs, size_t *algs_cnt, size_t max_cnt,
	const uint8_t *ext_data, size_t ext_datalen)
{
	const uint8_t *cp;
	size_t len;
	size_t i;

	if (tls_uint16array_from_bytes(&cp, &len, &ext_data, &ext_datalen) != 1
		|| tls_length_is_zero(ext_datalen) != 1) {
		error_print();
		return -1;
	}
	for (i = 0; i < max_cnt && len; i++) {
		uint16_t alg;
		if (tls_uint16_from_bytes(&alg, &cp, &len) != 1) {
			error_print();
			return -1;
		}
		if (!tls_signature_scheme_name(alg)) {
			error_print();
			return -1;
		}
		algs[i] = alg;
	}
	*algs_cnt = i;
	return 1;
}


static int tls_server_parameter_select(const int *server_params, size_t server_params_cnt,
	const int *client_params, size_t client_params_cnt,
	int *selected)
{
	size_t i, j;

	for (i = 0; i < server_params_cnt; i++) {
		*selected = server_params[i];
		for (j = 0; j < client_params_cnt; j++) {
			if (client_params[j] == *selected) {
				return 1;
			}
		}
	}
	error_print();
	return 0;
}

int tls_process_client_hello_exts(const uint8_t *exts, size_t extslen, uint8_t *out, size_t *outlen, size_t maxlen)
{
	int type;
	const uint8_t *data;
	size_t datalen;

	while (extslen) {
		if (tls_ext_from_bytes(&type, &data, &datalen, &exts, &extslen) != 1) {
			error_print();
			return -1;
		}

		switch (type) {
		case TLS_extension_ec_point_formats:
			if (tls_process_client_ec_point_formats(data, datalen, &out, outlen) != 1) {
				error_print();
				return -1;
			}
			break;
		case TLS_extension_signature_algorithms:
			/*				
			if (tls_process_client_signature_algorithms(data, datalen, &out, outlen) != 1) {
				error_print();
				return -1;
			}
			break;
		case TLS_extension_supported_groups:
			if (tls_process_client_supported_groups(data, datalen, &out, outlen) != 1) {
				error_print();
				return -1;
			}
			*/
			break;
		default:
			error_print();
			return -1;
		}
	}
	return 1;
}

int tls_process_server_hello_exts(const uint8_t *exts, size_t extslen,
	int *ec_point_format, int *supported_group, int *signature_algor)
{
	int type;
	const uint8_t *data;
	size_t datalen;

	*ec_point_format = -1;
	*supported_group = -1;
	*signature_algor = -1;

	while (extslen) {
		if (tls_ext_from_bytes(&type, &data, &datalen, &exts, &extslen) != 1) {
			error_print();
			return -1;
		}

		switch (type) {
		case TLS_extension_ec_point_formats:
			if (tls_process_server_ec_point_formats(data, datalen) != 1) {
				error_print();
				return -1;
			}
			*ec_point_format = TLS_point_uncompressed;
			break;
		case TLS_extension_signature_algorithms:
				
			/*
			if (tls_process_server_signature_algors(data, datalen) != 1) {
				error_print();
				return -1;
			}
			*supported_group = TLS_curve_sm2p256v1;
			break;
		case TLS_extension_supported_groups:
			if (tls_process_server_supported_groups(data, datalen) != 1) {
				error_print();
				return -1;
			}
			*/
			*signature_algor = TLS_sig_sm2sig_sm3;
			break;
		default:
			error_print();
			return -1;
		}
	}
	return 1;
}
