From b48f2c3772e399e1258120dc53be6b6ef3173630 Mon Sep 17 00:00:00 2001 From: Zhi Guan Date: Wed, 10 Jun 2026 23:44:31 +0800 Subject: [PATCH] Update TLS SCT --- include/gmssl/sct.h | 20 --------------- include/gmssl/tls.h | 11 ++++++++- src/tls13.c | 26 ++++++++++++++++++-- src/tls_sct.c | 60 ++++++++++++++++++++++++++++++++------------- 4 files changed, 77 insertions(+), 40 deletions(-) diff --git a/include/gmssl/sct.h b/include/gmssl/sct.h index 8401e359..365eba33 100644 --- a/include/gmssl/sct.h +++ b/include/gmssl/sct.h @@ -24,21 +24,6 @@ extern "C" { #endif -/* -Certificate Transparency (RFC 6962) uses TLS-style presentation language for -Signed Certificate Timestamp (SCT) objects. When SCTs are carried in an X.509 -or OCSP extension, the extension value is an ASN.1 OCTET STRING whose contents -are the TLS-serialized SignedCertificateTimestampList. - -id-ct OBJECT IDENTIFIER ::= { 1 3 6 1 4 1 11129 2 4 } - -id-ct-precertificate-scts OBJECT IDENTIFIER ::= { id-ct 2 } - -ExtnValue contents ::= - SignedCertificateTimestampList -*/ - - enum { SCT_version_v1 = 0, }; @@ -139,11 +124,6 @@ int signed_certificate_timestamp_verify(const uint8_t *sct, size_t sct_len, X509_KEY *key, const DIGEST *digest); -/* -在验证sct_list的时候,我们需要提供一组公钥的信息,包括X509_KEY, Key_hash, URL , description 这三个是最重要的了 -*/ - - typedef struct { X509_KEY log_key; uint8_t log_id[32]; diff --git a/include/gmssl/tls.h b/include/gmssl/tls.h index fd3d4914..2dfb7fed 100644 --- a/include/gmssl/tls.h +++ b/include/gmssl/tls.h @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef __cplusplus @@ -843,6 +844,9 @@ typedef struct { int signed_certificate_timestamp; uint8_t signed_certificate_timestamp_lists[512]; // list of uint16array size_t signed_certificate_timestamp_lists_len; + const CT_LOG_INFO *ct_logs; + size_t ct_logs_cnt; + size_t ct_at_least; // 35. session_ticket // session_ticket only supported in tls12 @@ -1878,11 +1882,16 @@ int tls_process_signature_algorithms(const uint8_t *ext_data, size_t ext_datalen // signed_certificate_timestamp response is set by tls_ctx_add_certificate_list_and_key() int tls_ctx_enable_signed_certificate_timestamp(TLS_CTX *ctx, int enable); // 这里enable的是什么?是否请求吗? int tls_enable_signed_certificate_timestamp(TLS_CONNECT *conn, int enable); +int tls_ctx_set_ct_logs(TLS_CTX *ctx, const CT_LOG_INFO *ct_logs, + size_t ct_logs_cnt, size_t at_least); // 客户端需要一组SCT服务器的公钥列表才能够去验证SCT,我们假定这个公钥列表在CTX中 -int tls13_signed_certificate_timestamp_verify(const uint8_t *sct_list, size_t sct_list_len); +int tls13_signed_certificate_timestamp_verify(const uint8_t *sct_list, size_t sct_list_len, + int entry_type, const uint8_t issuer_key_hash[SCT_ISSUER_KEY_HASH_SIZE], + const uint8_t *entry, size_t entry_len, + const CT_LOG_INFO *ct_logs, size_t ct_logs_cnt, size_t at_least); int tls_signed_certificate_timestamp_entry_to_bytes(const uint8_t key_id[32], uint64_t timestamp, const uint8_t *signature, size_t signature_len, diff --git a/src/tls13.c b/src/tls13.c index 87765ec9..cf1f8a98 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -5881,6 +5881,8 @@ int tls13_recv_server_certificate(TLS_CONNECT *conn) size_t leaf_status_request_ocsp_response_len; const uint8_t *leaf_signed_certificate_timestamp; size_t leaf_signed_certificate_timestamp_len; + const uint8_t *cert; + size_t certlen; const int *signature_algorithms_cert = NULL; size_t signature_algorithms_cert_cnt = 0; @@ -5996,9 +5998,18 @@ int tls13_recv_server_certificate(TLS_CONNECT *conn) } // signed_certificate_timestamp if (leaf_signed_certificate_timestamp) { + if (x509_certs_get_cert_by_index(conn->peer_cert_chain, + conn->peer_cert_chain_len, 0, &cert, &certlen) != 1) { + error_print(); + tls13_send_alert(conn, TLS_alert_bad_certificate); + return -1; + } if (tls13_signed_certificate_timestamp_verify( leaf_signed_certificate_timestamp, - leaf_signed_certificate_timestamp_len) != 1) { + leaf_signed_certificate_timestamp_len, + SCT_log_entry_type_x509_entry, NULL, cert, certlen, + conn->ctx->ct_logs, conn->ctx->ct_logs_cnt, + conn->ctx->ct_at_least) != 1) { error_print(); tls13_send_alert(conn, TLS_alert_bad_certificate); return -1; @@ -8215,6 +8226,8 @@ int tls13_recv_client_certificate(TLS_CONNECT *conn) size_t status_request_ocsp_response_len; const uint8_t *signed_certificate_timestamp = NULL; size_t signed_certificate_timestamp_len; + const uint8_t *cert; + size_t certlen; const int *signature_algorithms_cert = NULL; size_t signature_algorithms_cert_cnt = 0; @@ -8333,8 +8346,17 @@ int tls13_recv_client_certificate(TLS_CONNECT *conn) } // signed_certificate_timestamp if (signed_certificate_timestamp) { + if (x509_certs_get_cert_by_index(conn->peer_cert_chain, + conn->peer_cert_chain_len, 0, &cert, &certlen) != 1) { + error_print(); + tls13_send_alert(conn, TLS_alert_bad_certificate); + return -1; + } if (tls13_signed_certificate_timestamp_verify( - signed_certificate_timestamp, signed_certificate_timestamp_len) != 1) { + signed_certificate_timestamp, signed_certificate_timestamp_len, + SCT_log_entry_type_x509_entry, NULL, cert, certlen, + conn->ctx->ct_logs, conn->ctx->ct_logs_cnt, + conn->ctx->ct_at_least) != 1) { error_print(); tls13_send_alert(conn, TLS_alert_bad_certificate); return -1; diff --git a/src/tls_sct.c b/src/tls_sct.c index 232101d9..394fd656 100644 --- a/src/tls_sct.c +++ b/src/tls_sct.c @@ -22,6 +22,7 @@ #include #include #include +#include /* @@ -38,8 +39,10 @@ Certificate.certificate_list.CertificateEntry.exts.signed_certificate_timestamp uint64 timestamp; opaque signature<0..2^16-1>; } SignedCertificateTimestamp; + // SignedCertificateTimestamp 的格式不对 */ +/* int tls_signed_certificate_timestamp_entry_to_bytes(const uint8_t key_id[32], uint64_t timestamp, const uint8_t *signature, size_t signature_len, uint8_t **out, size_t *outlen) @@ -71,6 +74,7 @@ int tls_signed_certificate_timestamp_entry_from_bytes(const uint8_t **key_id, } return 1; } +*/ int tls_signed_certificate_timestamp_ext_to_bytes(const uint8_t *sct_list, size_t sct_list_len, uint8_t **out, size_t *outlen) @@ -101,8 +105,14 @@ int tls_signed_certificate_timestamp_print(FILE *fp, int fmt, int ind, const uin { const uint8_t *sct_list; size_t sct_list_len; + size_t i = 0; - if (tls_uint16array_from_bytes(&sct_list, &sct_list_len, &d, &dlen) != 1) { + if (!fp || !d) { + error_print(); + return -1; + } + if (tls_uint16array_from_bytes(&sct_list, &sct_list_len, &d, &dlen) != 1 + || dlen) { error_print(); return -1; } @@ -113,24 +123,18 @@ int tls_signed_certificate_timestamp_print(FILE *fp, int fmt, int ind, const uin format_print(fp, fmt, ind, "(null)\n"); } while (sct_list_len) { - const uint8_t *key_id; - uint64_t timestamp; - const uint8_t *signature; - size_t signature_len; - int entry_ind = ind + 4; + const uint8_t *sct; + size_t sct_len; + char label[64]; - format_print(fp, fmt, ind, "SignedCertificateTimestamp\n"); - - if (tls_array_from_bytes(&key_id, 32, &sct_list, &sct_list_len) != 1 - || tls_uint64_from_bytes(×tamp, &sct_list, &sct_list_len) != 1 - || tls_uint16array_from_bytes(&signature, &signature_len, &sct_list, &sct_list_len) != 1) { + if (tls_uint16array_from_bytes(&sct, &sct_len, + &sct_list, &sct_list_len) != 1) { error_print(); return -1; } - format_bytes(fp, fmt, entry_ind, "key_id", key_id, 32); - format_print(fp, fmt, entry_ind, "timestamp: %"PRIu64"\n", timestamp); - format_bytes(fp, fmt, entry_ind, "signature", signature, signature_len); - if (dlen) { + snprintf(label, sizeof(label), "SignedCertificateTimestamp[%zu]", i++); + if (signed_certificate_timestamp_print(fp, fmt, ind, label, + sct, sct_len) != 1) { error_print(); return -1; } @@ -158,8 +162,30 @@ int tls_ctx_enable_signed_certificate_timestamp(TLS_CTX *ctx, int enable) return 1; } -int tls13_signed_certificate_timestamp_verify(const uint8_t *sct_list, size_t sct_list_len) +int tls_ctx_set_ct_logs(TLS_CTX *ctx, const CT_LOG_INFO *ct_logs, + size_t ct_logs_cnt, size_t at_least) { - error_print(); + if (!ctx || (ct_logs_cnt && !ct_logs) || at_least > ct_logs_cnt) { + error_print(); + return -1; + } + ctx->ct_logs = ct_logs; + ctx->ct_logs_cnt = ct_logs_cnt; + ctx->ct_at_least = at_least; return 1; } + +int tls13_signed_certificate_timestamp_verify(const uint8_t *sct_list, size_t sct_list_len, + int entry_type, const uint8_t issuer_key_hash[SCT_ISSUER_KEY_HASH_SIZE], + const uint8_t *entry, size_t entry_len, + const CT_LOG_INFO *ct_logs, size_t ct_logs_cnt, size_t at_least) +{ + if (!ct_logs_cnt) { + return 1; + } + if (!at_least) { + at_least = 1; + } + return sct_list_verify(sct_list, sct_list_len, entry_type, + issuer_key_hash, entry, entry_len, ct_logs, ct_logs_cnt, at_least); +}