如何在C客户端的ClientHello消息中添加自定义TLS扩展?
TLS ClientHello自定义扩展数据缺失问题解决
问题根源
你的ext_add_cb回调存在两个致命错误:
- 用栈上局部变量存储扩展数据,回调结束后内存被回收,OpenSSL无法读取有效内容
- 错误地直接修改
out和outlen指针本身,而非通过指针赋值传递数据地址和长度
修正后的完整代码
#include <arpa/inet.h> #include <stdio.h> #include <string.h> #include <sys/socket.h> #include <unistd.h> #include "openssl/ssl.h" #include "openssl/err.h" SSL_CTX* InitCTX(void) { const SSL_METHOD *method; SSL_CTX *ctx; OpenSSL_add_all_algorithms(); SSL_load_error_strings(); method = TLS_client_method(); ctx = SSL_CTX_new(method); if (ctx == NULL) { ERR_print_errors_fp(stderr); abort(); } return ctx; } static int ext_add_cb(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char **out, size_t *outlen, X509 *x, size_t chainidx, int *al, void *add_arg) { printf("in ext_add_cb\n"); const char *ext_data = "testing"; size_t data_len = strlen(ext_data); // 分配堆内存,确保回调结束后数据有效 unsigned char *data_buf = OPENSSL_malloc(data_len); if (!data_buf) { *al = SSL_AD_INTERNAL_ERROR; return 0; } memcpy(data_buf, ext_data, data_len); // 正确传递数据:修改指针指向的内容 *out = data_buf; *outlen = data_len; return 1; } static void ext_free_cb(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char *out, void *add_arg) { printf("in ext_free_cb\n"); OPENSSL_free((unsigned char *)out); } static int ext_parse_cb(SSL *s, unsigned int ext_type, unsigned int context, const unsigned char *in, size_t inlen, X509 *x, size_t chainidx, int *al, void *parse_arg) { printf("in ext_parse_cb\n"); return 1; } int main() { struct sockaddr_in servaddr; char *host = "127.0.0.1"; char *port = "443"; int sockfd = 0; SSL_CTX * ctx = NULL; SSL * ssl = NULL; servaddr.sin_family = AF_INET; servaddr.sin_port = htons(atoi(port)); servaddr.sin_addr.s_addr = inet_addr(host); if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("socket error \n"); return -1; } if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { printf("connection failed \n"); return -1; } SSL_library_init(); OpenSSL_add_all_algorithms(); SSL_load_error_strings(); ctx = InitCTX(); int status = SSL_CTX_add_custom_ext(ctx, 65280, SSL_EXT_CLIENT_HELLO, ext_add_cb, ext_free_cb, NULL, ext_parse_cb, NULL); if (status != 1) { printf("SSL_CTX_add_custom_ext() failed\n"); } ssl = SSL_new(ctx); SSL_set_fd(ssl, sockfd); if (SSL_connect(ssl) == -1) { printf("SSL_connect() failed\n"); ERR_print_errors_fp(stderr); return -1; } char msg[] = "GET / HTTP/1.1\r\nHost: 127.0.0.1\r\nAccept: */*\r\n\r\n"; int bytes = SSL_write(ssl, msg, strlen(msg)); char buf[1024] = {0}; bytes = SSL_read(ssl, buf, sizeof(buf) - 1); buf[bytes] = '\0'; printf("Received: %s\n", buf); SSL_free(ssl); close(sockfd); SSL_CTX_free(ctx); return 0; }
核心修改点
- 内存管理:使用
OPENSSL_malloc分配堆内存存储扩展数据,避免栈内存回收问题 - 指针操作:通过
*out和*outlen赋值,将数据地址和长度传递给OpenSSL,而非修改指针变量本身 - 数据长度:移除不必要的字符串结束符,仅传递实际有效数据长度
- 调试增强:增加
SSL_connect失败时的错误打印,便于排查问题
内容的提问来源于stack exchange,提问作者Resolved
相关产品推荐
相关产品推荐

