From c87b8e01e055a360ab44e47983cf742cbfaaaf8b Mon Sep 17 00:00:00 2001 From: Zhi Guan Date: Fri, 19 Jun 2026 20:06:00 +0800 Subject: [PATCH] Add TLS cert verify --- CMakeLists.txt | 3 +- include/gmssl/tls.h | 17 ++ include/gmssl/version.h | 2 +- src/tlcp.c | 50 ++--- src/tls12.c | 172 ++++------------ src/tls13.c | 90 ++++----- src/tls_vrf.c | 422 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 529 insertions(+), 227 deletions(-) create mode 100644 src/tls_vrf.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e81ae34..bd885639 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -565,6 +565,7 @@ if (ENABLE_TLS) src/tls_ocsp.c src/tls_cookie.c src/tls_trace.c + src/tls_vrf.c src/tlcp.c src/tls12.c src/tls13.c) @@ -821,7 +822,7 @@ endif() # set(CPACK_PACKAGE_NAME "GmSSL") set(CPACK_PACKAGE_VENDOR "GmSSL develop team") -set(CPACK_PACKAGE_VERSION "3.2.0-dev.1108") +set(CPACK_PACKAGE_VERSION "3.2.0-dev.1109") 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 35ccbc89..977c70e0 100644 --- a/include/gmssl/tls.h +++ b/include/gmssl/tls.h @@ -1889,6 +1889,23 @@ int tls_cert_chain_match_extensions( const uint8_t *host_name, size_t host_name_len, // optional int *prefered_sig_alg); +int tls_cert_chain_verify( + int protocol, int cert_chain_type, int cipher_suite, + int verify_chain, + const uint8_t *cert_chain, size_t cert_chain_len, + const uint8_t *cacerts, size_t cacerts_len, + const uint8_t *crl, size_t crl_len, + const uint8_t *ocsp, size_t ocsp_len, + int verify_depth, + const int *supported_groups, size_t supported_groups_cnt, + const int *signature_algorithms, size_t signature_algorithms_cnt, + const int *signature_algorithms_cert, size_t signature_algorithms_cert_cnt, + const uint8_t *ca_names, size_t ca_names_len, + const uint8_t *oid_filters, size_t oid_filters_len, + const uint8_t *host_name, size_t host_name_len, + int *verify_result, + int *selected_sig_alg); + int tls13_cert_chains_select(const uint8_t *cert_chains, size_t cert_chains_len, const int *signature_algorithms, size_t signature_algorithms_cnt, diff --git a/include/gmssl/version.h b/include/gmssl/version.h index 8adb0efe..4f55238c 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.1108" +#define GMSSL_VERSION_STR "GmSSL 3.2.0-dev.1109" int gmssl_version_num(void); const char *gmssl_version_str(void); diff --git a/src/tlcp.c b/src/tlcp.c index 711dd388..9e295dda 100644 --- a/src/tlcp.c +++ b/src/tlcp.c @@ -746,9 +746,8 @@ int tlcp_recv_server_hello(TLS_CONNECT *conn) int tlcp_recv_server_certificate(TLS_CONNECT *conn) { int ret; - const uint8_t *server_cert; - size_t server_cert_len; int verify_result = X509_verify_ok; + int sig_alg = 0; if ((ret = tls_recv_record(conn)) != 1) { if (ret != TLS_ERROR_RECV_AGAIN) { @@ -785,41 +784,28 @@ int tlcp_recv_server_certificate(TLS_CONNECT *conn) 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, - 0, &server_cert, &server_cert_len) != 1) { + if (tls_cert_chain_verify(conn->protocol, X509_cert_chain_server, conn->cipher_suite, + conn->ctx->cacertslen ? 1 : 0, + conn->peer_cert_chain, conn->peer_cert_chain_len, + conn->ctx->cacerts, conn->ctx->cacertslen, + NULL, 0, + NULL, 0, + conn->ctx->verify_depth, + NULL, 0, + conn->ctx->signature_algorithms, conn->ctx->signature_algorithms_cnt, + NULL, 0, + NULL, 0, + NULL, 0, + conn->host_name, conn->host_name_len, + &verify_result, &sig_alg) != 1) { error_print(); + conn->verify_result = verify_result; tls_send_alert(conn, TLS_alert_bad_certificate); return -1; } - if (conn->host_name_len) { - if ((ret = tls_cert_match_server_name(server_cert, server_cert_len, - conn->host_name, conn->host_name_len)) < 0) { - error_print(); - conn->verify_result = X509_verify_err_hostname; - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } else if (ret == 0) { - error_print(); - conn->verify_result = X509_verify_err_hostname; - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } - } - // FIXME: 需要根据密码套件、ClientHello扩展等对证书做进一步的验证 - // x509_certs_verify_tlcp 只是验证证书链有效,不能完全判定服务器证书有效 - - if (conn->ctx->cacertslen) { - if (x509_certs_verify_tlcp(conn->peer_cert_chain, conn->peer_cert_chain_len, X509_cert_chain_server, - conn->ctx->cacerts, conn->ctx->cacertslen, NULL, 0, - NULL, 0, - conn->ctx->verify_depth, &verify_result) != 1) { - error_print(); - conn->verify_result = verify_result; - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } - } conn->verify_result = verify_result; + conn->signature_algorithms[0] = sig_alg; + conn->signature_algorithms_cnt = 1; if (conn->client_certs_len) { sm2_sign_update(&conn->sign_ctx, conn->record + 5, conn->recordlen - 5); diff --git a/src/tls12.c b/src/tls12.c index 6b41c17a..5ee035d1 100644 --- a/src/tls12.c +++ b/src/tls12.c @@ -1245,13 +1245,8 @@ int tls_recv_server_hello(TLS_CONNECT *conn) int tls_recv_server_certificate(TLS_CONNECT *conn) { int ret; - int verify_result = 0; - const uint8_t *server_cert; - size_t server_cert_len; - X509_KEY server_sign_key; + int verify_result = X509_verify_ok; int server_sig_alg = 0; - int server_group; - int cert_sig_alg = 0; const int *signature_algorithms_cert = NULL; size_t signature_algorithms_cert_cnt = 0; @@ -1301,91 +1296,6 @@ int tls_recv_server_certificate(TLS_CONNECT *conn) return -1; } - - // server_sign_key - if (x509_certs_get_cert_by_index(conn->peer_cert_chain, conn->peer_cert_chain_len, 0, - &server_cert, &server_cert_len) != 1) { - error_print(); - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } - if (x509_cert_get_subject_public_key(server_cert, server_cert_len, &server_sign_key) != 1) { - error_print(); - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } - - if (tls12_public_key_get_group(&server_sign_key, &server_group) != 1) { - error_print(); - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } - - // check server certificate matches negotiated cipher_suite - if (!tls12_cipher_suite_match_cert_group(conn->cipher_suite, server_group)) { - error_print(); - conn->verify_result = X509_verify_err_tls_extensions; - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } - switch (conn->cipher_suite) { - case TLS_cipher_ecdhe_sm4_cbc_sm3: - case TLS_cipher_ecdhe_sm4_gcm_sm3: - case TLS_cipher_ecc_sm4_cbc_sm3: - case TLS_cipher_ecc_sm4_gcm_sm3: - server_sig_alg = TLS_sig_sm2sig_sm3; - break; - case TLS_cipher_ecdhe_ecdsa_with_aes_128_cbc_sha256: - case TLS_cipher_ecdhe_ecdsa_with_aes_128_gcm_sha256: -#ifdef ENABLE_AES_CCM - case TLS_cipher_ecdhe_ecdsa_with_aes_128_ccm: -#endif - server_sig_alg = TLS_sig_ecdsa_secp256r1_sha256; - break; - default: - error_print(); - conn->verify_result = X509_verify_err_tls_extensions; - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } - - // check server certificate matches ClientHello.supported_groups - if (conn->ctx->supported_groups_cnt) { - if (!tls_type_is_in_list(server_group, conn->ctx->supported_groups, - conn->ctx->supported_groups_cnt)) { - error_print(); - conn->verify_result = X509_verify_err_tls_extensions; - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } - } - - // check server certificate matches ClientHello.signature_algorithms - if (conn->ctx->signature_algorithms_cnt) { - if ((ret = tls_cert_match_signature_algorithms(server_cert, server_cert_len, - conn->ctx->signature_algorithms, - conn->ctx->signature_algorithms_cnt, - &cert_sig_alg)) < 0) { - error_print(); - conn->verify_result = X509_verify_err_tls_extensions; - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } else if (ret == 0) { - error_print(); - conn->verify_result = X509_verify_err_tls_extensions; - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } - if (!tls12_signature_scheme_match_cert_group(cert_sig_alg, server_group) - || !tls12_signature_scheme_match_cipher_suite(cert_sig_alg, conn->cipher_suite)) { - error_print(); - conn->verify_result = X509_verify_err_tls_extensions; - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } - server_sig_alg = cert_sig_alg; - } - // check certificate-chain signatures match ClientHello.signature_algorithms_cert if (conn->signature_algorithms_cert) { signature_algorithms_cert = conn->ctx->signature_algorithms; @@ -1394,40 +1304,6 @@ int tls_recv_server_certificate(TLS_CONNECT *conn) signature_algorithms_cert = conn->ctx->signature_algorithms; signature_algorithms_cert_cnt = conn->ctx->signature_algorithms_cnt; } - if (signature_algorithms_cert && signature_algorithms_cert_cnt) { - if ((ret = tls_cert_chain_match_signature_algorithms_cert( - conn->peer_cert_chain, conn->peer_cert_chain_len, - signature_algorithms_cert, signature_algorithms_cert_cnt)) < 0) { - error_print(); - conn->verify_result = X509_verify_err_tls_extensions; - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } else if (ret == 0) { - error_print(); - conn->verify_result = X509_verify_err_tls_extensions; - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } - } - - // check server certificate matches configured hostname - if (conn->host_name_len) { - if ((ret = tls_cert_match_server_name(server_cert, server_cert_len, - conn->host_name, conn->host_name_len)) < 0) { - error_print(); - conn->verify_result = X509_verify_err_hostname; - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } else if (ret == 0) { - error_print(); - conn->verify_result = X509_verify_err_hostname; - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } - } - - conn->signature_algorithms[0] = server_sig_alg; - conn->signature_algorithms_cnt = 1; if (conn->client_certs_len) { sm2_sign_update(&conn->sign_ctx, conn->record + 5, conn->recordlen - 5); @@ -1436,18 +1312,28 @@ int tls_recv_server_certificate(TLS_CONNECT *conn) assert(conn->ctx->verify_depth > 0 && conn->ctx->verify_depth < 10); // verify server Certificate - if (conn->ctx->cacertslen) { - if (x509_certs_verify(conn->peer_cert_chain, conn->peer_cert_chain_len, X509_cert_chain_server, - conn->ctx->cacerts, conn->ctx->cacertslen, NULL, 0, - NULL, 0, - conn->ctx->verify_depth, &verify_result) != 1) { - error_print(); - conn->verify_result = verify_result; - tls_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } + if (tls_cert_chain_verify(conn->protocol, X509_cert_chain_server, conn->cipher_suite, + conn->ctx->cacertslen ? 1 : 0, + conn->peer_cert_chain, conn->peer_cert_chain_len, + conn->ctx->cacerts, conn->ctx->cacertslen, + NULL, 0, + NULL, 0, + conn->ctx->verify_depth, + conn->ctx->supported_groups, conn->ctx->supported_groups_cnt, + conn->ctx->signature_algorithms, conn->ctx->signature_algorithms_cnt, + signature_algorithms_cert, signature_algorithms_cert_cnt, + NULL, 0, + NULL, 0, + conn->host_name, conn->host_name_len, + &verify_result, &server_sig_alg) != 1) { + error_print(); + conn->verify_result = verify_result; + tls_send_alert(conn, TLS_alert_bad_certificate); + return -1; } conn->verify_result = verify_result; + conn->signature_algorithms[0] = server_sig_alg; + conn->signature_algorithms_cnt = 1; return 1; } @@ -2803,10 +2689,20 @@ int tls_recv_client_certificate(TLS_CONNECT *conn) tls_send_alert(conn, TLS_alert_unexpected_message); return -1; } - if (x509_certs_verify(conn->client_certs, conn->client_certs_len, X509_cert_chain_client, - conn->ctx->cacerts, conn->ctx->cacertslen, NULL, 0, + if (tls_cert_chain_verify(conn->protocol, X509_cert_chain_client, conn->cipher_suite, + 1, + conn->client_certs, conn->client_certs_len, + conn->ctx->cacerts, conn->ctx->cacertslen, NULL, 0, - conn->ctx->verify_depth, &verify_result) != 1) { + NULL, 0, + conn->ctx->verify_depth, + NULL, 0, + conn->ctx->signature_algorithms, conn->ctx->signature_algorithms_cnt, + NULL, 0, + NULL, 0, + NULL, 0, + NULL, 0, + &verify_result, NULL) != 1) { error_print(); conn->verify_result = verify_result; tls_send_alert(conn, TLS_alert_bad_certificate); diff --git a/src/tls13.c b/src/tls13.c index 937cd7e5..1bdf29b9 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -6242,50 +6242,23 @@ int tls13_recv_server_certificate(TLS_CONNECT *conn) host_name = conn->host_name; host_name_len = conn->host_name_len; } - if (host_name && host_name_len) { - if (x509_certs_get_cert_by_index(conn->peer_cert_chain, - conn->peer_cert_chain_len, 0, &cert, &certlen) != 1) { - error_print(); - conn->verify_result = X509_verify_err_certificate; - tls13_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } - if ((ret = tls_cert_match_server_name(cert, certlen, host_name, host_name_len)) < 0) { - error_print(); - conn->verify_result = X509_verify_err_hostname; - tls13_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } else if (ret == 0) { - error_print(); - conn->verify_result = X509_verify_err_hostname; - tls13_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } - } - if (tls_cert_chain_match_extensions(conn->peer_cert_chain, conn->peer_cert_chain_len, - conn->ctx->signature_algorithms, conn->ctx->signature_algorithms_cnt, - signature_algorithms_cert, signature_algorithms_cert_cnt, - ca_names, ca_names_len, // certificate_authorities - NULL, 0, // oid_filters - host_name, host_name_len, - NULL) != 1) { - error_print(); - conn->verify_result = X509_verify_err_tls_extensions; - tls13_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } // verify server cert_chain - // 函数x509_certs_verify的设计有问题 - // 验证一个证书链之前,应该首先判断一下这个证书链对应的根证书是否存在 - // 如果我们没有根证书,那么就根本不能验证 - // 把查找根证书和验证证书链的函数分开 - ret = x509_certs_verify( - conn->peer_cert_chain, conn->peer_cert_chain_len, X509_cert_chain_server, + ret = tls_cert_chain_verify( + conn->protocol, X509_cert_chain_server, conn->cipher_suite, + 1, + conn->peer_cert_chain, conn->peer_cert_chain_len, conn->ctx->cacerts, conn->ctx->cacertslen, NULL, 0, leaf_status_request_ocsp_response, leaf_status_request_ocsp_response_len, - conn->ctx->verify_depth, &verify_result); + conn->ctx->verify_depth, + NULL, 0, + conn->ctx->signature_algorithms, conn->ctx->signature_algorithms_cnt, + signature_algorithms_cert, signature_algorithms_cert_cnt, + ca_names, ca_names_len, + NULL, 0, + host_name, host_name_len, + &verify_result, NULL); if (ret < 0) { error_print(); conn->verify_result = verify_result; @@ -6295,7 +6268,12 @@ int tls13_recv_server_certificate(TLS_CONNECT *conn) if (ret == 0) { error_print(); conn->verify_result = verify_result; - tls13_send_alert(conn, TLS_alert_certificate_revoked); + if (verify_result == X509_verify_err_crl + || verify_result == X509_verify_err_ocsp) { + tls13_send_alert(conn, TLS_alert_certificate_revoked); + } else { + tls13_send_alert(conn, TLS_alert_bad_certificate); + } return -1; } conn->verify_result = verify_result; @@ -8626,25 +8604,22 @@ int tls13_recv_client_certificate(TLS_CONNECT *conn) oid_filters = conn->ctx->oid_filters; oid_filters_len = conn->ctx->oid_filters_len; } - if (tls_cert_chain_match_extensions(conn->peer_cert_chain, conn->peer_cert_chain_len, + // verify client cert_chain + ret = tls_cert_chain_verify( + conn->protocol, X509_cert_chain_client, conn->cipher_suite, + 1, + conn->peer_cert_chain, conn->peer_cert_chain_len, + conn->ctx->cacerts, conn->ctx->cacertslen, + NULL, 0, + status_request_ocsp_response, status_request_ocsp_response_len, + conn->ctx->verify_depth, + NULL, 0, conn->ctx->signature_algorithms, conn->ctx->signature_algorithms_cnt, signature_algorithms_cert, signature_algorithms_cert_cnt, ca_names, ca_names_len, oid_filters, oid_filters_len, - NULL, 0, // server_name not in CertificateRequest - NULL) != 1) { - error_print(); - conn->verify_result = X509_verify_err_tls_extensions; - tls13_send_alert(conn, TLS_alert_bad_certificate); - return -1; - } - - // verify client cert_chain - ret = x509_certs_verify(conn->peer_cert_chain, conn->peer_cert_chain_len, X509_cert_chain_client, - conn->ctx->cacerts, conn->ctx->cacertslen, NULL, 0, - status_request_ocsp_response, status_request_ocsp_response_len, - conn->ctx->verify_depth, &verify_result); + &verify_result, NULL); if (ret < 0) { error_print(); conn->verify_result = verify_result; @@ -8654,7 +8629,12 @@ int tls13_recv_client_certificate(TLS_CONNECT *conn) if (ret == 0) { error_print(); conn->verify_result = verify_result; - tls13_send_alert(conn, TLS_alert_certificate_revoked); + if (verify_result == X509_verify_err_crl + || verify_result == X509_verify_err_ocsp) { + tls13_send_alert(conn, TLS_alert_certificate_revoked); + } else { + tls13_send_alert(conn, TLS_alert_bad_certificate); + } return -1; } conn->verify_result = verify_result; diff --git a/src/tls_vrf.c b/src/tls_vrf.c new file mode 100644 index 00000000..05eca140 --- /dev/null +++ b/src/tls_vrf.c @@ -0,0 +1,422 @@ +/* + * 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 +#include +#include + + +static void tls_cert_verify_set_result(int *verify_result, int result) +{ + if (verify_result) { + *verify_result = result; + } +} + +static int tls_cert_verify_get_cert_group(const uint8_t *cert, size_t certlen, int *group) +{ + X509_KEY public_key; + + if (!cert || !certlen || !group) { + error_print(); + return -1; + } + if (x509_cert_get_subject_public_key(cert, certlen, &public_key) != 1) { + error_print(); + return -1; + } + if (public_key.algor != OID_ec_public_key) { + error_print(); + return -1; + } + if ((*group = tls_named_curve_from_oid(public_key.algor_param)) == 0) { + error_print(); + return -1; + } + return 1; +} + +static int tls12_cipher_suite_match_cert_group(int cipher_suite, int cert_group) +{ + switch (cipher_suite) { + case TLS_cipher_ecdhe_sm4_cbc_sm3: + case TLS_cipher_ecdhe_sm4_gcm_sm3: + return cert_group == TLS_curve_sm2p256v1; + 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: + return cert_group == TLS_curve_secp256r1; + default: + return 0; + } +} + +static int tls12_signature_scheme_match_cert_group(int sig_alg, int cert_group) +{ + return tls_signature_scheme_group_oid(sig_alg) == tls_named_curve_oid(cert_group); +} + +static int tls12_signature_scheme_match_cipher_suite(int sig_alg, int cipher_suite) +{ + switch (sig_alg) { + case TLS_sig_sm2sig_sm3: + switch (cipher_suite) { + case TLS_cipher_ecdhe_sm4_cbc_sm3: + case TLS_cipher_ecdhe_sm4_gcm_sm3: + return 1; + } + break; + case TLS_sig_ecdsa_secp256r1_sha256: + switch (cipher_suite) { + 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: + return 1; + } + break; + } + return 0; +} + +static int tls12_signature_scheme_from_cipher_suite(int cipher_suite) +{ + switch (cipher_suite) { + case TLS_cipher_ecdhe_sm4_cbc_sm3: + case TLS_cipher_ecdhe_sm4_gcm_sm3: + case TLS_cipher_ecc_sm4_cbc_sm3: + case TLS_cipher_ecc_sm4_gcm_sm3: + return TLS_sig_sm2sig_sm3; + 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: + return TLS_sig_ecdsa_secp256r1_sha256; + default: + return -1; + } +} + +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) +{ + int ret; + const uint8_t *cert; + size_t certlen; + + if (!host_name || !host_name_len) { + return 1; + } + if (x509_certs_get_cert_by_index(cert_chain, cert_chain_len, 0, &cert, &certlen) != 1) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_certificate); + return -1; + } + if ((ret = tls_cert_match_server_name(cert, certlen, host_name, host_name_len)) < 0) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_hostname); + return -1; + } + if (ret == 0) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_hostname); + return 0; + } + return 1; +} + +static int tls12_cert_chain_match( + int cert_chain_type, int cipher_suite, + const uint8_t *cert_chain, size_t cert_chain_len, + const int *supported_groups, size_t supported_groups_cnt, + const int *signature_algorithms, size_t signature_algorithms_cnt, + const int *signature_algorithms_cert, size_t signature_algorithms_cert_cnt, + const uint8_t *ca_names, size_t ca_names_len, + const uint8_t *host_name, size_t host_name_len, + int *verify_result, int *selected_sig_alg) +{ + int ret; + const uint8_t *cert; + size_t certlen; + int cert_group; + int sig_alg; + + if (x509_certs_get_cert_by_index(cert_chain, cert_chain_len, 0, &cert, &certlen) != 1) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_certificate); + return -1; + } + + if (cert_chain_type == X509_cert_chain_server) { + if (tls_cert_verify_get_cert_group(cert, certlen, &cert_group) != 1) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_certificate); + return -1; + } + if (!tls12_cipher_suite_match_cert_group(cipher_suite, cert_group)) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return 0; + } + if (supported_groups && supported_groups_cnt) { + if (!tls_type_is_in_list(cert_group, supported_groups, supported_groups_cnt)) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return 0; + } + } + sig_alg = tls12_signature_scheme_from_cipher_suite(cipher_suite); + if (sig_alg < 0) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return -1; + } + if (selected_sig_alg) { + *selected_sig_alg = sig_alg; + } + } + + if (signature_algorithms && signature_algorithms_cnt) { + if ((ret = tls_cert_match_signature_algorithms(cert, certlen, + signature_algorithms, signature_algorithms_cnt, &sig_alg)) < 0) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return -1; + } + if (ret == 0) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return 0; + } + if (cert_chain_type == X509_cert_chain_server) { + if (!tls12_signature_scheme_match_cert_group(sig_alg, cert_group) + || !tls12_signature_scheme_match_cipher_suite(sig_alg, cipher_suite)) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return 0; + } + } + if (selected_sig_alg) { + *selected_sig_alg = sig_alg; + } + } + + if (signature_algorithms_cert && signature_algorithms_cert_cnt) { + if ((ret = tls_cert_chain_match_signature_algorithms_cert(cert_chain, cert_chain_len, + signature_algorithms_cert, signature_algorithms_cert_cnt)) < 0) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return -1; + } + if (ret == 0) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return 0; + } + } + + if (ca_names && ca_names_len) { + if ((ret = tls_authorities_issued_certificate(ca_names, ca_names_len, + cert_chain, cert_chain_len)) < 0) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return -1; + } + if (ret == 0) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return 0; + } + } + + return tls_cert_chain_check_name(cert_chain, cert_chain_len, + host_name, host_name_len, verify_result); +} + +static int tlcp_cert_chain_match( + int cert_chain_type, int cipher_suite, + const uint8_t *cert_chain, size_t cert_chain_len, + const int *signature_algorithms, size_t signature_algorithms_cnt, + const uint8_t *ca_names, size_t ca_names_len, + const uint8_t *host_name, size_t host_name_len, + int *verify_result, int *selected_sig_alg) +{ + int ret; + + switch (cipher_suite) { + case TLS_cipher_ecc_sm4_cbc_sm3: + case TLS_cipher_ecc_sm4_gcm_sm3: + case TLS_cipher_ecdhe_sm4_cbc_sm3: + case TLS_cipher_ecdhe_sm4_gcm_sm3: + break; + default: + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return 0; + } + + if (signature_algorithms && signature_algorithms_cnt) { + if (!tls_type_is_in_list(TLS_sig_sm2sig_sm3, + signature_algorithms, signature_algorithms_cnt)) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return 0; + } + } + if (selected_sig_alg) { + *selected_sig_alg = TLS_sig_sm2sig_sm3; + } + + if (ca_names && ca_names_len) { + if ((ret = tls_authorities_issued_certificate(ca_names, ca_names_len, + cert_chain, cert_chain_len)) < 0) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return -1; + } + if (ret == 0) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return 0; + } + } + + if (cert_chain_type == X509_cert_chain_server) { + return tls_cert_chain_check_name(cert_chain, cert_chain_len, + host_name, host_name_len, verify_result); + } + return 1; +} + +static int tls13_cert_chain_match( + const uint8_t *cert_chain, size_t cert_chain_len, + const int *signature_algorithms, size_t signature_algorithms_cnt, + const int *signature_algorithms_cert, size_t signature_algorithms_cert_cnt, + const uint8_t *ca_names, size_t ca_names_len, + const uint8_t *oid_filters, size_t oid_filters_len, + const uint8_t *host_name, size_t host_name_len, + int *verify_result, int *selected_sig_alg) +{ + int ret; + + if ((ret = tls_cert_chain_check_name(cert_chain, cert_chain_len, + host_name, host_name_len, verify_result)) != 1) { + return ret; + } + if ((ret = tls_cert_chain_match_extensions(cert_chain, cert_chain_len, + signature_algorithms, signature_algorithms_cnt, + signature_algorithms_cert, signature_algorithms_cert_cnt, + ca_names, ca_names_len, + oid_filters, oid_filters_len, + NULL, 0, + selected_sig_alg)) < 0) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return -1; + } + if (ret == 0) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return 0; + } + return 1; +} + +int tls_cert_chain_verify( + int protocol, int cert_chain_type, int cipher_suite, + int verify_chain, + const uint8_t *cert_chain, size_t cert_chain_len, + const uint8_t *cacerts, size_t cacerts_len, + const uint8_t *crl, size_t crl_len, + const uint8_t *ocsp, size_t ocsp_len, + int verify_depth, + const int *supported_groups, size_t supported_groups_cnt, + const int *signature_algorithms, size_t signature_algorithms_cnt, + const int *signature_algorithms_cert, size_t signature_algorithms_cert_cnt, + const uint8_t *ca_names, size_t ca_names_len, + const uint8_t *oid_filters, size_t oid_filters_len, + const uint8_t *host_name, size_t host_name_len, + int *verify_result, + int *selected_sig_alg) +{ + int ret; + + if (!cert_chain || !cert_chain_len) { + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_certificate); + return -1; + } + if (selected_sig_alg) { + *selected_sig_alg = 0; + } + tls_cert_verify_set_result(verify_result, X509_verify_ok); + + switch (protocol) { + case TLS_protocol_tls12: + ret = tls12_cert_chain_match(cert_chain_type, cipher_suite, + cert_chain, cert_chain_len, + supported_groups, supported_groups_cnt, + signature_algorithms, signature_algorithms_cnt, + signature_algorithms_cert, signature_algorithms_cert_cnt, + ca_names, ca_names_len, + host_name, host_name_len, + verify_result, selected_sig_alg); + break; + case TLS_protocol_tlcp: + ret = tlcp_cert_chain_match(cert_chain_type, cipher_suite, + cert_chain, cert_chain_len, + signature_algorithms, signature_algorithms_cnt, + ca_names, ca_names_len, + host_name, host_name_len, + verify_result, selected_sig_alg); + break; + case TLS_protocol_tls13: + ret = tls13_cert_chain_match(cert_chain, cert_chain_len, + signature_algorithms, signature_algorithms_cnt, + signature_algorithms_cert, signature_algorithms_cert_cnt, + ca_names, ca_names_len, + oid_filters, oid_filters_len, + host_name, host_name_len, + verify_result, selected_sig_alg); + break; + default: + error_print(); + tls_cert_verify_set_result(verify_result, X509_verify_err_tls_extensions); + return -1; + } + if (ret < 0) { + error_print(); + return -1; + } + if (ret == 0) { + error_print(); + return 0; + } + + if (verify_chain) { + if (protocol == TLS_protocol_tlcp && cert_chain_type == X509_cert_chain_server) { + 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); + } else { + ret = x509_certs_verify(cert_chain, cert_chain_len, cert_chain_type, + cacerts, cacerts_len, crl, crl_len, ocsp, ocsp_len, + verify_depth, verify_result); + } + if (ret < 0) { + error_print(); + return -1; + } + if (ret == 0) { + error_print(); + return 0; + } + } + + tls_cert_verify_set_result(verify_result, X509_verify_ok); + return 1; +}