Add ECDHE cipher suites to TLCP

This commit is contained in:
Zhi Guan
2026-06-24 08:12:01 +08:00
parent 24f4224fcb
commit dadd2a3e0d
16 changed files with 1083 additions and 105 deletions

View File

@@ -244,6 +244,7 @@ set(tests
sm2_key
sm2_sign
sm2_enc
sm2_exch
block_cipher
digest
hkdf
@@ -873,6 +874,8 @@ if(ENABLE_TLS AND NOT WIN32)
add_test(NAME tool_tlcp_sm4_gcm_sni COMMAND ${CMAKE_COMMAND} -DTEST_CASE=tlcp_sm4_gcm_sni -P "${CMAKE_SOURCE_DIR}/cmake/tlcp_commands.cmake")
add_test(NAME tool_tlcp_sm4_cbc_sni COMMAND ${CMAKE_COMMAND} -DTEST_CASE=tlcp_sm4_cbc_sni -P "${CMAKE_SOURCE_DIR}/cmake/tlcp_commands.cmake")
add_test(NAME tool_tlcp_sm4_gcm_client_cert COMMAND ${CMAKE_COMMAND} -DTEST_CASE=tlcp_sm4_gcm_client_cert -P "${CMAKE_SOURCE_DIR}/cmake/tlcp_commands.cmake")
add_test(NAME tool_tlcp_ecdhe_sm4_cbc_client_cert COMMAND ${CMAKE_COMMAND} -DTEST_CASE=tlcp_ecdhe_sm4_cbc_client_cert -P "${CMAKE_SOURCE_DIR}/cmake/tlcp_commands.cmake")
add_test(NAME tool_tlcp_ecdhe_sm4_gcm_client_cert COMMAND ${CMAKE_COMMAND} -DTEST_CASE=tlcp_ecdhe_sm4_gcm_client_cert -P "${CMAKE_SOURCE_DIR}/cmake/tlcp_commands.cmake")
add_test(NAME tool_tls12_sm4_gcm_sni COMMAND ${CMAKE_COMMAND} -DTEST_CASE=tls12_sm4_gcm_sni -P "${CMAKE_SOURCE_DIR}/cmake/tls12_commands.cmake")
add_test(NAME tool_tls12_sm4_cbc_sni COMMAND ${CMAKE_COMMAND} -DTEST_CASE=tls12_sm4_cbc_sni -P "${CMAKE_SOURCE_DIR}/cmake/tls12_commands.cmake")
add_test(NAME tool_tls12_sm4_gcm_client_cert COMMAND ${CMAKE_COMMAND} -DTEST_CASE=tls12_sm4_gcm_client_cert -P "${CMAKE_SOURCE_DIR}/cmake/tls12_commands.cmake")
@@ -890,6 +893,8 @@ if(ENABLE_TLS AND NOT WIN32)
tool_tlcp_sm4_gcm_sni
tool_tlcp_sm4_cbc_sni
tool_tlcp_sm4_gcm_client_cert
tool_tlcp_ecdhe_sm4_cbc_client_cert
tool_tlcp_ecdhe_sm4_gcm_client_cert
tool_tls12_sm4_gcm_sni
tool_tls12_sm4_cbc_sni
tool_tls12_sm4_gcm_client_cert
@@ -942,7 +947,7 @@ endif()
#
set(CPACK_PACKAGE_NAME "GmSSL")
set(CPACK_PACKAGE_VENDOR "GmSSL develop team")
set(CPACK_PACKAGE_VERSION "3.3.0-dev.1162")
set(CPACK_PACKAGE_VERSION "3.3.0-dev.1163")
set(CPACK_PACKAGE_DESCRIPTION_FILE ${PROJECT_SOURCE_DIR}/README.md)
set(CPACK_NSIS_MODIFY_PATH ON)
include(CPack)

View File

@@ -5,6 +5,8 @@ gmssl_require_file(sm2_tlcp_server_certs.pem)
gmssl_require_file(sm2_tlcp_server_keys.pem)
gmssl_require_file(sm2_tls_client_certs.pem)
gmssl_require_file(sm2_tls_client_key.pem)
gmssl_require_file(sm2_tlcp_client_certs.pem)
gmssl_require_file(sm2_tlcp_client_keys.pem)
if(NOT DEFINED TEST_CASE)
set(TEST_CASE tlcp_sm4_gcm_sni)
@@ -25,6 +27,18 @@ elseif(TEST_CASE STREQUAL tlcp_sm4_gcm_client_cert)
set(TEST_PORT 4436)
set(TEST_CIPHER_SUITE TLS_ECC_SM4_GCM_SM3)
set(TEST_CLIENT_CERT ON)
elseif(TEST_CASE STREQUAL tlcp_ecdhe_sm4_cbc_client_cert)
set(TEST_NAME tlcp_ecdhe_sm4_cbc_client_cert)
set(TEST_PORT 4437)
set(TEST_CIPHER_SUITE TLS_ECDHE_SM4_CBC_SM3)
set(TEST_CLIENT_CERT ON)
set(TEST_CLIENT_DOUBLE_CERT ON)
elseif(TEST_CASE STREQUAL tlcp_ecdhe_sm4_gcm_client_cert)
set(TEST_NAME tlcp_ecdhe_sm4_gcm_client_cert)
set(TEST_PORT 4438)
set(TEST_CIPHER_SUITE TLS_ECDHE_SM4_GCM_SM3)
set(TEST_CLIENT_CERT ON)
set(TEST_CLIENT_DOUBLE_CERT ON)
else()
message(FATAL_ERROR "unknown TLCP test case: ${TEST_CASE}")
endif()
@@ -50,10 +64,17 @@ if(TEST_CLIENT_CERT)
list(APPEND TEST_SERVER_ARGS
-cacert sm2_root_ca_cert.pem
-cert_request)
list(APPEND TEST_CLIENT_ARGS
-cert sm2_tls_client_certs.pem
-key sm2_tls_client_key.pem
-pass P@ssw0rd)
if(TEST_CLIENT_DOUBLE_CERT)
list(APPEND TEST_CLIENT_ARGS
-cert sm2_tlcp_client_certs.pem
-key sm2_tlcp_client_keys.pem
-pass P@ssw0rd)
else()
list(APPEND TEST_CLIENT_ARGS
-cert sm2_tls_client_certs.pem
-key sm2_tls_client_key.pem
-pass P@ssw0rd)
endif()
endif()
gmssl_run_tls_command_test(

View File

@@ -187,6 +187,20 @@ gmssl_generate_end_entity(SM2 sm2_tls_client "GmSSL SM2 TLS Client"
gmssl_write_bundle(sm2_tls_client_certs.pem
sm2_tls_client_cert.pem sm2_tls_client_ca_cert.pem)
# SM2 TLCP client chain reuses the SM2 TLS client CA and adds an encryption certificate.
gmssl_generate_end_entity(SM2 sm2_tlcp_client_sign "GmSSL SM2 TLCP Client"
sm2_tls_client_ca_cert.pem sm2_tls_client_ca_key.pem
digitalSignature clientAuth "" OFF)
gmssl_generate_end_entity(SM2 sm2_tlcp_client_enc "GmSSL SM2 TLCP Client"
sm2_tls_client_ca_cert.pem sm2_tls_client_ca_key.pem
keyEncipherment clientAuth "" OFF)
gmssl_write_bundle(sm2_tlcp_client_certs.pem
sm2_tlcp_client_sign_cert.pem
sm2_tlcp_client_enc_cert.pem
sm2_tls_client_ca_cert.pem)
gmssl_write_bundle(sm2_tlcp_client_keys.pem
sm2_tlcp_client_sign_key.pem sm2_tlcp_client_enc_key.pem)
# P256 TLS client chain: root -> client CA -> client certificate
gmssl_generate_ca(P256 p256_tls_client_ca "GmSSL P256 TLS Client CA"
p256_root_ca_cert.pem p256_root_ca_key.pem 0)

View File

@@ -254,6 +254,22 @@ int sm2_encrypt_fixlen(const SM2_KEY *key, const uint8_t *in, size_t inlen, int
int sm2_do_ecdh(const SM2_KEY *key, const SM2_KEY *peer_key, uint8_t out[32]);
int sm2_ecdh(const SM2_KEY *key, const uint8_t uncompressed_point[65], uint8_t out[32]);
int sm2_key_exchange(int is_initiator,
const SM2_KEY *key, const char *id, size_t idlen,
const SM2_KEY *peer_public_key, const char *peer_id, size_t peer_idlen,
const SM2_KEY *key_exchange, const uint8_t peer_key_exchange[65],
uint8_t optional_shared_point[65], size_t shared_key_len, uint8_t *shared_key);
int sm2_key_exchange_compute_confirm(int is_initiator,
const SM2_KEY *key, const char *id, size_t idlen,
const SM2_KEY *peer_public_key, const char *peer_id, size_t peer_idlen,
const SM2_KEY *key_exchange, const uint8_t peer_key_exchange[65],
const uint8_t shared_point[65], uint8_t confirm[32]);
int sm2_key_exchange_verify_confirm(int is_initiator,
const SM2_KEY *key, const char *id, size_t idlen,
const SM2_KEY *peer_public_key, const char *peer_id, size_t peer_idlen,
const SM2_KEY *key_exchange, const uint8_t peer_key_exchange[65],
const uint8_t shared_point[65], const uint8_t confirm[32]);
typedef struct {
sm2_z256_t k;

View File

@@ -1008,8 +1008,12 @@ int tls_ctx_set_certificate_and_key(TLS_CTX *ctx, const char *chainfile,
const char *keyfile, const char *keypass);
int tlcp_ctx_add_server_certificate_and_keys(TLS_CTX *ctx, const char *chainfile,
const char *keyfile, const char *keypass);
int tlcp_ctx_add_client_certificate_and_keys(TLS_CTX *ctx, const char *chainfile,
const char *keyfile, const char *keypass);
int tls_ctx_set_tlcp_server_certificate_and_keys(TLS_CTX *ctx, const char *chainfile,
const char *keyfile, const char *keypass);
int tls_ctx_set_tlcp_client_certificate_and_keys(TLS_CTX *ctx, const char *chainfile,
const char *keyfile, const char *keypass);
void tls_ctx_cleanup(TLS_CTX *ctx);
int tls_ctx_add_certificate_chain_and_key(TLS_CTX *ctx, const char *chainfile,

View File

@@ -18,7 +18,7 @@ extern "C" {
#define GMSSL_VERSION_NUM 30300
#define GMSSL_VERSION_STR "GmSSL 3.3.0-dev.1162"
#define GMSSL_VERSION_STR "GmSSL 3.3.0-dev.1163"
int gmssl_version_num(void);
const char *gmssl_version_str(void);

View File

@@ -55,3 +55,245 @@ int sm2_ecdh(const SM2_KEY *key, const uint8_t uncompressed_point[65], uint8_t o
gmssl_secure_clear(x, sizeof(sm2_z256_t));
return 1;
}
static int sm2_z256_point_get_x_hat(const SM2_Z256_POINT *P, sm2_z256_t x_hat)
{
sm2_z256_t x;
if (sm2_z256_point_get_xy(P, x, NULL) != 1) {
error_print();
return -1;
}
// x' = 2^127 + (x mod 2^127)
x_hat[0] = x[0];
x_hat[1] = (x[1] & 0x7fffffffffffffff) | 0x8000000000000000;
x_hat[2] = 0;
x_hat[3] = 0;
gmssl_secure_clear(x, sizeof(x));
return 1;
}
int sm2_key_exchange(int is_initiator,
const SM2_KEY *key, const char *id, size_t idlen,
const SM2_KEY *peer_public_key, const char *peer_id, size_t peer_idlen,
const SM2_KEY *key_exchange, const uint8_t peer_key_exchange[65],
uint8_t optional_shared_point[65], size_t shared_key_len, uint8_t *shared_key)
{
SM2_Z256_POINT peer_point;
SM2_Z256_POINT point;
sm2_z256_t local_x_hat;
sm2_z256_t peer_x_hat;
sm2_z256_t t;
uint8_t za[32];
uint8_t zb[32];
uint8_t kdf_input[128];
int ret = -1;
if (!key || !id || !peer_public_key || !peer_id || !key_exchange
|| !peer_key_exchange || !shared_key_len || !shared_key) {
error_print();
return -1;
}
if (idlen > SM2_MAX_ID_LENGTH || peer_idlen > SM2_MAX_ID_LENGTH) {
error_print();
return -1;
}
if (sm2_z256_point_from_octets(&peer_point, peer_key_exchange, 65) != 1) {
error_print();
goto end;
}
if (is_initiator) {
if (sm2_compute_z(za, &key->public_key, id, idlen) != 1
|| sm2_compute_z(zb, &peer_public_key->public_key, peer_id, peer_idlen) != 1) {
error_print();
goto end;
}
} else {
if (sm2_compute_z(za, &peer_public_key->public_key, peer_id, peer_idlen) != 1
|| sm2_compute_z(zb, &key->public_key, id, idlen) != 1) {
error_print();
goto end;
}
}
if (sm2_z256_point_get_x_hat(&key_exchange->public_key, local_x_hat) != 1
|| sm2_z256_point_get_x_hat(&peer_point, peer_x_hat) != 1) {
error_print();
goto end;
}
sm2_z256_modn_mul(t, local_x_hat, key_exchange->private_key);
sm2_z256_modn_add(t, t, key->private_key);
sm2_z256_point_mul(&point, peer_x_hat, &peer_point);
sm2_z256_point_add(&point, &peer_public_key->public_key, &point);
if (sm2_z256_point_is_at_infinity(&point)) {
error_print();
goto end;
}
sm2_z256_point_mul(&point, t, &point);
if (sm2_z256_point_is_at_infinity(&point)) {
error_print();
goto end;
}
if (optional_shared_point
&& sm2_z256_point_to_uncompressed_octets(&point, optional_shared_point) != 1) {
error_print();
goto end;
}
sm2_z256_point_to_bytes(&point, kdf_input);
memcpy(kdf_input + 64, za, 32);
memcpy(kdf_input + 96, zb, 32);
if (sm2_kdf(kdf_input, sizeof(kdf_input), shared_key_len, shared_key) != 1) {
error_print();
goto end;
}
if (mem_is_zero(shared_key, shared_key_len)) {
error_print();
goto end;
}
ret = 1;
end:
gmssl_secure_clear(&peer_point, sizeof(peer_point));
gmssl_secure_clear(&point, sizeof(point));
gmssl_secure_clear(local_x_hat, sizeof(local_x_hat));
gmssl_secure_clear(peer_x_hat, sizeof(peer_x_hat));
gmssl_secure_clear(t, sizeof(t));
gmssl_secure_clear(za, sizeof(za));
gmssl_secure_clear(zb, sizeof(zb));
gmssl_secure_clear(kdf_input, sizeof(kdf_input));
return ret;
}
static int sm2_key_exchange_compute_confirm_ex(int is_initiator,
const SM2_KEY *key, const char *id, size_t idlen,
const SM2_KEY *peer_public_key, const char *peer_id, size_t peer_idlen,
const SM2_KEY *key_exchange, const uint8_t peer_key_exchange[65],
const uint8_t shared_point[65], int is_initiator_confirm, uint8_t confirm[32])
{
SM2_Z256_POINT uv;
SM2_Z256_POINT peer_point;
SM2_Z256_POINT ra;
SM2_Z256_POINT rb;
uint8_t za[32];
uint8_t zb[32];
uint8_t xy[64];
uint8_t ra_bytes[64];
uint8_t rb_bytes[64];
uint8_t hash[32];
uint8_t prefix = is_initiator_confirm ? 0x03 : 0x02;
SM3_CTX ctx;
int ret = -1;
if (!key || !id || !peer_public_key || !peer_id || !key_exchange
|| !peer_key_exchange || !shared_point || !confirm) {
error_print();
return -1;
}
if (idlen > SM2_MAX_ID_LENGTH || peer_idlen > SM2_MAX_ID_LENGTH) {
error_print();
return -1;
}
if (sm2_z256_point_from_octets(&uv, shared_point, 65) != 1
|| sm2_z256_point_from_octets(&peer_point, peer_key_exchange, 65) != 1) {
error_print();
goto end;
}
if (is_initiator) {
ra = key_exchange->public_key;
rb = peer_point;
if (sm2_compute_z(za, &key->public_key, id, idlen) != 1
|| sm2_compute_z(zb, &peer_public_key->public_key, peer_id, peer_idlen) != 1) {
error_print();
goto end;
}
} else {
ra = peer_point;
rb = key_exchange->public_key;
if (sm2_compute_z(za, &peer_public_key->public_key, peer_id, peer_idlen) != 1
|| sm2_compute_z(zb, &key->public_key, id, idlen) != 1) {
error_print();
goto end;
}
}
sm2_z256_point_to_bytes(&uv, xy);
sm2_z256_point_to_bytes(&ra, ra_bytes);
sm2_z256_point_to_bytes(&rb, rb_bytes);
sm3_init(&ctx);
sm3_update(&ctx, xy, 32);
sm3_update(&ctx, za, sizeof(za));
sm3_update(&ctx, zb, sizeof(zb));
sm3_update(&ctx, ra_bytes, sizeof(ra_bytes));
sm3_update(&ctx, rb_bytes, sizeof(rb_bytes));
sm3_finish(&ctx, hash);
sm3_init(&ctx);
sm3_update(&ctx, &prefix, sizeof(prefix));
sm3_update(&ctx, xy + 32, 32);
sm3_update(&ctx, hash, sizeof(hash));
sm3_finish(&ctx, confirm);
ret = 1;
end:
gmssl_secure_clear(&uv, sizeof(uv));
gmssl_secure_clear(&peer_point, sizeof(peer_point));
gmssl_secure_clear(&ra, sizeof(ra));
gmssl_secure_clear(&rb, sizeof(rb));
gmssl_secure_clear(za, sizeof(za));
gmssl_secure_clear(zb, sizeof(zb));
gmssl_secure_clear(xy, sizeof(xy));
gmssl_secure_clear(ra_bytes, sizeof(ra_bytes));
gmssl_secure_clear(rb_bytes, sizeof(rb_bytes));
gmssl_secure_clear(hash, sizeof(hash));
gmssl_secure_clear(&ctx, sizeof(ctx));
return ret;
}
int sm2_key_exchange_compute_confirm(int is_initiator,
const SM2_KEY *key, const char *id, size_t idlen,
const SM2_KEY *peer_public_key, const char *peer_id, size_t peer_idlen,
const SM2_KEY *key_exchange, const uint8_t peer_key_exchange[65],
const uint8_t shared_point[65], uint8_t confirm[32])
{
if (sm2_key_exchange_compute_confirm_ex(is_initiator,
key, id, idlen, peer_public_key, peer_id, peer_idlen,
key_exchange, peer_key_exchange, shared_point, is_initiator, confirm) != 1) {
error_print();
return -1;
}
return 1;
}
int sm2_key_exchange_verify_confirm(int is_initiator,
const SM2_KEY *key, const char *id, size_t idlen,
const SM2_KEY *peer_public_key, const char *peer_id, size_t peer_idlen,
const SM2_KEY *key_exchange, const uint8_t peer_key_exchange[65],
const uint8_t shared_point[65], const uint8_t confirm[32])
{
uint8_t expected[32];
int ret;
if (!confirm) {
error_print();
return -1;
}
if (sm2_key_exchange_compute_confirm_ex(is_initiator,
key, id, idlen, peer_public_key, peer_id, peer_idlen,
key_exchange, peer_key_exchange, shared_point, !is_initiator, expected) != 1) {
error_print();
return -1;
}
ret = gmssl_secure_memcmp(expected, confirm, sizeof(expected)) == 0 ? 1 : 0;
gmssl_secure_clear(expected, sizeof(expected));
return ret;
}

View File

@@ -39,13 +39,77 @@ const size_t tlcp_signature_algorithms_cnt =
const int tlcp_cipher_suites[] = {
TLS_cipher_ecc_sm4_cbc_sm3,
TLS_cipher_ecc_sm4_gcm_sm3,
TLS_cipher_ecdhe_sm4_cbc_sm3,
TLS_cipher_ecdhe_sm4_gcm_sm3,
};
const size_t tlcp_cipher_suites_cnt =
sizeof(tlcp_cipher_suites)/sizeof(tlcp_cipher_suites[0]);
static int tlcp_cipher_suite_is_ecc(int cipher_suite)
{
switch (cipher_suite) {
case TLS_cipher_ecc_sm4_cbc_sm3:
case TLS_cipher_ecc_sm4_gcm_sm3:
return 1;
default:
return 0;
}
}
static int tlcp_cipher_suite_is_ecdhe(int cipher_suite)
{
switch (cipher_suite) {
case TLS_cipher_ecdhe_sm4_cbc_sm3:
case TLS_cipher_ecdhe_sm4_gcm_sm3:
return 1;
default:
return 0;
}
}
/*--
当采用ECDHE_SM4_CBC/GCM_SM3时
双方采用SM2密钥交换算法也就是 sm2_key_exchange 函数完成密钥交换
其中服务器作为发起方,客户端做为接收方
当采用这个套件时要求服务器方必须发起cert_reqeust发送CertificateRequest
客户端必须响应不为空的client Certificate
客户端响应的证书链必须是SM2的双证书证书链
服务器加密证书中的公钥作为发起方的持久公钥即sm2_key_exchange的参数key
服务器ServerKeyExchagne中的public公钥作为临时公钥即_key_exchange的参数key_exchange
客户端加密证书中的公钥作为响应方的持久公钥
客户端ClientKeyExchagne中的公钥作为响应方的临时公钥
双方的id,peed_id参数使用默认的SM2_DEFAULT_ID
在密钥交换时使用sm2_key_exchange进行密钥交换
ServerKeyExchange
select (KeyExchangeAlgorithm) {
case ECC:
digitall-signed struct {
opaque client_random[32];
opaque server_random[32];
opaque ASN1.Cert<1..2^24-1>;
} signed_params;
case ECDHE:
ServerECDHEParams params;
digitally-signed struct {
opaque client_random[32];
opaque server_random[32];
ServerECDHEParams params;
/*
ServerKeyExchange
select (KeyExchangeAlgorithm) {
@@ -82,8 +146,52 @@ select (KeyExchangeAlgorithm) {
} ServerKeyExchange;
`signed_params` is DER signature encoded in uint16array
struct {
ECParameters curve_params;
ECPoint public;
} ServerECDHEParams;
struct {
ClientCertificateType certificate_type<1..2^8-1>;
DistinguishedName certificate_authorities<0..2^16-1>;
} CertificateRequest;
enum {
ecdsa_sign(64), ibc_params(80),
} ClientCertificateType;
struct {
select (KeyExchangeAlgorithm) {
case ECC:
opaque ECCEncryptedPreMasterSecret<0..2^16-1>;
case ECDHE:
Opaque ClientECDHEParams<1..2^16-1>;
case IBSDH:
Opaque ClientIBSDHParams<1..2^16-1>;
case IBC:
opaque IBCEncryptedPreMasterSecret<0..2^16-1>;
} exchange_keys;
} ClientKeyExchange;
struct {
ECParameters curve_params; 值为SM2命名曲线
ECPoint pubulic;
} ClientECDHEParams;
ClientIBSDHParams SM9的密钥交换数据
IBCEncryptedPreMasterSecret SM9密文加密的pre_master_secret
*/
int tlcp_server_key_exchange_ecc_print(FILE *fp, const uint8_t *data, size_t datalen, int fmt, int ind)
{
const uint8_t *sig;
@@ -214,22 +322,7 @@ int tlcp_record_get_handshake_server_key_exchange(const uint8_t *record,
}
/*
struct {
select (KeyExchangeAlgorithm) {
case ECC:
opaque ECCEncryptedPreMasterSecret<0..2^16-1>;
case ECDHE:
Opaque ClientECDHEParams<1..2^16-1>;
case IBSDH:
Opaque ClientIBSDHParams<1..2^16-1>;
case IBC:
opaque IBCEncryptedPreMasterSecret<0..2^16-1>;
case RSA:
opaque RSAEncryptedPreMasterSecret<0..2^16-1>;
} exchange_keys;
} ClientKeyExchange;
*/
int tlcp_record_set_handshake_client_key_exchange(uint8_t *record, size_t *recordlen,
const uint8_t *enced_pms, size_t enced_pms_len)
@@ -817,6 +910,8 @@ int tlcp_recv_server_certificate(TLS_CONNECT *conn)
int tlcp_recv_server_key_exchange(TLS_CONNECT *conn)
{
int ret;
const uint8_t *server_ecdh_params;
size_t server_ecdh_params_len;
const uint8_t *sig;
size_t siglen;
const uint8_t *sign_cert;
@@ -857,36 +952,95 @@ int tlcp_recv_server_key_exchange(TLS_CONNECT *conn)
tls_send_alert(conn, TLS_alert_protocol_version);
return -1;
}
if (tlcp_record_get_handshake_server_key_exchange(conn->record,
TLS_server_key_exchange_ecc, NULL, 0, &sig, &siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
// verify ServerKeyExchange
if (x509_certs_get_cert_by_index(conn->peer_cert_chain, conn->peer_cert_chain_len, 0, &sign_cert, &sign_cert_len) != 1
|| x509_cert_get_subject_public_key(sign_cert, sign_cert_len, &sign_key) != 1
|| x509_certs_get_cert_by_index(conn->peer_cert_chain, conn->peer_cert_chain_len, 1, &enc_cert, &enc_cert_len) != 1) {
|| x509_cert_get_subject_public_key(sign_cert, sign_cert_len, &sign_key) != 1) {
error_print();
return -1;
}
tls_uint24_to_bytes(enc_cert_len, &enc_cert_header_ptr, &enc_cert_header_len);
if (sign_key.algor != OID_ec_public_key || sign_key.algor_param != OID_sm2) {
error_print();
tls_send_alert(conn, TLS_alert_bad_certificate);
return -1;
}
if (sm2_verify_init(&verify_ctx, &sign_key.u.sm2_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1
|| sm2_verify_update(&verify_ctx, conn->client_random, 32) != 1
|| sm2_verify_update(&verify_ctx, conn->server_random, 32) != 1
|| sm2_verify_update(&verify_ctx, enc_cert_header, enc_cert_header_len) != 1
|| sm2_verify_update(&verify_ctx, enc_cert, enc_cert_len) != 1) {
if (tlcp_cipher_suite_is_ecdhe(conn->cipher_suite)) {
const uint8_t *server_key_exchange;
size_t server_key_exchange_len;
const uint8_t *params;
size_t params_len;
if (tlcp_record_get_handshake_server_key_exchange(conn->record,
TLS_server_key_exchange_ecdhe, &server_ecdh_params, &server_ecdh_params_len,
&sig, &siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
if (sm2_verify_init(&verify_ctx, &sign_key.u.sm2_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1
|| sm2_verify_update(&verify_ctx, conn->client_random, 32) != 1
|| sm2_verify_update(&verify_ctx, conn->server_random, 32) != 1
|| sm2_verify_update(&verify_ctx, server_ecdh_params, server_ecdh_params_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (sm2_verify_finish(&verify_ctx, sig, siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_decrypt_error);
return -1;
}
params = server_ecdh_params;
params_len = server_ecdh_params_len;
if (tls_server_ecdh_params_from_bytes(&conn->key_exchange_group,
&server_key_exchange, &server_key_exchange_len, &params, &params_len) != 1
|| tls_length_is_zero(params_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_decode_error);
return -1;
}
if (conn->key_exchange_group != TLS_curve_sm2p256v1
|| server_key_exchange_len != sizeof(conn->peer_key_exchange)) {
error_print();
tls_send_alert(conn, TLS_alert_illegal_parameter);
return -1;
}
memcpy(conn->peer_key_exchange, server_key_exchange, server_key_exchange_len);
conn->peer_key_exchange_len = server_key_exchange_len;
} else if (tlcp_cipher_suite_is_ecc(conn->cipher_suite)) {
if (tlcp_record_get_handshake_server_key_exchange(conn->record,
TLS_server_key_exchange_ecc, NULL, 0, &sig, &siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_unexpected_message);
return -1;
}
if (x509_certs_get_cert_by_index(conn->peer_cert_chain, conn->peer_cert_chain_len, 1,
&enc_cert, &enc_cert_len) != 1) {
error_print();
return -1;
}
tls_uint24_to_bytes(enc_cert_len, &enc_cert_header_ptr, &enc_cert_header_len);
if (sm2_verify_init(&verify_ctx, &sign_key.u.sm2_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1
|| sm2_verify_update(&verify_ctx, conn->client_random, 32) != 1
|| sm2_verify_update(&verify_ctx, conn->server_random, 32) != 1
|| sm2_verify_update(&verify_ctx, enc_cert_header, enc_cert_header_len) != 1
|| sm2_verify_update(&verify_ctx, enc_cert, enc_cert_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (sm2_verify_finish(&verify_ctx, sig, siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_decrypt_error);
return -1;
}
} else {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (sm2_verify_finish(&verify_ctx, sig, siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_decrypt_error);
return -1;
}
return 1;
}
@@ -981,33 +1135,90 @@ int tlcp_send_client_key_exchange(TLS_CONNECT *conn)
X509_KEY public_key;
uint8_t enced_pre_master_secret[SM2_MAX_CIPHERTEXT_SIZE];
size_t enced_pre_master_secret_len;
uint8_t client_ecdh_params[69];
uint8_t *client_ecdh_params_ptr = client_ecdh_params;
size_t client_ecdh_params_len = 0;
int curve_oid = tls_named_curve_oid(TLS_curve_sm2p256v1);
if (conn->verbose)
tls_trace("send ClientKeyExchange\n");
if (x509_certs_get_cert_by_index(conn->peer_cert_chain, conn->peer_cert_chain_len, 1,
&enc_cert, &enc_cert_len) != 1
|| x509_cert_get_subject_public_key(enc_cert, enc_cert_len, &public_key) != 1) {
error_print();
return -1;
}
if (tlcp_cipher_suite_is_ecdhe(conn->cipher_suite)) {
X509_KEY *enc_key;
if (tlcp_generate_pre_master_secret(conn) != 1
|| tls_derive_master_secret(conn) != 1
|| tls_derive_key_block(conn) != 1
|| tls_init_application_keys(conn) != 1) {
error_print();
return -1;
}
if (!conn->client_certificate_verify || !conn->cert_chain_idx || !conn->peer_key_exchange_len) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (x509_certs_get_cert_by_index(conn->peer_cert_chain, conn->peer_cert_chain_len, 1,
&enc_cert, &enc_cert_len) != 1
|| x509_cert_get_subject_public_key(enc_cert, enc_cert_len, &public_key) != 1) {
error_print();
return -1;
}
enc_key = &conn->ctx->enc_keys[conn->cert_chain_idx - 1];
if (public_key.algor != OID_ec_public_key || public_key.algor_param != OID_sm2
|| enc_key->algor != OID_ec_public_key || enc_key->algor_param != OID_sm2) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (x509_key_generate(&conn->key_exchanges[0], OID_ec_public_key,
&curve_oid, sizeof(curve_oid)) != 1
|| tls_server_ecdh_params_to_bytes(&conn->key_exchanges[0],
&client_ecdh_params_ptr, &client_ecdh_params_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (client_ecdh_params_len != sizeof(client_ecdh_params)) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (sm2_key_exchange(0, &enc_key->u.sm2_key,
SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH,
&public_key.u.sm2_key,
SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH,
&conn->key_exchanges[0].u.sm2_key,
conn->peer_key_exchange, NULL, 48, conn->pre_master_secret) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
conn->pre_master_secret_len = 48;
if (tlcp_record_set_handshake_client_key_exchange(conn->record, &conn->recordlen,
client_ecdh_params, client_ecdh_params_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
} else if (tlcp_cipher_suite_is_ecc(conn->cipher_suite)) {
if (x509_certs_get_cert_by_index(conn->peer_cert_chain, conn->peer_cert_chain_len, 1,
&enc_cert, &enc_cert_len) != 1
|| x509_cert_get_subject_public_key(enc_cert, enc_cert_len, &public_key) != 1) {
error_print();
return -1;
}
if (sm2_encrypt(&public_key.u.sm2_key, conn->pre_master_secret, 48,
enced_pre_master_secret, &enced_pre_master_secret_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (tlcp_record_set_handshake_client_key_exchange(conn->record, &conn->recordlen,
enced_pre_master_secret, enced_pre_master_secret_len) != 1) {
if (tlcp_generate_pre_master_secret(conn) != 1) {
error_print();
return -1;
}
if (sm2_encrypt(&public_key.u.sm2_key, conn->pre_master_secret, 48,
enced_pre_master_secret, &enced_pre_master_secret_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (tlcp_record_set_handshake_client_key_exchange(conn->record, &conn->recordlen,
enced_pre_master_secret, enced_pre_master_secret_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
} else {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
@@ -1026,6 +1237,13 @@ int tlcp_send_client_key_exchange(TLS_CONNECT *conn)
error_print();
return -1;
}
if (tls_derive_master_secret(conn) != 1
|| tls_derive_key_block(conn) != 1
|| tls_init_application_keys(conn) != 1) {
error_print();
return -1;
}
}
if ((ret = tls_send_record(conn)) != 1) {
@@ -1201,6 +1419,11 @@ int tlcp_recv_client_hello(TLS_CONNECT *conn)
break;
case TLS_cipher_ecdhe_sm4_cbc_sm3:
case TLS_cipher_ecdhe_sm4_gcm_sm3:
conn->sig_alg = TLS_sig_sm2sig_sm3;
conn->signature_algorithms[0] = TLS_sig_sm2sig_sm3;
conn->key_exchange_group = TLS_curve_sm2p256v1;
conn->client_certificate_verify = 1;
break;
default:
error_print();
return -1;
@@ -1546,6 +1769,10 @@ int tlcp_send_server_key_exchange(TLS_CONNECT *conn)
uint8_t enc_cert_header[3];
uint8_t *enc_cert_header_ptr = enc_cert_header;
size_t enc_cert_header_len = 0;
uint8_t server_ecdh_params[69];
uint8_t *server_ecdh_params_ptr = server_ecdh_params;
size_t server_ecdh_params_len = 0;
int curve_oid = tls_named_curve_oid(TLS_curve_sm2p256v1);
X509_KEY *sign_key;
SM2_SIGN_CTX sign_ctx;
uint8_t sigbuf[SM2_MAX_SIGNATURE_SIZE];
@@ -1574,19 +1801,54 @@ int tlcp_send_server_key_exchange(TLS_CONNECT *conn)
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (sm2_sign_init(&sign_ctx, &sign_key->u.sm2_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1
|| sm2_sign_update(&sign_ctx, conn->client_random, 32) != 1
|| sm2_sign_update(&sign_ctx, conn->server_random, 32) != 1
|| sm2_sign_update(&sign_ctx, enc_cert_header, enc_cert_header_len) != 1
|| sm2_sign_update(&sign_ctx, enc_cert, enc_cert_len) != 1
|| sm2_sign_finish(&sign_ctx, sigbuf, &siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (tlcp_record_set_handshake_server_key_exchange(conn->record, &conn->recordlen,
TLS_server_key_exchange_ecc, NULL, 0, sigbuf, siglen) != 1) {
if (tlcp_cipher_suite_is_ecdhe(conn->cipher_suite)) {
if (x509_key_generate(&conn->key_exchanges[0], OID_ec_public_key,
&curve_oid, sizeof(curve_oid)) != 1
|| tls_server_ecdh_params_to_bytes(&conn->key_exchanges[0],
&server_ecdh_params_ptr, &server_ecdh_params_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (server_ecdh_params_len != sizeof(server_ecdh_params)) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (sm2_sign_init(&sign_ctx, &sign_key->u.sm2_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1
|| sm2_sign_update(&sign_ctx, conn->client_random, 32) != 1
|| sm2_sign_update(&sign_ctx, conn->server_random, 32) != 1
|| sm2_sign_update(&sign_ctx, server_ecdh_params, server_ecdh_params_len) != 1
|| sm2_sign_finish(&sign_ctx, sigbuf, &siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (tlcp_record_set_handshake_server_key_exchange(conn->record, &conn->recordlen,
TLS_server_key_exchange_ecdhe, server_ecdh_params, server_ecdh_params_len,
sigbuf, siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
} else if (tlcp_cipher_suite_is_ecc(conn->cipher_suite)) {
if (sm2_sign_init(&sign_ctx, &sign_key->u.sm2_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1
|| sm2_sign_update(&sign_ctx, conn->client_random, 32) != 1
|| sm2_sign_update(&sign_ctx, conn->server_random, 32) != 1
|| sm2_sign_update(&sign_ctx, enc_cert_header, enc_cert_header_len) != 1
|| sm2_sign_update(&sign_ctx, enc_cert, enc_cert_len) != 1
|| sm2_sign_finish(&sign_ctx, sigbuf, &siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (tlcp_record_set_handshake_server_key_exchange(conn->record, &conn->recordlen,
TLS_server_key_exchange_ecc, NULL, 0, sigbuf, siglen) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
} else {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
@@ -1773,7 +2035,6 @@ int tlcp_recv_client_key_exchange(TLS_CONNECT *conn)
return -1;
}
// decrypt enced_pre_master_secret
if (!conn->cert_chain_idx) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
@@ -1785,25 +2046,82 @@ int tlcp_recv_client_key_exchange(TLS_CONNECT *conn)
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (sm2_decrypt(&enc_key->u.sm2_key, enced_pms, enced_pms_len,
pre_master_secret, &pre_master_secret_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_decrypt_error);
return -1;
}
if (pre_master_secret_len != 48) {
gmssl_secure_clear(pre_master_secret, pre_master_secret_len);
error_print();
tls_send_alert(conn, TLS_alert_illegal_parameter);
return -1;
}
memcpy(conn->pre_master_secret, pre_master_secret, pre_master_secret_len);
conn->pre_master_secret_len = pre_master_secret_len;
gmssl_secure_clear(pre_master_secret, pre_master_secret_len);
if (tlcp_check_pre_master_secret(conn) != 1) {
if (tlcp_cipher_suite_is_ecdhe(conn->cipher_suite)) {
int key_exchange_group;
const uint8_t *client_key_exchange;
size_t client_key_exchange_len;
const uint8_t *params = enced_pms;
size_t params_len = enced_pms_len;
const uint8_t *enc_cert;
size_t enc_cert_len;
X509_KEY peer_public_key;
if (tls_server_ecdh_params_from_bytes(&key_exchange_group,
&client_key_exchange, &client_key_exchange_len, &params, &params_len) != 1
|| tls_length_is_zero(params_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_decode_error);
return -1;
}
if (key_exchange_group != TLS_curve_sm2p256v1
|| client_key_exchange_len != sizeof(conn->peer_key_exchange)) {
error_print();
tls_send_alert(conn, TLS_alert_illegal_parameter);
return -1;
}
if (x509_certs_get_cert_by_index(conn->client_certs, conn->client_certs_len, 1,
&enc_cert, &enc_cert_len) != 1
|| x509_cert_get_subject_public_key(enc_cert, enc_cert_len, &peer_public_key) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_bad_certificate);
return -1;
}
if (peer_public_key.algor != OID_ec_public_key || peer_public_key.algor_param != OID_sm2
|| conn->key_exchanges[0].algor != OID_ec_public_key
|| conn->key_exchanges[0].algor_param != OID_sm2) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (sm2_key_exchange(1, &enc_key->u.sm2_key,
SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH,
&peer_public_key.u.sm2_key,
SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH,
&conn->key_exchanges[0].u.sm2_key,
client_key_exchange, NULL, 48, conn->pre_master_secret) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_decrypt_error);
return -1;
}
memcpy(conn->peer_key_exchange, client_key_exchange, client_key_exchange_len);
conn->peer_key_exchange_len = client_key_exchange_len;
conn->pre_master_secret_len = 48;
} else if (tlcp_cipher_suite_is_ecc(conn->cipher_suite)) {
if (sm2_decrypt(&enc_key->u.sm2_key, enced_pms, enced_pms_len,
pre_master_secret, &pre_master_secret_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_decrypt_error);
return -1;
}
if (pre_master_secret_len != 48) {
gmssl_secure_clear(pre_master_secret, pre_master_secret_len);
error_print();
tls_send_alert(conn, TLS_alert_illegal_parameter);
return -1;
}
memcpy(conn->pre_master_secret, pre_master_secret, pre_master_secret_len);
conn->pre_master_secret_len = pre_master_secret_len;
gmssl_secure_clear(pre_master_secret, pre_master_secret_len);
if (tlcp_check_pre_master_secret(conn) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_illegal_parameter);
return -1;
}
} else {
error_print();
tls_send_alert(conn, TLS_alert_illegal_parameter);
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
if (tls_derive_master_secret(conn) != 1
@@ -1877,6 +2195,7 @@ int tlcp_send(TLS_CONNECT *conn, const uint8_t *in, size_t inlen, size_t *sentle
switch (conn->cipher_suite) {
case TLS_cipher_ecc_sm4_cbc_sm3:
case TLS_cipher_ecdhe_sm4_cbc_sm3:
if (tls_cbc_encrypt(hmac_ctx, enc_key, seq_num, conn->databuf,
conn->databuf + 5, tls_record_data_length(conn->databuf),
conn->record + 5, &recordlen) != 1) {
@@ -1886,6 +2205,7 @@ int tlcp_send(TLS_CONNECT *conn, const uint8_t *in, size_t inlen, size_t *sentle
break;
case TLS_cipher_ecc_sm4_gcm_sm3:
case TLS_cipher_ecdhe_sm4_gcm_sm3:
if (tls_gcm_encrypt(enc_key, iv, seq_num, conn->databuf,
conn->databuf + 5, tls_record_data_length(conn->databuf),
conn->record + 5, &recordlen) != 1) {
@@ -1977,6 +2297,11 @@ int tlcp_do_client_handshake(TLS_CONNECT *conn)
case TLS_state_certificate_request:
ret = tlcp_recv_certificate_request(conn);
if (ret == 0 && tlcp_cipher_suite_is_ecdhe(conn->cipher_suite)) {
error_print();
tls_send_alert(conn, TLS_alert_handshake_failure);
return -1;
}
if (ret == 1) conn->client_certificate_verify = 1;
next_state = TLS_state_server_hello_done;
break;

View File

@@ -3077,6 +3077,29 @@ static int tls_ctx_get_certificate_chain(const TLS_CTX *ctx, size_t idx,
return 1;
}
static int tls_cipher_suite_is_tlcp_ecdhe(int cipher_suite)
{
switch (cipher_suite) {
case TLS_cipher_ecdhe_sm4_cbc_sm3:
case TLS_cipher_ecdhe_sm4_gcm_sm3:
return 1;
default:
return 0;
}
}
static int tls_ctx_has_tlcp_ecdhe_cipher_suite(const TLS_CTX *ctx)
{
size_t i;
for (i = 0; i < ctx->cipher_suites_cnt; i++) {
if (tls_cipher_suite_is_tlcp_ecdhe(ctx->cipher_suites[i])) {
return 1;
}
}
return 0;
}
static int tls_ctx_check(const TLS_CTX *ctx)
{
const int *supported_cipher_suites = NULL;
@@ -3088,6 +3111,7 @@ static int tls_ctx_check(const TLS_CTX *ctx)
const uint8_t *cert_chains;
size_t cert_chains_len;
size_t cert_chains_cnt = 0;
int tlcp_client_needs_double_certs = 0;
size_t i;
if (!ctx) {
@@ -3137,6 +3161,9 @@ static int tls_ctx_check(const TLS_CTX *ctx)
return -1;
}
}
if (ctx->protocol == TLS_protocol_tlcp && ctx->is_client) {
tlcp_client_needs_double_certs = tls_ctx_has_tlcp_ecdhe_cipher_suite(ctx);
}
if (ctx->supported_groups_cnt > sizeof(ctx->supported_groups)/sizeof(ctx->supported_groups[0])) {
error_print();
@@ -3249,6 +3276,7 @@ static int tls_ctx_check(const TLS_CTX *ctx)
const uint8_t *cert_chain;
size_t cert_chain_len;
size_t certs_cnt;
size_t key_idx = cert_chains_cnt;
if (tls_uint24array_from_bytes(&cert_chain, &cert_chain_len,
&cert_chains, &cert_chains_len) != 1
@@ -3264,6 +3292,14 @@ static int tls_ctx_check(const TLS_CTX *ctx)
error_print();
return -1;
}
if (tlcp_client_needs_double_certs) {
if (certs_cnt < 2
|| ctx->enc_keys[key_idx].algor != OID_ec_public_key
|| ctx->enc_keys[key_idx].algor_param != OID_sm2) {
error_print();
return -1;
}
}
cert_chains_cnt++;
}
@@ -3272,6 +3308,11 @@ static int tls_ctx_check(const TLS_CTX *ctx)
error_print();
return -1;
}
} else if (tlcp_client_needs_double_certs) {
if (!ctx->cert_chains_len || !ctx->x509_keys_cnt || cert_chains_cnt != ctx->x509_keys_cnt) {
error_print();
return -1;
}
} else if (ctx->cert_chains_len) {
if (!ctx->x509_keys_cnt || cert_chains_cnt != ctx->x509_keys_cnt) {
error_print();

View File

@@ -14,6 +14,7 @@
#include <string.h>
#include <assert.h>
#include <gmssl/x509.h>
#include <gmssl/x509_ext.h>
#include <gmssl/error.h>
#include <gmssl/sm2.h>
#include <gmssl/sm3.h>
@@ -1676,9 +1677,91 @@ int tls_recv_server_hello_done(TLS_CONNECT *conn)
return 1;
}
static int tlcp_cert_is_encryption_cert(const uint8_t *cert, size_t certlen)
{
int ret;
int critical;
const uint8_t *exts;
size_t extslen;
const uint8_t *val;
size_t vlen;
int bits;
if (!cert || !certlen) {
error_print();
return -1;
}
if ((ret = x509_cert_get_exts(cert, certlen, &exts, &extslen)) != 1) {
if (ret) error_print();
return ret;
}
if ((ret = x509_exts_get_ext_by_oid(exts, extslen, OID_ce_key_usage,
&critical, &val, &vlen)) != 1) {
if (ret) error_print();
return ret;
}
if (x509_key_usage_from_der(&bits, &val, &vlen) != 1
|| asn1_length_is_zero(vlen) != 1) {
error_print();
return -1;
}
return (bits & X509_KU_KEY_ENCIPHERMENT) ? 1 : 0;
}
static int tlcp_client_certs_without_encryption_cert(const uint8_t *certs, size_t certslen,
uint8_t *out, size_t *outlen, size_t maxlen)
{
const uint8_t *p = certs;
size_t len = certslen;
size_t cert_idx = 0;
if (!certs || !certslen || !out || !outlen) {
error_print();
return -1;
}
*outlen = 0;
while (len) {
const uint8_t *cert_der = p;
const uint8_t *cert;
size_t certlen;
size_t derlen;
int skip = 0;
if (x509_cert_from_der(&cert, &certlen, &p, &len) != 1) {
error_print();
return -1;
}
derlen = (size_t)(p - cert_der);
if (cert_idx == 1) {
int ret = tlcp_cert_is_encryption_cert(cert, certlen);
if (ret < 0) {
error_print();
return -1;
}
skip = ret;
}
if (!skip) {
if (*outlen > maxlen || derlen > maxlen - *outlen) {
error_print();
return -1;
}
memcpy(out + *outlen, cert_der, derlen);
*outlen += derlen;
}
cert_idx++;
}
return 1;
}
int tls_send_client_certificate(TLS_CONNECT *conn)
{
int ret;
const uint8_t *client_certs;
size_t client_certs_len;
uint8_t client_certs_without_enc[TLS_MAX_CERTIFICATES_SIZE];
size_t client_certs_without_enc_len;
if(conn->verbose) tls_trace("send client Certificate\n");
if (conn->client_certs_len == 0) {
@@ -1687,8 +1770,23 @@ int tls_send_client_certificate(TLS_CONNECT *conn)
}
if (conn->recordlen == 0) {
client_certs = conn->client_certs;
client_certs_len = conn->client_certs_len;
if (conn->protocol == TLS_protocol_tlcp
&& (conn->cipher_suite == TLS_cipher_ecc_sm4_cbc_sm3
|| conn->cipher_suite == TLS_cipher_ecc_sm4_gcm_sm3)) {
if (tlcp_client_certs_without_encryption_cert(conn->client_certs, conn->client_certs_len,
client_certs_without_enc, &client_certs_without_enc_len,
sizeof(client_certs_without_enc)) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
}
client_certs = client_certs_without_enc;
client_certs_len = client_certs_without_enc_len;
}
if (tls_record_set_handshake_certificate(conn->record, &conn->recordlen,
conn->client_certs, conn->client_certs_len) != 1) {
client_certs, client_certs_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
return -1;
@@ -2747,6 +2845,30 @@ int tls_recv_client_certificate(TLS_CONNECT *conn)
}
conn->verify_result = verify_result;
if (conn->protocol == TLS_protocol_tlcp
&& (conn->cipher_suite == TLS_cipher_ecdhe_sm4_cbc_sm3
|| conn->cipher_suite == TLS_cipher_ecdhe_sm4_gcm_sm3)) {
const uint8_t *enc_cert;
size_t enc_cert_len;
if (x509_certs_get_cert_by_index(conn->client_certs, conn->client_certs_len,
1, &enc_cert, &enc_cert_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_bad_certificate);
return -1;
}
ret = tlcp_cert_is_encryption_cert(enc_cert, enc_cert_len);
if (ret < 0) {
error_print();
tls_send_alert(conn, TLS_alert_bad_certificate);
return -1;
} else if (ret == 0) {
error_print();
tls_send_alert(conn, TLS_alert_unsupported_certificate);
return -1;
}
}
if (digest_update(&conn->dgst_ctx, conn->record + 5, conn->recordlen - 5) != 1) {
error_print();

View File

@@ -287,7 +287,7 @@ int tls_ctx_set_certificate_and_key(TLS_CTX *ctx, const char *chainfile,
return 1;
}
int tlcp_ctx_add_server_certificate_and_keys(TLS_CTX *ctx, const char *chainfile,
static int tlcp_ctx_add_certificate_and_keys(TLS_CTX *ctx, const char *chainfile,
const char *keyfile, const char *keypass)
{
int ret = -1;
@@ -314,7 +314,7 @@ int tlcp_ctx_add_server_certificate_and_keys(TLS_CTX *ctx, const char *chainfile
error_print();
return -1;
}
if (ctx->protocol != TLS_protocol_tlcp || ctx->is_client) {
if (ctx->protocol != TLS_protocol_tlcp) {
error_print();
return -1;
}
@@ -397,6 +397,34 @@ end:
return ret;
}
int tlcp_ctx_add_server_certificate_and_keys(TLS_CTX *ctx, const char *chainfile,
const char *keyfile, const char *keypass)
{
if (!ctx || ctx->is_client) {
error_print();
return -1;
}
if (tlcp_ctx_add_certificate_and_keys(ctx, chainfile, keyfile, keypass) != 1) {
error_print();
return -1;
}
return 1;
}
int tlcp_ctx_add_client_certificate_and_keys(TLS_CTX *ctx, const char *chainfile,
const char *keyfile, const char *keypass)
{
if (!ctx || !ctx->is_client) {
error_print();
return -1;
}
if (tlcp_ctx_add_certificate_and_keys(ctx, chainfile, keyfile, keypass) != 1) {
error_print();
return -1;
}
return 1;
}
int tls_ctx_set_tlcp_server_certificate_and_keys(TLS_CTX *ctx, const char *chainfile,
const char *keyfile, const char *keypass)
{
@@ -412,6 +440,21 @@ int tls_ctx_set_tlcp_server_certificate_and_keys(TLS_CTX *ctx, const char *chain
return 1;
}
int tls_ctx_set_tlcp_client_certificate_and_keys(TLS_CTX *ctx, const char *chainfile,
const char *keyfile, const char *keypass)
{
if (!ctx || ctx->cert_chains_len || ctx->x509_keys_cnt) {
error_print();
return -1;
}
if (tlcp_ctx_add_client_certificate_and_keys(ctx, chainfile,
keyfile, keypass) != 1) {
error_print();
return -1;
}
return 1;
}
int tls_authorities_issued_certificate(const uint8_t *ca_names, size_t ca_names_len, const uint8_t *certs, size_t certslen)
{
const uint8_t *cert;
@@ -584,4 +627,3 @@ int tls12_cert_chains_select(const uint8_t *cert_chains, size_t cert_chains_len,
return 0;
}

View File

@@ -101,6 +101,17 @@ static int tls12_signature_scheme_from_cipher_suite(int cipher_suite)
}
}
static int tls_cipher_suite_is_tlcp_ecdhe(int cipher_suite)
{
switch (cipher_suite) {
case TLS_cipher_ecdhe_sm4_cbc_sm3:
case TLS_cipher_ecdhe_sm4_gcm_sm3:
return 1;
default:
return 0;
}
}
static int tls_cert_chain_check_name(const uint8_t *cert_chain, size_t cert_chain_len,
const uint8_t *host_name, size_t host_name_len, int *verify_result)
{
@@ -398,7 +409,10 @@ int tls_cert_chain_verify(
}
if (verify_chain) {
if (protocol == TLS_protocol_tlcp && cert_chain_type == X509_cert_chain_server) {
if (protocol == TLS_protocol_tlcp
&& (cert_chain_type == X509_cert_chain_server
|| (cert_chain_type == X509_cert_chain_client
&& tls_cipher_suite_is_tlcp_ecdhe(cipher_suite)))) {
ret = x509_certs_verify_tlcp(cert_chain, cert_chain_len, cert_chain_type,
cacerts, cacerts_len, crl, crl_len, ocsp, ocsp_len,
verify_depth, verify_result);

View File

@@ -2116,7 +2116,7 @@ int x509_certs_verify(const uint8_t *certs, size_t certslen, int certs_type,
return 1;
}
// 只有 TLCP 的服务器证书链才是双证书客户端证书和TLS12是一样的
// TLCP ECC server and TLCP ECDHE client certificate chains use dual entity certificates.
int x509_certs_verify_tlcp(const uint8_t *certs, size_t certslen, int certs_type,
const uint8_t *rootcerts, size_t rootcertslen,
const uint8_t *crl, size_t crl_len,
@@ -2144,6 +2144,10 @@ int x509_certs_verify_tlcp(const uint8_t *certs, size_t certslen, int certs_type
sign_cert_type = X509_cert_server_auth;
kenc_cert_type = X509_cert_server_key_encipher;
break;
case X509_cert_chain_client:
sign_cert_type = X509_cert_client_auth;
kenc_cert_type = X509_cert_client_key_encipher;
break;
default:
error_print();
x509_verify_set_result(verify_result, X509_verify_err_certificate);

90
tests/sm2_exchtest.c Normal file
View File

@@ -0,0 +1,90 @@
/*
* 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 <stdio.h>
#include <string.h>
#include <gmssl/error.h>
#include <gmssl/sm2.h>
static int test_sm2_key_exchange(void)
{
SM2_KEY a;
SM2_KEY b;
SM2_KEY ra;
SM2_KEY rb;
uint8_t ra_octets[65];
uint8_t rb_octets[65];
uint8_t ua[65];
uint8_t vb[65];
uint8_t ska[48];
uint8_t skb[48];
uint8_t sa[32];
uint8_t sb[32];
const char ida[] = "Alice";
const char idb[] = "Bob";
if (sm2_key_generate(&a) != 1
|| sm2_key_generate(&b) != 1
|| sm2_key_generate(&ra) != 1
|| sm2_key_generate(&rb) != 1
|| sm2_z256_point_to_uncompressed_octets(&ra.public_key, ra_octets) != 1
|| sm2_z256_point_to_uncompressed_octets(&rb.public_key, rb_octets) != 1) {
error_print();
return -1;
}
if (sm2_key_exchange(1, &a, ida, sizeof(ida) - 1, &b, idb, sizeof(idb) - 1,
&ra, rb_octets, ua, sizeof(ska), ska) != 1
|| sm2_key_exchange(0, &b, idb, sizeof(idb) - 1, &a, ida, sizeof(ida) - 1,
&rb, ra_octets, vb, sizeof(skb), skb) != 1) {
error_print();
return -1;
}
if (memcmp(ska, skb, sizeof(ska)) != 0 || memcmp(ua, vb, sizeof(ua)) != 0) {
error_print();
return -1;
}
if (sm2_key_exchange_compute_confirm(1, &a, ida, sizeof(ida) - 1, &b, idb, sizeof(idb) - 1,
&ra, rb_octets, ua, sa) != 1
|| sm2_key_exchange_compute_confirm(0, &b, idb, sizeof(idb) - 1, &a, ida, sizeof(ida) - 1,
&rb, ra_octets, vb, sb) != 1) {
error_print();
return -1;
}
if (sm2_key_exchange_verify_confirm(1, &a, ida, sizeof(ida) - 1, &b, idb, sizeof(idb) - 1,
&ra, rb_octets, ua, sb) != 1
|| sm2_key_exchange_verify_confirm(0, &b, idb, sizeof(idb) - 1, &a, ida, sizeof(ida) - 1,
&rb, ra_octets, vb, sa) != 1) {
error_print();
return -1;
}
sb[0] ^= 0x01;
if (sm2_key_exchange_verify_confirm(1, &a, ida, sizeof(ida) - 1, &b, idb, sizeof(idb) - 1,
&ra, rb_octets, ua, sb) != 0) {
error_print();
return -1;
}
printf("%s() ok\n", __FUNCTION__);
return 1;
}
int main(void)
{
if (test_sm2_key_exchange() != 1) goto err;
printf("%s all tests passed\n", __FILE__);
return 0;
err:
error_print();
return -1;
}

View File

@@ -37,8 +37,8 @@ static const char *help =
" -sig_alg str Supported signature algorithms\n"
" -cacert pem Trusted CA certificate(s) in PEM format\n"
" -verify_depth num Certificate verification depth\n"
" -cert pem Client certificate(s) in PEM format\n"
" -key pem Private key of client certificate in PEM format\n"
" -cert pem Client certificate(s) in PEM format, TLCP ECDHE requires a double certificate chain\n"
" -key pem Private key of client certificate in PEM format, TLCP ECDHE requires signing and encryption keys\n"
" -pass password Password of encrypted private key\n"
" -client_cert_optional Allow client send empty Certificate\n"
" -get path Send a GET request with given path of URI\n"
@@ -53,6 +53,29 @@ static const char *help =
#include "tlcp_help.h"
"\n";
static int tlcp_cipher_suite_is_ecdhe(int cipher_suite)
{
switch (cipher_suite) {
case TLS_cipher_ecdhe_sm4_cbc_sm3:
case TLS_cipher_ecdhe_sm4_gcm_sm3:
return 1;
default:
return 0;
}
}
static int tlcp_cipher_suites_have_ecdhe(const int *cipher_suites, size_t cipher_suites_cnt)
{
size_t i;
for (i = 0; i < cipher_suites_cnt; i++) {
if (tlcp_cipher_suite_is_ecdhe(cipher_suites[i])) {
return 1;
}
}
return 0;
}
static int do_handshake_select(TLS_CONNECT *conn)
{
@@ -228,6 +251,7 @@ int tlcp_client_main(int argc, char *argv[])
char *infile = NULL;
char *certoutfile = NULL;
int verbose = 0;
int has_ecdhe_cipher_suite = 0;
struct sockaddr_in server;
tls_socket_t sock = tls_socket_invalid();
TLS_CTX ctx;
@@ -379,6 +403,11 @@ bad:
fprintf(stderr, "%s: '-get' and '-in' should not be used together\n", prog);
return -1;
}
has_ecdhe_cipher_suite = tlcp_cipher_suites_have_ecdhe(cipher_suites, cipher_suites_cnt);
if (has_ecdhe_cipher_suite && (!certfile || !keyfile || !pass)) {
fprintf(stderr, "%s: TLCP ECDHE cipher suites require '-cert', '-key' and '-pass' with a double certificate chain\n", prog);
return -1;
}
if (tls_socket_lib_init() != 1) {
error_print();
@@ -447,9 +476,16 @@ bad:
fprintf(stderr, "%s: option '-pass' missing\n", prog);
goto end;
}
if (tls_ctx_set_certificate_and_key(&ctx, certfile, keyfile, pass) != 1) {
fprintf(stderr, "%s: failed to load client certificate\n", prog);
goto end;
if (has_ecdhe_cipher_suite) {
if (tls_ctx_set_tlcp_client_certificate_and_keys(&ctx, certfile, keyfile, pass) != 1) {
fprintf(stderr, "%s: failed to load TLCP client double certificate chain and keys\n", prog);
goto end;
}
} else {
if (tls_ctx_set_certificate_and_key(&ctx, certfile, keyfile, pass) != 1) {
fprintf(stderr, "%s: failed to load client certificate\n", prog);
goto end;
}
}
}

View File

@@ -11,6 +11,8 @@
"Supported cipher suites:\n"
" TLS_ECC_SM4_CBC_SM3\n"
" TLS_ECC_SM4_GCM_SM3\n"
" TLS_ECDHE_SM4_CBC_SM3\n"
" TLS_ECDHE_SM4_GCM_SM3\n"
"\n"
"\n"
"Examples\n"