Add renegotiation_info and SCSV support

This commit is contained in:
Zhi Guan
2026-06-11 23:46:16 +08:00
parent 6ff18acae3
commit 0c974eaa25
4 changed files with 204 additions and 1 deletions

View File

@@ -901,6 +901,10 @@ typedef struct {
// 66. client_id (TLCP only) // 66. client_id (TLCP only)
int client_id; int client_id;
// 65281. renegotiation_info (TLS 1.2 only)
int renegotiation_info;
int empty_renegotiation_info_scsv;
} TLS_CTX; } TLS_CTX;
@@ -1264,6 +1268,9 @@ typedef struct {
// 66. client_id (TLCP only) // 66. client_id (TLCP only)
int client_id; int client_id;
// 65281. renegotiation_info (TLS 1.2 only)
int secure_renegotiation;
} TLS_CONNECT; } TLS_CONNECT;
@@ -1782,6 +1789,10 @@ int tls_server_name_from_bytes(const uint8_t **host_name, size_t *host_name_len,
const uint8_t *ext_data, size_t ext_datalen); const uint8_t *ext_data, size_t ext_datalen);
int tls_server_name_print(FILE *fp, int fmt, int ind, const uint8_t *ext_data, size_t ext_datalen); int tls_server_name_print(FILE *fp, int fmt, int ind, const uint8_t *ext_data, size_t ext_datalen);
// 65281. renegotiation_info (TLS 1.2 only)
int tls12_ctx_set_renegotiation_info(TLS_CTX *ctx, int enable);
int tls12_ctx_set_empty_renegotiation_info_scsv(TLS_CTX *ctx, int enable);
// 16. application_layer_protocol_negotiation // 16. application_layer_protocol_negotiation
int tls_ctx_set_application_layer_protocol_negotiation(TLS_CTX *ctx, int tls_ctx_set_application_layer_protocol_negotiation(TLS_CTX *ctx,
char *protocols[], size_t protocols_cnt); char *protocols[], size_t protocols_cnt);

View File

@@ -888,6 +888,57 @@ int tls_handshake_init(TLS_CONNECT *conn)
const int ec_point_formats[] = { TLS_point_uncompressed }; const int ec_point_formats[] = { TLS_point_uncompressed };
size_t ec_point_formats_cnt = sizeof(ec_point_formats)/sizeof(ec_point_formats[0]); size_t ec_point_formats_cnt = sizeof(ec_point_formats)/sizeof(ec_point_formats[0]);
int tls12_ctx_set_renegotiation_info(TLS_CTX *ctx, int enable)
{
if (!ctx || ctx->protocol != TLS_protocol_tls12) {
error_print();
return -1;
}
ctx->renegotiation_info = enable ? 1 : 0;
return 1;
}
int tls12_ctx_set_empty_renegotiation_info_scsv(TLS_CTX *ctx, int enable)
{
if (!ctx || ctx->protocol != TLS_protocol_tls12) {
error_print();
return -1;
}
ctx->empty_renegotiation_info_scsv = enable ? 1 : 0;
return 1;
}
static int tls12_renegotiation_info_ext_is_empty(const uint8_t *ext_data, size_t ext_datalen)
{
const uint8_t *renegotiated_connection;
size_t renegotiated_connection_len;
if (tls_uint8array_from_bytes(&renegotiated_connection, &renegotiated_connection_len,
&ext_data, &ext_datalen) != 1
|| tls_length_is_zero(ext_datalen) != 1) {
error_print();
return -1;
}
return renegotiated_connection_len == 0;
}
static int tls12_cipher_suites_include_empty_renegotiation_info_scsv(
const uint8_t *cipher_suites, size_t cipher_suites_len)
{
while (cipher_suites_len) {
uint16_t cipher_suite;
if (tls_uint16_from_bytes(&cipher_suite, &cipher_suites, &cipher_suites_len) != 1) {
error_print();
return -1;
}
if (cipher_suite == TLS_cipher_empty_renegotiation_info_scsv) {
return 1;
}
}
return 0;
}
// 有可能需要支持SNI // 有可能需要支持SNI
@@ -900,6 +951,9 @@ int tls_send_client_hello(TLS_CONNECT *conn)
uint8_t exts[TLS_MAX_EXTENSIONS_SIZE]; uint8_t exts[TLS_MAX_EXTENSIONS_SIZE];
uint8_t *pexts = exts; uint8_t *pexts = exts;
size_t extslen = 0; size_t extslen = 0;
int cipher_suites[TLS_MAX_CIPHER_SUITES_COUNT + 1];
const int *client_cipher_suites = conn->ctx->cipher_suites;
size_t client_cipher_suites_cnt = conn->ctx->cipher_suites_cnt;
tls_trace("send ClientHello\n"); tls_trace("send ClientHello\n");
@@ -943,9 +997,33 @@ int tls_send_client_hello(TLS_CONNECT *conn)
} }
} }
// renegotiation_info
if (conn->ctx->renegotiation_info) {
uint8_t ext_data[1] = { 0 };
if (conn->ctx->empty_renegotiation_info_scsv) {
error_print();
return -1;
}
if (tls_ext_to_bytes(TLS_extension_renegotiation_info,
ext_data, sizeof(ext_data), &pexts, &extslen) != 1) {
error_print();
return -1;
}
}
// TLS_EMPTY_RENEGOTIATION_INFO_SCSV
if (conn->ctx->empty_renegotiation_info_scsv) {
memcpy(cipher_suites, conn->ctx->cipher_suites,
conn->ctx->cipher_suites_cnt * sizeof(conn->ctx->cipher_suites[0]));
cipher_suites[conn->ctx->cipher_suites_cnt] = TLS_cipher_empty_renegotiation_info_scsv;
client_cipher_suites = cipher_suites;
client_cipher_suites_cnt = conn->ctx->cipher_suites_cnt + 1;
}
if (tls_record_set_handshake_client_hello(conn->record, &conn->recordlen, if (tls_record_set_handshake_client_hello(conn->record, &conn->recordlen,
conn->protocol, conn->client_random, NULL, 0, conn->protocol, conn->client_random, NULL, 0,
conn->ctx->cipher_suites, conn->ctx->cipher_suites_cnt, client_cipher_suites, client_cipher_suites_cnt,
exts, extslen) != 1) { exts, extslen) != 1) {
error_print(); error_print();
return -1; return -1;
@@ -1315,6 +1393,9 @@ int tls_recv_client_hello(TLS_CONNECT *conn)
size_t signature_algorithms_cert_len = 0; size_t signature_algorithms_cert_len = 0;
const uint8_t *server_name = NULL; const uint8_t *server_name = NULL;
size_t server_name_len = 0; size_t server_name_len = 0;
const uint8_t *renegotiation_info = NULL;
size_t renegotiation_info_len = 0;
int empty_renegotiation_info_scsv = 0;
int common_cipher_suites[TLS_MAX_CIPHER_SUITES_COUNT]; int common_cipher_suites[TLS_MAX_CIPHER_SUITES_COUNT];
size_t common_cipher_suites_cnt = 0; size_t common_cipher_suites_cnt = 0;
int common_supported_groups[32]; int common_supported_groups[32];
@@ -1388,6 +1469,7 @@ int tls_recv_client_hello(TLS_CONNECT *conn)
case TLS_extension_signature_algorithms: case TLS_extension_signature_algorithms:
case TLS_extension_signature_algorithms_cert: case TLS_extension_signature_algorithms_cert:
case TLS_extension_server_name: case TLS_extension_server_name:
case TLS_extension_renegotiation_info:
if (!ext_data) { if (!ext_data) {
error_print(); error_print();
tls_send_alert(conn, TLS_alert_decode_error); tls_send_alert(conn, TLS_alert_decode_error);
@@ -1442,11 +1524,50 @@ int tls_recv_client_hello(TLS_CONNECT *conn)
server_name = ext_data; server_name = ext_data;
server_name_len = ext_datalen; server_name_len = ext_datalen;
break; break;
case TLS_extension_renegotiation_info:
if (renegotiation_info) {
error_print();
tls_send_alert(conn, TLS_alert_illegal_parameter);
return -1;
}
renegotiation_info = ext_data;
renegotiation_info_len = ext_datalen;
break;
default: default:
warning_print(); warning_print();
} }
} }
if ((ret = tls12_cipher_suites_include_empty_renegotiation_info_scsv(
cipher_suites, cipher_suites_len)) < 0) {
error_print();
tls_send_alert(conn, TLS_alert_decode_error);
return -1;
} else if (ret == 1) {
empty_renegotiation_info_scsv = 1;
}
if (renegotiation_info && empty_renegotiation_info_scsv) {
error_print();
tls_send_alert(conn, TLS_alert_handshake_failure);
return -1;
}
if (renegotiation_info) {
if ((ret = tls12_renegotiation_info_ext_is_empty(
renegotiation_info, renegotiation_info_len)) < 0) {
error_print();
tls_send_alert(conn, TLS_alert_decode_error);
return -1;
} else if (ret == 0) {
error_print();
tls_send_alert(conn, TLS_alert_illegal_parameter);
return -1;
}
}
if (conn->ctx->renegotiation_info && (renegotiation_info || empty_renegotiation_info_scsv)) {
conn->secure_renegotiation = 1;
}
if (ec_point_formats) { if (ec_point_formats) {
if ((ret = tls_ec_point_formats_support_uncompressed(ec_point_formats, ec_point_formats_len)) < 0) { if ((ret = tls_ec_point_formats_support_uncompressed(ec_point_formats, ec_point_formats_len)) < 0) {
error_print(); error_print();
@@ -1631,6 +1752,17 @@ int tls_send_server_hello(TLS_CONNECT *conn)
} }
} }
// renegotiation_info
if (conn->secure_renegotiation) {
uint8_t ext_data[1] = { 0 };
if (tls_ext_to_bytes(TLS_extension_renegotiation_info,
ext_data, sizeof(ext_data), &pexts, &extslen) != 1) {
error_print();
return -1;
}
}
if (tls_record_set_handshake_server_hello(conn->record, &conn->recordlen, if (tls_record_set_handshake_server_hello(conn->record, &conn->recordlen,
conn->protocol, conn->server_random, NULL, 0, conn->protocol, conn->server_random, NULL, 0,
conn->cipher_suite, conn->cipher_suite,
@@ -1679,6 +1811,7 @@ int tls_recv_server_hello(TLS_CONNECT *conn)
const uint8_t *ec_point_formats = NULL; const uint8_t *ec_point_formats = NULL;
size_t ec_point_formats_len = 0; size_t ec_point_formats_len = 0;
int server_name = 0; int server_name = 0;
int renegotiation_info = 0;
tls_trace("recv ServerHello\n"); tls_trace("recv ServerHello\n");
@@ -1770,6 +1903,25 @@ int tls_recv_server_hello(TLS_CONNECT *conn)
} }
server_name = 1; server_name = 1;
break; break;
case TLS_extension_renegotiation_info:
if ((!conn->ctx->renegotiation_info && !conn->ctx->empty_renegotiation_info_scsv)
|| renegotiation_info) {
error_print();
tls_send_alert(conn, TLS_alert_illegal_parameter);
return -1;
}
if ((ret = tls12_renegotiation_info_ext_is_empty(ext_data, ext_datalen)) < 0) {
error_print();
tls_send_alert(conn, TLS_alert_decode_error);
return -1;
} else if (ret == 0) {
error_print();
tls_send_alert(conn, TLS_alert_illegal_parameter);
return -1;
}
renegotiation_info = 1;
conn->secure_renegotiation = 1;
break;
default: default:
error_print(); error_print();
tls_send_alert(conn, TLS_alert_illegal_parameter); tls_send_alert(conn, TLS_alert_illegal_parameter);
@@ -1777,6 +1929,13 @@ int tls_recv_server_hello(TLS_CONNECT *conn)
} }
} }
if ((conn->ctx->renegotiation_info || conn->ctx->empty_renegotiation_info_scsv)
&& !renegotiation_info) {
error_print();
tls_send_alert(conn, TLS_alert_handshake_failure);
return -1;
}
if (ec_point_formats) { if (ec_point_formats) {
if ((ret = tls_ec_point_formats_support_uncompressed(ec_point_formats, ec_point_formats_len)) < 0) { if ((ret = tls_ec_point_formats_support_uncompressed(ec_point_formats, ec_point_formats_len)) < 0) {
error_print(); error_print();

View File

@@ -40,6 +40,9 @@ static const char *help =
" -pass str Password to decrypt private key\n" " -pass str Password to decrypt private key\n"
" -client_cert_optional Allow client send empty Certificate\n" " -client_cert_optional Allow client send empty Certificate\n"
" -server_name str Send server_name (SNI) request\n" " -server_name str Send server_name (SNI) request\n"
" -renegotiation_info Send renegotiation_info extension\n"
" -renegotiation_info_scsv\n"
" Send TLS_EMPTY_RENEGOTIATION_INFO_SCSV\n"
" -status_request Send status_request (OCSP Stapling) request\n" " -status_request Send status_request (OCSP Stapling) request\n"
"\n" "\n"
#include "tls12_help.h" #include "tls12_help.h"
@@ -64,6 +67,8 @@ int tls12_client_main(int argc, char *argv[])
char *pass = NULL; char *pass = NULL;
int client_cert_optional = 0; int client_cert_optional = 0;
char *server_name = NULL; char *server_name = NULL;
int renegotiation_info = 0;
int empty_renegotiation_info_scsv = 0;
TLS_CTX ctx; TLS_CTX ctx;
TLS_CONNECT conn; TLS_CONNECT conn;
struct hostent *hp; struct hostent *hp;
@@ -155,6 +160,10 @@ int tls12_client_main(int argc, char *argv[])
} else if (!strcmp(*argv, "-server_name")) { } else if (!strcmp(*argv, "-server_name")) {
if (--argc < 1) goto bad; if (--argc < 1) goto bad;
server_name = *(++argv); server_name = *(++argv);
} else if (!strcmp(*argv, "-renegotiation_info")) {
renegotiation_info = 1;
} else if (!strcmp(*argv, "-renegotiation_info_scsv")) {
empty_renegotiation_info_scsv = 1;
} else if (!strcmp(*argv, "-client_cert_optional")) { } else if (!strcmp(*argv, "-client_cert_optional")) {
client_cert_optional = 1; client_cert_optional = 1;
} else { } else {
@@ -214,6 +223,19 @@ bad:
} }
} }
if (renegotiation_info) {
if (tls12_ctx_set_renegotiation_info(&ctx, 1) != 1) {
error_print();
goto end;
}
}
if (empty_renegotiation_info_scsv) {
if (tls12_ctx_set_empty_renegotiation_info_scsv(&ctx, 1) != 1) {
error_print();
goto end;
}
}
if (certfile) { if (certfile) {
if (!keyfile) { if (!keyfile) {
fprintf(stderr, "%s: option '-key' missing\n", prog); fprintf(stderr, "%s: option '-key' missing\n", prog);

View File

@@ -34,6 +34,7 @@ static const char *help =
" -cacert file CA certificate for client certificate verification\n" " -cacert file CA certificate for client certificate verification\n"
" -verify_depth num Certificate verification depth\n" " -verify_depth num Certificate verification depth\n"
" -client_cert_optional Allow client send empty Certificate\n" " -client_cert_optional Allow client send empty Certificate\n"
" -renegotiation_info Send renegotiation_info response when client supports RFC 5746\n"
"\n" "\n"
#include "tls12_help.h" #include "tls12_help.h"
"\n"; "\n";
@@ -60,6 +61,7 @@ int tls12_server_main(int argc , char **argv)
char *cacertfile = NULL; char *cacertfile = NULL;
int verify_depth = TLS_DEFAULT_VERIFY_DEPTH; int verify_depth = TLS_DEFAULT_VERIFY_DEPTH;
int client_cert_optional = 0; int client_cert_optional = 0;
int renegotiation_info = 0;
TLS_CTX ctx; TLS_CTX ctx;
TLS_CONNECT conn; TLS_CONNECT conn;
char buf[1600] = {0}; char buf[1600] = {0};
@@ -165,6 +167,8 @@ int tls12_server_main(int argc , char **argv)
} }
} else if (!strcmp(*argv, "-client_cert_optional")) { } else if (!strcmp(*argv, "-client_cert_optional")) {
client_cert_optional = 1; client_cert_optional = 1;
} else if (!strcmp(*argv, "-renegotiation_info")) {
renegotiation_info = 1;
} else { } else {
fprintf(stderr, "%s: invalid option '%s'\n", prog, *argv); fprintf(stderr, "%s: invalid option '%s'\n", prog, *argv);
return 1; return 1;
@@ -224,6 +228,13 @@ bad:
} }
} }
if (renegotiation_info) {
if (tls12_ctx_set_renegotiation_info(&ctx, 1) != 1) {
error_print();
goto end;
}
}
// Certificate // Certificate
for (i = 0; i < certfiles_cnt; i++) { for (i = 0; i < certfiles_cnt; i++) {
if (tls_ctx_add_certificate_chain_and_key(&ctx, certfiles[i], keyfiles[i], passes[i]) != 1) { if (tls_ctx_add_certificate_chain_and_key(&ctx, certfiles[i], keyfiles[i], passes[i]) != 1) {