【发布时间】:2021-06-13 22:29:55
【问题描述】:
我正在尝试使用 openssl api 在个人项目中实现 JA3 方法(TLS 指纹识别方法)。为此,我需要获取有关 Client Hello 数据包的一些信息,并且我正在尝试使用 openssl api https://www.openssl.org/docs/man1.1.1/man3/ 来做到这一点。首先,我下载了一个代码,该代码在我的计算机和网站之间建立了 TLS 连接,并检索了证书信息。该程序运行良好,tls 连接使用 TLS 1.3,并且证书信息正常。然后我尝试检索 Client Hello 数据包以开始实现 JA3 方法。经过几次研究,我发现了许多可以让我获得所需信息的功能:https://www.openssl.org/docs/man1.1.1/man3/SSL_client_hello_cb_fn.html。所有这些函数只能在客户端 hello 回调函数上调用。由于 SSL_CTX_set_client_hello_cb 函数,可以调用此函数。但就我而言,我的函数永远不会被调用。我开始绝望了,这就是为什么我需要你的帮助。我确实搜索了很多来调试它,但我没有找到可以允许回调函数或类似功能的标志。这是程序:
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
int create_socket(char[], BIO *);
int callback(SSL *s, int *al, void *arg)
{
int * number = arg;
*number = (*number) + 1;
printf("\nWe are in the callback function !\n");
return SSL_CLIENT_HELLO_SUCCESS;
}
int main() {
char dest_url[] = "https://www.hp.com";
BIO *certbio = NULL;
BIO *outbio = NULL;
X509 *cert = NULL;
X509_NAME *certname = NULL;
const SSL_METHOD *method;
SSL_CTX *ctx;
struct ssl_st *ssl;
int server = 0;
OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_load_error_strings();
certbio = BIO_new(BIO_s_file());
outbio = BIO_new_fp(stdout, BIO_NOCLOSE);
if(SSL_library_init() < 0)
BIO_printf(outbio, "Could not initialize the OpenSSL library !\n");
method = TLS_client_method();
if ( (ctx = SSL_CTX_new(method)) == NULL)
BIO_printf(outbio, "Unable to create a new SSL context structure.\n");
int hope = 12;
SSL_CTX_set_client_hello_cb(ctx, &callback, (void *)&hope);
ssl = SSL_new(ctx);
server = create_socket(dest_url, outbio);
if(server != 0)
BIO_printf(outbio, "Successfully made the TCP connection to: %s.\n", dest_url);
SSL_set_fd(ssl, server);
if ( SSL_connect(ssl) != 1 )
BIO_printf(outbio, "Error: Could not build a SSL session to: %s.\n", dest_url);
else
BIO_printf(outbio, "Successfully enabled SSL/TLS session to: %s.\n", dest_url);
cert = SSL_get_peer_certificate(ssl);
if (cert == NULL)
BIO_printf(outbio, "Error: Could not get a certificate from: %s.\n", dest_url);
else
BIO_printf(outbio, "Retrieved the server's certificate from: %s.\n", dest_url);
certname = X509_NAME_new();
certname = X509_get_subject_name(cert);
BIO_printf(outbio, "Displaying the certificate subject data:\n");
X509_NAME_print_ex(outbio, certname, 0, 0);
BIO_printf(outbio, "\n");
SSL_free(ssl);
close(server);
X509_free(cert);
SSL_CTX_free(ctx);
BIO_printf(outbio, "Finished SSL/TLS connection with server: %s.\n", dest_url);
printf("Hope value : %d \n", hope);
return(0);
}
int create_socket(char url_str[], BIO *out) {
int sockfd;
char hostname[256] = "";
char portnum[6] = "443";
char proto[6] = "";
char *tmp_ptr = NULL;
int port;
struct hostent *host;
struct sockaddr_in dest_addr;
if(url_str[strlen(url_str)] == '/')
url_str[strlen(url_str)] = '\0';
strncpy(proto, url_str, (strchr(url_str, ':')-url_str));
strncpy(hostname, strstr(url_str, "://")+3, sizeof(hostname));
if(strchr(hostname, ':')) {
tmp_ptr = strchr(hostname, ':');
/* the last : starts the port number, if avail, i.e. 8443 */
strncpy(portnum, tmp_ptr+1, sizeof(portnum));
*tmp_ptr = '\0';
}
port = atoi(portnum);
if ( (host = gethostbyname(hostname)) == NULL ) {
BIO_printf(out, "Error: Cannot resolve hostname %s.\n", hostname);
abort();
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
dest_addr.sin_family=AF_INET;
dest_addr.sin_port=htons(port);
dest_addr.sin_addr.s_addr = *(long*)(host->h_addr);
memset(&(dest_addr.sin_zero), '\0', 8);
tmp_ptr = inet_ntoa(dest_addr.sin_addr);
if ( connect(sockfd, (struct sockaddr *) &dest_addr,
sizeof(struct sockaddr)) == -1 ) {
BIO_printf(out, "Error: Cannot connect to host %s [%s] on port %d.\n",
hostname, tmp_ptr, port);
}
return sockfd;
}
我正在等待您的答复,谢谢。
【问题讨论】: