mirror of
https://github.com/guanzhi/GmSSL.git
synced 2026-11-15 09:05:00 +08:00
Clean TLS code
This commit is contained in:
@@ -818,7 +818,7 @@ endif()
|
|||||||
#
|
#
|
||||||
set(CPACK_PACKAGE_NAME "GmSSL")
|
set(CPACK_PACKAGE_NAME "GmSSL")
|
||||||
set(CPACK_PACKAGE_VENDOR "GmSSL develop team")
|
set(CPACK_PACKAGE_VENDOR "GmSSL develop team")
|
||||||
set(CPACK_PACKAGE_VERSION "3.2.0-dev.1063")
|
set(CPACK_PACKAGE_VERSION "3.2.0-dev.1064")
|
||||||
set(CPACK_PACKAGE_DESCRIPTION_FILE ${PROJECT_SOURCE_DIR}/README.md)
|
set(CPACK_PACKAGE_DESCRIPTION_FILE ${PROJECT_SOURCE_DIR}/README.md)
|
||||||
set(CPACK_NSIS_MODIFY_PATH ON)
|
set(CPACK_NSIS_MODIFY_PATH ON)
|
||||||
include(CPack)
|
include(CPack)
|
||||||
|
|||||||
@@ -1816,6 +1816,7 @@ int tls_trusted_authorities_print(FILE *fp, int fmt, int ind, const uint8_t *ext
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int tls_cipher_suite_get(int cipher_suite, const BLOCK_CIPHER **cipher, const DIGEST **digest);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1823,7 +1824,6 @@ int tls_trusted_authorities_print(FILE *fp, int fmt, int ind, const uint8_t *ext
|
|||||||
// TLS 1.3 cipher/key related
|
// TLS 1.3 cipher/key related
|
||||||
|
|
||||||
int tls13_random_generate(uint8_t random[32]);
|
int tls13_random_generate(uint8_t random[32]);
|
||||||
int tls13_cipher_suite_get(int cipher_suite, const BLOCK_CIPHER **cipher, const DIGEST **digest);
|
|
||||||
int tls13_padding_len_rand(size_t *padding_len);
|
int tls13_padding_len_rand(size_t *padding_len);
|
||||||
|
|
||||||
int tls13_gcm_encrypt(const BLOCK_CIPHER_KEY *key, const uint8_t iv[12],
|
int tls13_gcm_encrypt(const BLOCK_CIPHER_KEY *key, const uint8_t iv[12],
|
||||||
@@ -1912,6 +1912,7 @@ int tls_ctx_enable_certificate_request(TLS_CTX *ctx, int enable);
|
|||||||
// Extensions
|
// Extensions
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 0. server_name (SNI): in ClientHello, EncryptedExtensions
|
// 0. server_name (SNI): in ClientHello, EncryptedExtensions
|
||||||
int tls_set_server_name(TLS_CONNECT *conn, const uint8_t *host_name, size_t host_name_len); // client only
|
int tls_set_server_name(TLS_CONNECT *conn, const uint8_t *host_name, size_t host_name_len); // client only
|
||||||
int tls_server_name_ext_to_bytes(const uint8_t *host_name, size_t host_name_len, uint8_t **out, size_t *outlen);
|
int tls_server_name_ext_to_bytes(const uint8_t *host_name, size_t host_name_len, uint8_t **out, size_t *outlen);
|
||||||
@@ -2010,6 +2011,11 @@ int tls_process_supported_groups(const uint8_t *ext_data, size_t ext_datalen,
|
|||||||
|
|
||||||
|
|
||||||
// 11. ec_point_format
|
// 11. ec_point_format
|
||||||
|
extern const int ec_point_formats[];
|
||||||
|
extern size_t ec_point_formats_cnt;
|
||||||
|
|
||||||
|
int tls_ec_point_formats_support_uncompressed(const uint8_t *ext_data, size_t ext_datalen);
|
||||||
|
|
||||||
int tls_ec_point_formats_ext_to_bytes(const int *formats, size_t formats_cnt,
|
int tls_ec_point_formats_ext_to_bytes(const int *formats, size_t formats_cnt,
|
||||||
uint8_t **out, size_t *outlen);
|
uint8_t **out, size_t *outlen);
|
||||||
int tls_process_client_ec_point_formats(const uint8_t *ext_data, size_t ext_datalen,
|
int tls_process_client_ec_point_formats(const uint8_t *ext_data, size_t ext_datalen,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ extern "C" {
|
|||||||
|
|
||||||
|
|
||||||
#define GMSSL_VERSION_NUM 30200
|
#define GMSSL_VERSION_NUM 30200
|
||||||
#define GMSSL_VERSION_STR "GmSSL 3.2.0-dev.1063"
|
#define GMSSL_VERSION_STR "GmSSL 3.2.0-dev.1064"
|
||||||
|
|
||||||
int gmssl_version_num(void);
|
int gmssl_version_num(void);
|
||||||
const char *gmssl_version_str(void);
|
const char *gmssl_version_str(void);
|
||||||
|
|||||||
34
src/tls.c
34
src/tls.c
@@ -278,6 +278,32 @@ int tls_record_set_data(uint8_t *record, const uint8_t *data, size_t datalen)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tls_cipher_suite_get(int cipher_suite, const BLOCK_CIPHER **cipher, const DIGEST **digest)
|
||||||
|
{
|
||||||
|
switch (cipher_suite) {
|
||||||
|
case TLS_cipher_ecdhe_sm4_cbc_sm3:
|
||||||
|
case TLS_cipher_ecdhe_sm4_gcm_sm3:
|
||||||
|
case TLS_cipher_sm4_gcm_sm3:
|
||||||
|
case TLS_cipher_sm4_ccm_sm3:
|
||||||
|
*cipher = BLOCK_CIPHER_sm4();
|
||||||
|
*digest = DIGEST_sm3();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TLS_cipher_ecdhe_ecdsa_with_aes_128_cbc_sha256:
|
||||||
|
case TLS_cipher_ecdhe_ecdsa_with_aes_128_gcm_sha256:
|
||||||
|
case TLS_cipher_ecdhe_ecdsa_with_aes_128_ccm:
|
||||||
|
case TLS_cipher_aes_128_gcm_sha256:
|
||||||
|
case TLS_cipher_aes_128_ccm_sha256:
|
||||||
|
*cipher = BLOCK_CIPHER_aes128();
|
||||||
|
*digest = DIGEST_sha256();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error_print();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int tls_cbc_encrypt(const HMAC_CTX *inited_hmac_ctx, const BLOCK_CIPHER_KEY *enc_key,
|
int tls_cbc_encrypt(const HMAC_CTX *inited_hmac_ctx, const BLOCK_CIPHER_KEY *enc_key,
|
||||||
const uint8_t seq_num[8], const uint8_t header[5],
|
const uint8_t seq_num[8], const uint8_t header[5],
|
||||||
const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen)
|
const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen)
|
||||||
@@ -3321,8 +3347,6 @@ int tls_init(TLS_CONNECT *conn, TLS_CTX *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3377,3 +3401,9 @@ int tls_get_verify_result(TLS_CONNECT *conn, int *result)
|
|||||||
*result = conn->verify_result;
|
*result = conn->verify_result;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tls_clean_record(TLS_CONNECT *conn)
|
||||||
|
{
|
||||||
|
conn->record_offset = 0;
|
||||||
|
conn->recordlen = 0;
|
||||||
|
}
|
||||||
|
|||||||
2896
src/tls12.c
2896
src/tls12.c
File diff suppressed because it is too large
Load Diff
36
src/tls13.c
36
src/tls13.c
@@ -74,32 +74,6 @@ int tls13_random_generate(uint8_t random[32])
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int tls13_cipher_suite_get(int cipher_suite, const BLOCK_CIPHER **cipher, const DIGEST **digest)
|
|
||||||
{
|
|
||||||
switch (cipher_suite) {
|
|
||||||
case TLS_cipher_sm4_gcm_sm3:
|
|
||||||
#ifdef ENABLE_SM4_CCM
|
|
||||||
case TLS_cipher_sm4_ccm_sm3:
|
|
||||||
#endif
|
|
||||||
*digest = DIGEST_sm3();
|
|
||||||
*cipher = BLOCK_CIPHER_sm4();
|
|
||||||
break;
|
|
||||||
#if defined(ENABLE_AES) && defined(ENABLE_SHA2)
|
|
||||||
case TLS_cipher_aes_128_gcm_sha256:
|
|
||||||
#ifdef ENABLE_AES_CCM
|
|
||||||
case TLS_cipher_aes_128_ccm_sha256:
|
|
||||||
#endif
|
|
||||||
*digest = DIGEST_sha256();
|
|
||||||
*cipher = BLOCK_CIPHER_aes128();
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
error_print();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int tls13_padding_len_rand(size_t *padding_len)
|
int tls13_padding_len_rand(size_t *padding_len)
|
||||||
{
|
{
|
||||||
@@ -642,7 +616,7 @@ int tls13_generate_early_keys(TLS_CONNECT *conn)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tls13_cipher_suite_get(conn->psk_cipher_suites[0], &conn->cipher, &conn->digest) != 1) {
|
if (tls_cipher_suite_get(conn->psk_cipher_suites[0], &conn->cipher, &conn->digest) != 1) {
|
||||||
error_print();
|
error_print();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -4479,7 +4453,7 @@ int tls13_recv_hello_retry_request(TLS_CONNECT *conn)
|
|||||||
tls13_send_alert(conn, TLS_alert_illegal_parameter);
|
tls13_send_alert(conn, TLS_alert_illegal_parameter);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (tls13_cipher_suite_get(cipher_suite, &conn->cipher, &conn->digest) != 1) {
|
if (tls_cipher_suite_get(cipher_suite, &conn->cipher, &conn->digest) != 1) {
|
||||||
error_print();
|
error_print();
|
||||||
tls13_send_alert(conn, TLS_alert_internal_error);
|
tls13_send_alert(conn, TLS_alert_internal_error);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -5075,7 +5049,7 @@ int tls13_recv_server_hello(TLS_CONNECT *conn)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
conn->cipher_suite = cipher_suite;
|
conn->cipher_suite = cipher_suite;
|
||||||
if (tls13_cipher_suite_get(cipher_suite, &conn->cipher, &conn->digest) != 1) {
|
if (tls_cipher_suite_get(cipher_suite, &conn->cipher, &conn->digest) != 1) {
|
||||||
error_print();
|
error_print();
|
||||||
tls13_send_alert(conn, TLS_alert_internal_error);
|
tls13_send_alert(conn, TLS_alert_internal_error);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -6749,7 +6723,7 @@ static int tls13_cipher_suites_match_signature_scheme(
|
|||||||
const BLOCK_CIPHER *cipher;
|
const BLOCK_CIPHER *cipher;
|
||||||
const DIGEST *digest;
|
const DIGEST *digest;
|
||||||
|
|
||||||
if (tls13_cipher_suite_get(cipher_suites[i], &cipher, &digest) != 1) {
|
if (tls_cipher_suite_get(cipher_suites[i], &cipher, &digest) != 1) {
|
||||||
error_print();
|
error_print();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -7305,7 +7279,7 @@ int tls13_recv_client_hello(TLS_CONNECT *conn)
|
|||||||
|
|
||||||
// format_print(stderr, 0, 0, "conn->cipher_suite: %s\n", tls_cipher_suite_name(conn->cipher_suite));
|
// format_print(stderr, 0, 0, "conn->cipher_suite: %s\n", tls_cipher_suite_name(conn->cipher_suite));
|
||||||
|
|
||||||
if (tls13_cipher_suite_get(conn->cipher_suite, &conn->cipher, &conn->digest) != 1) {
|
if (tls_cipher_suite_get(conn->cipher_suite, &conn->cipher, &conn->digest) != 1) {
|
||||||
error_print();
|
error_print();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -382,6 +382,48 @@ Example:
|
|||||||
ec_point_format_list: 0x00 (uncompressed)
|
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)
|
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;
|
const uint8_t *ec_point_format_list;
|
||||||
|
|||||||
@@ -982,7 +982,7 @@ int tls13_psk_binders_generate_empty(const int *psk_cipher_suites, size_t psk_ci
|
|||||||
const BLOCK_CIPHER *cipher;
|
const BLOCK_CIPHER *cipher;
|
||||||
const DIGEST *digest;
|
const DIGEST *digest;
|
||||||
|
|
||||||
if (tls13_cipher_suite_get(psk_cipher_suites[i], &cipher, &digest) != 1) {
|
if (tls_cipher_suite_get(psk_cipher_suites[i], &cipher, &digest) != 1) {
|
||||||
error_print();
|
error_print();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1028,7 +1028,7 @@ int tls13_psk_binders_generate(
|
|||||||
size_t psk_key_len;
|
size_t psk_key_len;
|
||||||
const char *binder_label = "ext binder";
|
const char *binder_label = "ext binder";
|
||||||
|
|
||||||
if (tls13_cipher_suite_get(psk_cipher_suites[i], &cipher, &digest) != 1) {
|
if (tls_cipher_suite_get(psk_cipher_suites[i], &cipher, &digest) != 1) {
|
||||||
error_print();
|
error_print();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1260,7 +1260,7 @@ int tls13_add_pre_shared_key(TLS_CONNECT *conn,
|
|||||||
error_print();
|
error_print();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (tls13_cipher_suite_get(psk_cipher_suite, &cipher, &digest) != 1) {
|
if (tls_cipher_suite_get(psk_cipher_suite, &cipher, &digest) != 1) {
|
||||||
error_print();
|
error_print();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1421,7 +1421,7 @@ int tls13_process_client_pre_shared_key_external(TLS_CONNECT *conn,
|
|||||||
|
|
||||||
conn->cipher_suite = conn->psk_cipher_suites[matched_psk_idx];
|
conn->cipher_suite = conn->psk_cipher_suites[matched_psk_idx];
|
||||||
|
|
||||||
if (tls13_cipher_suite_get(conn->cipher_suite, &conn->cipher, &conn->digest) != 1) {
|
if (tls_cipher_suite_get(conn->cipher_suite, &conn->cipher, &conn->digest) != 1) {
|
||||||
error_print();
|
error_print();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -364,6 +364,24 @@ int tls_named_curve_from_name(const char *name)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tls_named_curve_oid(int named_curve)
|
||||||
|
{
|
||||||
|
switch (named_curve) {
|
||||||
|
case TLS_curve_secp256r1: return OID_secp256r1;
|
||||||
|
case TLS_curve_sm2p256v1: return OID_sm2;
|
||||||
|
}
|
||||||
|
return OID_undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tls_named_curve_from_oid(int oid)
|
||||||
|
{
|
||||||
|
switch (oid) {
|
||||||
|
case OID_secp256r1: return TLS_curve_secp256r1;
|
||||||
|
case OID_sm2: return TLS_curve_sm2p256v1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const char *tls_signature_scheme_name(int scheme)
|
const char *tls_signature_scheme_name(int scheme)
|
||||||
{
|
{
|
||||||
switch (scheme) {
|
switch (scheme) {
|
||||||
|
|||||||
@@ -1120,8 +1120,6 @@ int x509_general_names_print(FILE *fp, int fmt, int ind, const char *label, cons
|
|||||||
format_print(fp, fmt, ind, "%s\n", label);
|
format_print(fp, fmt, ind, "%s\n", label);
|
||||||
ind += 4;
|
ind += 4;
|
||||||
|
|
||||||
format_bytes(fp, 0, 0, "der", d, dlen);
|
|
||||||
|
|
||||||
while (dlen) {
|
while (dlen) {
|
||||||
if (x509_general_name_from_der(&choice, &p, &len, &d, &dlen) != 1) {
|
if (x509_general_name_from_der(&choice, &p, &len, &d, &dlen) != 1) {
|
||||||
error_print();
|
error_print();
|
||||||
|
|||||||
@@ -37,3 +37,7 @@
|
|||||||
"\n"
|
"\n"
|
||||||
" gmssl tlcp_server -port 4431 -cert tlcpcert.pem -key tlcpkey.pem -pass 1234 -cipher_suite TLS_ECC_SM4_CBC_SM3\n"
|
" gmssl tlcp_server -port 4431 -cert tlcpcert.pem -key tlcpkey.pem -pass 1234 -cipher_suite TLS_ECC_SM4_CBC_SM3\n"
|
||||||
" gmssl tlcp_client -port 4431 -host 127.0.0.1 -cacert sm2rootcacert.pem -cipher_suite TLS_ECC_SM4_CBC_SM3\n"
|
" gmssl tlcp_client -port 4431 -host 127.0.0.1 -cacert sm2rootcacert.pem -cipher_suite TLS_ECC_SM4_CBC_SM3\n"
|
||||||
|
"\n"
|
||||||
|
" gmssl tlcp_server -port 4431 -cert tlcpcert.pem -key tlcpkey.pem -pass 1234 -cacert sm2cacert.pem -verbose\n"
|
||||||
|
" gmssl tlcp_client -port 4431 -host 127.0.0.1 -cacert sm2rootcacert.pem -cipher_suite TLS_ECC_SM4_CBC_SM3 -cert sm2signcert.pem -key sm2signkey.pem -pass 1234 -verbose\n"
|
||||||
|
"\n"
|
||||||
|
|||||||
@@ -98,3 +98,8 @@
|
|||||||
" -supported_group prime256v1 -sig_alg ecdsa_secp256r1_sha256 \\\n"
|
" -supported_group prime256v1 -sig_alg ecdsa_secp256r1_sha256 \\\n"
|
||||||
" -cacert rootcacerts.pem\n"
|
" -cacert rootcacerts.pem\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
" gmssl tls12_server -port 4430 -cipher_suite TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 -supported_group prime256v1 -sig_alg ecdsa_secp256r1_sha256 -cert p256certs.pem -key p256signkey.pem -pass 1234 \\\n"
|
||||||
|
" -cacert p256cacert.pem -verbose -cert_request\n"
|
||||||
|
" gmssl tls12_client -host 127.0.0.1 -port 4430 -cipher_suite TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 -supported_group prime256v1 -sig_alg ecdsa_secp256r1_sha256 \\\n"
|
||||||
|
" -cert p256signcert.pem -key p256signkey.pem -pass 1234 -cacert p256rootcacert.pem -verbose\n"
|
||||||
|
"\n"
|
||||||
|
|||||||
@@ -673,7 +673,7 @@ bad:
|
|||||||
uint8_t psk_key[64];
|
uint8_t psk_key[64];
|
||||||
size_t psk_key_len;
|
size_t psk_key_len;
|
||||||
|
|
||||||
if (tls13_cipher_suite_get(psk_cipher_suites[i], &psk_cipher, &psk_digest) != 1) {
|
if (tls_cipher_suite_get(psk_cipher_suites[i], &psk_cipher, &psk_digest) != 1) {
|
||||||
error_print();
|
error_print();
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -557,7 +557,7 @@ bad:
|
|||||||
error_print();
|
error_print();
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
if (tls13_cipher_suite_get(psk_cipher_suite, &psk_cipher, &psk_digest) != 1) {
|
if (tls_cipher_suite_get(psk_cipher_suite, &psk_cipher, &psk_digest) != 1) {
|
||||||
error_print();
|
error_print();
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user