From 3d44be73cd5da4d9d772fe706365ec794de6ba3c Mon Sep 17 00:00:00 2001 From: Zhi Guan Date: Fri, 19 Jun 2026 18:30:45 +0800 Subject: [PATCH] Fix TLS 1.2 CertificateRequest --- CMakeLists.txt | 2 +- include/gmssl/tls.h | 2 +- include/gmssl/version.h | 2 +- src/tls12.c | 240 +++++++++++++++++++++++++++++++++++++++- src/tls_trace.c | 30 ++++- 5 files changed, 267 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index afc8fce7..5b176080 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -821,7 +821,7 @@ endif() # set(CPACK_PACKAGE_NAME "GmSSL") set(CPACK_PACKAGE_VENDOR "GmSSL develop team") -set(CPACK_PACKAGE_VERSION "3.2.0-dev.1106") +set(CPACK_PACKAGE_VERSION "3.2.0-dev.1107") set(CPACK_PACKAGE_DESCRIPTION_FILE ${PROJECT_SOURCE_DIR}/README.md) set(CPACK_NSIS_MODIFY_PATH ON) include(CPack) diff --git a/include/gmssl/tls.h b/include/gmssl/tls.h index 55756c4c..35ccbc89 100644 --- a/include/gmssl/tls.h +++ b/include/gmssl/tls.h @@ -692,7 +692,7 @@ int tlcp_certificate_request_print(FILE *fp, const uint8_t *data, size_t datalen int tls12_record_set_handshake_certificate_request(uint8_t *record, size_t *recordlen, const uint8_t *cert_types, size_t cert_types_len, - const uint8_t *sig_algs, size_t sig_algs_len, + const int *sig_algs, size_t sig_algs_cnt, const uint8_t *ca_names, size_t ca_names_len); int tls12_record_get_handshake_certificate_request(const uint8_t *record, const uint8_t **cert_types, size_t *cert_types_len, diff --git a/include/gmssl/version.h b/include/gmssl/version.h index 2131887c..6e0dce8d 100644 --- a/include/gmssl/version.h +++ b/include/gmssl/version.h @@ -18,7 +18,7 @@ extern "C" { #define GMSSL_VERSION_NUM 30200 -#define GMSSL_VERSION_STR "GmSSL 3.2.0-dev.1106" +#define GMSSL_VERSION_STR "GmSSL 3.2.0-dev.1107" int gmssl_version_num(void); const char *gmssl_version_str(void); diff --git a/src/tls12.c b/src/tls12.c index a3ae7b97..6118cc3b 100644 --- a/src/tls12.c +++ b/src/tls12.c @@ -192,9 +192,78 @@ struct { DistinguishedName certificate_authorities<0..2^16-1>; } CertificateRequest; */ +static int tls12_supported_signature_algorithms_to_bytes(const int *sig_algs, size_t sig_algs_cnt, + uint8_t **out, size_t *outlen) +{ + size_t i; + + if (!sig_algs || !sig_algs_cnt || !outlen) { + error_print(); + return -1; + } + if (sig_algs_cnt > ((1 << 16) - 2)/2) { + error_print(); + return -1; + } + tls_uint16_to_bytes((uint16_t)(sig_algs_cnt * tls_uint16_size()), out, outlen); + for (i = 0; i < sig_algs_cnt; i++) { + if (!tls_signature_scheme_name(sig_algs[i])) { + error_print(); + return -1; + } + tls_uint16_to_bytes((uint16_t)sig_algs[i], out, outlen); + } + return 1; +} + +static int tls12_supported_signature_algorithms_from_bytes(const uint8_t **sig_algs, size_t *sig_algs_len, + const uint8_t **in, size_t *inlen) +{ + const uint8_t *d; + size_t dlen; + const uint8_t *p; + size_t len; + const uint8_t *cp; + size_t cplen; + + if (!sig_algs || !sig_algs_len || !in || !inlen) { + error_print(); + return -1; + } + + d = *in; + dlen = *inlen; + if (tls_uint16array_from_bytes(&p, &len, in, inlen) != 1) { + error_print(); + return -1; + } + if (len < tls_uint16_size() || len % tls_uint16_size()) { + error_print(); + return -1; + } + + cp = p; + cplen = len; + while (cplen) { + uint16_t sig_alg; + + if (tls_uint16_from_bytes(&sig_alg, &cp, &cplen) != 1) { + error_print(); + return -1; + } + if (!tls_signature_scheme_name(sig_alg)) { + warning_print(); + } + } + + *sig_algs = d; + *sig_algs_len = dlen - *inlen; + return 1; +} + int tls12_record_set_handshake_certificate_request(uint8_t *record, size_t *recordlen, const uint8_t *cert_types, size_t cert_types_len, - const uint8_t *sig_algs, size_t sig_algs_len, + const int *sig_algs, size_t sig_algs_cnt, const uint8_t *ca_names, size_t ca_names_len) { int type = TLS_handshake_certificate_request; @@ -206,6 +275,10 @@ int tls12_record_set_handshake_certificate_request(uint8_t *record, size_t *reco error_print(); return -1; } + if (!sig_algs || !sig_algs_cnt) { + error_print(); + return -1; + } if (cert_types) { if (cert_types_len == 0 || cert_types_len > TLS_MAX_CERTIFICATE_TYPES) { error_print(); @@ -219,6 +292,10 @@ int tls12_record_set_handshake_certificate_request(uint8_t *record, size_t *reco } } tls_uint8array_to_bytes(cert_types, cert_types_len, NULL, &datalen); + if (tls12_supported_signature_algorithms_to_bytes(sig_algs, sig_algs_cnt, NULL, &datalen) != 1) { + error_print(); + return -1; + } tls_uint16array_to_bytes(ca_names, ca_names_len, NULL, &datalen); if (datalen > TLS_MAX_HANDSHAKE_DATA_SIZE) { error_print(); @@ -226,6 +303,10 @@ int tls12_record_set_handshake_certificate_request(uint8_t *record, size_t *reco } p = tls_handshake_data(tls_record_data(record)); tls_uint8array_to_bytes(cert_types, cert_types_len, &p, &len); + if (tls12_supported_signature_algorithms_to_bytes(sig_algs, sig_algs_cnt, &p, &len) != 1) { + error_print(); + return -1; + } tls_uint16array_to_bytes(ca_names, ca_names_len, &p, &len); tls_record_set_handshake(record, recordlen, type, NULL, datalen); return 1; @@ -241,7 +322,8 @@ int tls12_record_get_handshake_certificate_request(const uint8_t *record, size_t len; size_t i; - if (!record || !cert_types || !cert_types_len || !ca_names || !ca_names_len) { + if (!record || !cert_types || !cert_types_len + || !sig_algs || !sig_algs_len || !ca_names || !ca_names_len) { error_print(); return -1; } @@ -254,6 +336,7 @@ int tls12_record_get_handshake_certificate_request(const uint8_t *record, return -1; } if (tls_uint8array_from_bytes(cert_types, cert_types_len, &cp, &len) != 1 + || tls12_supported_signature_algorithms_from_bytes(sig_algs, sig_algs_len, &cp, &len) != 1 || tls_uint16array_from_bytes(ca_names, ca_names_len, &cp, &len) != 1 || tls_length_is_zero(len) != 1) { error_print(); @@ -327,6 +410,66 @@ int tls12_record_get_handshake_client_key_exchange(const uint8_t *record, return 1; } +static int tls12_record_set_handshake_certificate_verify(uint8_t *record, size_t *recordlen, + int sig_alg, const uint8_t *sig, size_t siglen) +{ + int type = TLS_handshake_certificate_verify; + uint8_t *p; + size_t len = 0; + + if (!record || !recordlen || !sig || !siglen) { + error_print(); + return -1; + } + if (!tls_signature_scheme_name(sig_alg)) { + error_print(); + return -1; + } + if (siglen > TLS_MAX_SIGNATURE_SIZE) { + error_print(); + return -1; + } + p = tls_handshake_data(tls_record_data(record)); + tls_uint16_to_bytes((uint16_t)sig_alg, &p, &len); + tls_uint16array_to_bytes(sig, siglen, &p, &len); + tls_record_set_handshake(record, recordlen, type, NULL, len); + return 1; +} + +static int tls12_record_get_handshake_certificate_verify(const uint8_t *record, + int *sig_alg, const uint8_t **sig, size_t *siglen) +{ + int type; + const uint8_t *cp; + size_t len; + uint16_t alg; + + if (!record || !sig_alg || !sig || !siglen) { + error_print(); + return -1; + } + if (tls_record_get_handshake(record, &type, &cp, &len) != 1) { + error_print(); + return -1; + } + if (type != TLS_handshake_certificate_verify) { + error_print(); + return -1; + } + if (tls_uint16_from_bytes(&alg, &cp, &len) != 1 + || tls_uint16array_from_bytes(sig, siglen, &cp, &len) != 1 + || tls_length_is_zero(len) != 1) { + error_print(); + return -1; + } + if (!tls_signature_scheme_name(alg)) { + error_print(); + return -1; + } + *sig_alg = alg; + return 1; +} + @@ -1460,8 +1603,15 @@ int tls12_recv_certificate_request(TLS_CONNECT *conn) size_t cert_types_len; const uint8_t *sig_algs; size_t sig_algs_len; + const int *local_sig_algs; + size_t local_sig_algs_cnt; + int common_sig_algs[32]; + size_t common_sig_algs_cnt = 0; const uint8_t *ca_names; size_t ca_names_len; + const uint8_t *client_cert; + size_t client_cert_len; + int client_sig_alg; if(conn->verbose) tls_trace("recv CertificateRequest*\n"); @@ -1506,12 +1656,59 @@ int tls12_recv_certificate_request(TLS_CONNECT *conn) return -1; } + local_sig_algs = conn->ctx->signature_algorithms; + local_sig_algs_cnt = conn->ctx->signature_algorithms_cnt; + if (!local_sig_algs_cnt) { + local_sig_algs = tls12_signature_algorithms; + local_sig_algs_cnt = tls12_signature_algorithms_cnt; + } + if ((ret = tls_process_signature_algorithms(sig_algs, sig_algs_len, + local_sig_algs, local_sig_algs_cnt, + common_sig_algs, &common_sig_algs_cnt, + sizeof(common_sig_algs)/sizeof(common_sig_algs[0]))) < 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_unsupported_certificate); + return -1; + } + if (tls_cert_types_has_ecdsa_sign(cert_types, cert_types_len) != 1 || tls_authorities_issued_certificate(ca_names, ca_names_len, conn->client_certs, conn->client_certs_len) != 1) { error_print(); tls_send_alert(conn, TLS_alert_unsupported_certificate); return -1; } + if (x509_certs_get_cert_by_index(conn->client_certs, conn->client_certs_len, + 0, &client_cert, &client_cert_len) != 1) { + error_print(); + tls_send_alert(conn, TLS_alert_bad_certificate); + return -1; + } + if ((ret = tls_cert_match_signature_algorithms(client_cert, client_cert_len, + common_sig_algs, common_sig_algs_cnt, &client_sig_alg)) < 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 ((ret = tls_cert_chain_match_signature_algorithms_cert(conn->client_certs, conn->client_certs_len, + common_sig_algs, common_sig_algs_cnt)) < 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; + } + + conn->sig_alg = client_sig_alg; sm2_sign_update(&conn->sign_ctx, conn->record + 5, conn->recordlen - 5); @@ -1708,7 +1905,13 @@ int tls_send_certificate_verify(TLS_CONNECT *conn) } gmssl_secure_clear(&sign_ctx, sizeof(sign_ctx)); - if (tls_record_set_handshake_certificate_verify(conn->record, &conn->recordlen, sig, siglen) != 1) { + if (conn->protocol == TLS_protocol_tls12) { + ret = tls12_record_set_handshake_certificate_verify(conn->record, &conn->recordlen, + conn->sig_alg, sig, siglen); + } else { + ret = tls_record_set_handshake_certificate_verify(conn->record, &conn->recordlen, sig, siglen); + } + if (ret != 1) { error_print(); tls_send_alert(conn, TLS_alert_internal_error); return -1; @@ -2464,6 +2667,8 @@ int tls12_send_certificate_request(TLS_CONNECT *conn) // 如果要进行客户端证书验证,服务器要提供验证的证书,但是所有证书的 const uint8_t cert_types[] = { TLS_cert_type_ecdsa_sign }; + const int *sig_algs = conn->ctx->signature_algorithms; + size_t sig_algs_cnt = conn->ctx->signature_algorithms_cnt; uint8_t ca_names[TLS_MAX_CA_NAMES_SIZE] = {0}; // TODO: 根据客户端验证CA证书列计算缓冲大小,或直接输出到record缓冲 size_t ca_names_len = 0; @@ -2472,6 +2677,10 @@ int tls12_send_certificate_request(TLS_CONNECT *conn) error_print(); return -1; } + if (!sig_algs_cnt) { + sig_algs = tls12_signature_algorithms; + sig_algs_cnt = tls12_signature_algorithms_cnt; + } if (conn->recordlen == 0) { if(conn->verbose) tls_trace("send CertificateRequest\n"); @@ -2483,7 +2692,7 @@ int tls12_send_certificate_request(TLS_CONNECT *conn) } if (tls12_record_set_handshake_certificate_request(conn->record, &conn->recordlen, cert_types, sizeof(cert_types), - NULL, 0, // TODO: 这里需要至少添加TLS_cert_type_ecdsa_sign + sig_algs, sig_algs_cnt, ca_names, ca_names_len) != 1) { error_print(); tls_send_alert(conn, TLS_alert_internal_error); @@ -2687,6 +2896,9 @@ int tls_recv_certificate_verify(TLS_CONNECT *conn) size_t signer_idlen = 0; const uint8_t *sig; size_t siglen; + int sig_alg = 0; + const int *local_sig_algs; + size_t local_sig_algs_cnt; const uint8_t *client_cert; size_t client_cert_len; @@ -2711,8 +2923,26 @@ int tls_recv_certificate_verify(TLS_CONNECT *conn) } if (conn->verbose) tls_record_print(stderr, 0, 0, conn->cipher_suite, conn->record, conn->recordlen); + local_sig_algs = conn->ctx->signature_algorithms; + local_sig_algs_cnt = conn->ctx->signature_algorithms_cnt; + if (!local_sig_algs_cnt) { + local_sig_algs = tls12_signature_algorithms; + local_sig_algs_cnt = tls12_signature_algorithms_cnt; + } + // get signature from certificate_verify - if (tls_record_get_handshake_certificate_verify(conn->record, &sig, &siglen) != 1) { + if (conn->protocol == TLS_protocol_tls12) { + if (tls12_record_get_handshake_certificate_verify(conn->record, &sig_alg, &sig, &siglen) != 1) { + tls_send_alert(conn, TLS_alert_unexpected_message); + error_print(); + return -1; + } + if (tls_type_is_in_list(sig_alg, local_sig_algs, local_sig_algs_cnt) != 1) { + tls_send_alert(conn, TLS_alert_unsupported_certificate); + error_print(); + return -1; + } + } else if (tls_record_get_handshake_certificate_verify(conn->record, &sig, &siglen) != 1) { tls_send_alert(conn, TLS_alert_unexpected_message); error_print(); return -1; diff --git a/src/tls_trace.c b/src/tls_trace.c index d69fda4d..293e85d7 100644 --- a/src/tls_trace.c +++ b/src/tls_trace.c @@ -887,8 +887,9 @@ int tls_certificate_subjects_print(FILE *fp, int fmt, int ind, const char *label int tls_certificate_request_print(FILE *fp, const uint8_t *data, size_t datalen, int fmt, int ind) { const uint8_t *cert_types; + const uint8_t *sig_algs; const uint8_t *ca_names; - size_t cert_types_len, ca_names_len; + size_t cert_types_len, sig_algs_len, ca_names_len; format_print(fp, fmt, ind, "CertificateRequest\n"); ind += 4; if (tls_uint8array_from_bytes(&cert_types, &cert_types_len, &data, &datalen) != 1) goto bad; @@ -897,8 +898,20 @@ int tls_certificate_request_print(FILE *fp, const uint8_t *data, size_t datalen, int cert_type = *cert_types++; format_print(fp, fmt, ind + 4, "%s (%d)\n", tls_cert_type_name(cert_type), cert_type); } + if (tls_uint16array_from_bytes(&sig_algs, &sig_algs_len, &data, &datalen) != 1) goto bad; + format_print(fp, fmt, ind, "signature_algorithms\n"); + while (sig_algs_len) { + const char *sig_alg_name; + uint16_t sig_alg; + + if (tls_uint16_from_bytes(&sig_alg, &sig_algs, &sig_algs_len) != 1) goto bad; + sig_alg_name = tls_signature_scheme_name(sig_alg); + format_print(fp, fmt, ind + 4, "%s (0x%04x)\n", + sig_alg_name ? sig_alg_name : "unknown", sig_alg); + } if (tls_uint16array_from_bytes(&ca_names, &ca_names_len, &data, &datalen) != 1) goto bad; tls_certificate_subjects_print(fp, fmt, ind, "CAnames", ca_names, ca_names_len); + if (datalen) goto bad; return 1; bad: @@ -984,7 +997,22 @@ struct { */ int tls_certificate_verify_print(FILE *fp, const uint8_t *data, size_t datalen, int fmt, int ind) { + const uint8_t *p = data; + size_t len = datalen; + uint16_t sig_alg; + const char *sig_alg_name; + const uint8_t *sig; + size_t siglen; + format_print(fp, fmt, ind, "CertificateVerify\n"); + if (tls_uint16_from_bytes(&sig_alg, &p, &len) == 1 + && (sig_alg_name = tls_signature_scheme_name(sig_alg)) != NULL + && tls_uint16array_from_bytes(&sig, &siglen, &p, &len) == 1 + && tls_length_is_zero(len) == 1) { + format_print(fp, fmt, ind + 4, "algorithm: %s (0x%04x)\n", sig_alg_name, sig_alg); + format_bytes(fp, fmt, ind + 4, "Signature", sig, siglen); + return 1; + } format_bytes(fp, fmt, ind + 4, "Signature", data, datalen); return 1; }