如何在 C 客户端应用程序的 ClientHello 消息中添加自定义扩展?

问题描述 投票:0回答:1

我正在尝试从 C 客户端套接字程序在 ClientHello 中添加自定义扩展,该程序通过 TLSv1.3 向 Apache Web 服务器发送 HTTP 请求。我尝试从 OpenSSL 调用

SSL_CTX_add_custom_ext()
函数来添加随机扩展类型 65280,但不确定如何正确定义
add_cb
回调。文档(https://www.openssl.org/docs/manmaster/man3/SSL_CTX_add_custom_ext.html)说将
out 
设置为扩展数据,将
outlen 
设置为扩展数据长度并返回1,我尝试过(很可能是错误的)。扩展数据只是一个字符串,“testing”。

使用wireshark,在握手协议下可以看到一个未知的扩展类型65280,但长度为0,数据显示缺失,如下图。我如何正确添加自定义扩展,以便它与wireshark中的数据一起显示。

下面是我的客户端 C 代码,它通过 TLSv1.3 向 Apache Web 服务器发送 HTTP 请求:

#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");
    unsigned char data[] = "testing";
    unsigned char *pdata = &data;
    size_t len = strlen(data) + 1;
    out = (const unsigned char **)&pdata;
    outlen = &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");
        return -1;
    }

    // ssl write HTTP request
    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));

    // ssl read HTTP response
    char buf[1024] = {0};
    bytes = SSL_read(ssl, buf, sizeof(buf) - 1);
    buf[bytes] = '\0';
    printf("Received: %s\n", buf);


    // closing the connected socket
    SSL_free(ssl);
    close(sockfd);
    SSL_CTX_free(ctx);
    return 0;
}

c ssl openssl network-programming handshake
1个回答
1
投票

我设法解决了这个问题。问题确实在于我的扩展回调

add_cb()
定义。需要调用
OPENSSL_malloc()
来分配内存并返回指向所分配内存的指针。该指针应设置为
unsigned char *
指针变量,然后数据可以分配到内存。

下面是在

add_cb()
回调中设置扩展数据的简单示例。

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)
{
    unsigned char *p_data = NULL;
    p_data = OPENSSL_malloc(sizeof(*p_data));
    if (p_data == NULL) {
        return 0;
    }
    *p_data = 1;
    *out = p_data;
    *outlen = sizeof(*p_data);
    return 1;
}
© www.soinside.com 2019 - 2024. All rights reserved.