openssl_1.1.1_perl_dump.txt
我们正在尝试升级Openssl版本1.1.1,安全层从TLS 1.2升级到TLS 1.3。
我们的代码库执行SSL握手,然后使用send & read/recv函数传输数据。* 注意-它在TLS 1.2中运行良好。但是,当我们切换到TLS 1.3时,send & read/recv无法接收数据包,但仅在使用SSL_write和SSL_read时才能正常工作。
下面我们试着制作一个服务器和客户端程序的例子,在成功的SSL连接后,我们使用send & read/recv函数,在这里它也适用于TLS 1.2,但是在TLS 1.3的情况下,收到的数据包会有延迟,服务器的第一个响应是空白的,请参考下面的输出configdata.pm。使用本参考文章https://help.ubuntu.com/community/OpenSSL中提到的步骤创建SSL证书。
server.c
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "/usr/include/openssl/ssl.h"
#include "/usr/include/openssl/crypto.h"
#include "/usr/include/openssl/err.h"
#define FAIL -1
int OpenListener(int port)
{ int sd;
struct sockaddr_in addr;
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
perror("can't bind port");
abort();
}
if ( listen(sd, 10) != 0 )
{
perror("Can't configure listening port");
abort();
}
return sd;
}
int isRoot()
{
if (getuid() != 0)
{
return 0;
}
else
{
return 1;
}
}
SSL_CTX* InitServerCTX(void)
{ SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
SSL_load_error_strings(); /* load all error messages */
char *imethod=getenv("TLS_METHOD");
if(imethod!=NULL && strncmp(imethod, "1.3", 3)==0){
printf("\nSetting TLS1.3 method\n");
fflush(stdout);
method = TLS_server_method(); /* create new server-method instance */
}
else{
printf("\nSetting TLS1.2 method\n");
fflush(stdout);
method = TLSv1_2_server_method(); /* create new server-method instance */
}
ctx = SSL_CTX_new(method); /* create new context from method */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
if(imethod!=NULL && strncmp(imethod, "1.3", 3)==0)
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
SSL_CTX_load_verify_locations(ctx, "01.pem", "/home/qarun/aparopka/myCA/signedcerts");
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
//New lines - Force the client-side have a certificate
/*SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL);
SSL_CTX_set_verify_depth(ctx, 2);*/
//End new lines
}
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
if ( cert != NULL )
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
printf("No certificates.\n");
}
void Servlet(SSL* ssl) /* Serve the connection -- threadable */
{ char buf[1024];
char reply[1024];
int sd, bytes;
const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";
sd = SSL_get_fd(ssl); /* get socket connection */
printf("\nsd: <%d>", sd);
if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
else
{
/*if(SSL_do_handshake(ssl) <= 0){
printf("\n SSL_do_handshake failed....\n");
}*/
ShowCerts(ssl); /* get any certificates */
do{
//bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
//bytes = read(sd, buf, sizeof(buf));
bytes = recv(sd, buf, sizeof(buf), 0);
if ( bytes > 0 )
{
buf[bytes] = 0;
printf("Client msg: \"%s\"\n", buf);
sprintf(reply, HTMLecho, buf); /* construct reply */
//SSL_write(ssl, reply, strlen(reply)); /* send reply */
send(sd, reply, strlen(reply), 0); // MSG_NOSIGNAL | MSG_DONTWAIT); //MSG_CONFIRM);
}
else
ERR_print_errors_fp(stderr);
}while(bytes>0);
}
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
}
int main(int count, char *strings[])
{ SSL_CTX *ctx;
int server;
char *portnum;
if(!isRoot())
{
printf("This program must be run as root/sudo user!!");
//exit(0);
}
if ( count != 2 )
{
printf("Usage: %s <portnum>\n", strings[0]);
exit(0);
}
SSL_library_init();
portnum = strings[1];
ctx = InitServerCTX(); /* initialize SSL */
LoadCertificates(ctx, "/home/qarun/aparopka/myCA/server_crt.pem", "/home/qarun/aparopka/myCA/server_key.pem"); /* load certs */
server = OpenListener(atoi(portnum)); /* create server socket */
while (1)
{ struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL *ssl;
int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */
printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, client); /* set connection socket to SSL state */
Servlet(ssl); /* service connection */
}
close(server); /* close server socket */
SSL_CTX_free(ctx); /* release context */
}
client.c
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define FAIL -1
//Added the LoadCertificates how in the server-side makes.
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_chain_file(ctx, CertFile ) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
}
int OpenConnection(const char *hostname, int port)
{ int sd;
struct hostent *host;
struct sockaddr_in addr;
if ( (host = gethostbyname(hostname)) == NULL )
{
perror(hostname);
abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
close(sd);
perror(hostname);
abort();
}
return sd;
}
SSL_CTX* InitCTX(void)
{ SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
SSL_load_error_strings(); /* Bring in and register error messages */
char *imethod=getenv("TLS_METHOD");
if(imethod!=NULL && strncmp(imethod, "1.3", 3)==0){
printf("\nSetting TLS1.3 method\n");
fflush(stdout);
method = TLS_client_method(); /* create new server-method instance */
}
else{
printf("\nSetting TLS1.2 method\n");
fflush(stdout);
method = TLSv1_2_client_method(); /* create new server-method instance */
}
ctx = SSL_CTX_new(method); /* Create new context */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
if(imethod!=NULL && strncmp(imethod, "1.3", 3)==0)
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
return ctx;
}
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
if ( cert != NULL )
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line); /* free the malloc'ed string */
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line); /* free the malloc'ed string */
X509_free(cert); /* free the malloc'ed certificate copy */
}
else
printf("Info: No client certificates configured.\n");
}
int main(int count, char *strings[])
{ SSL_CTX *ctx;
int server;
SSL *ssl;
char buf[1024];
int bytes;
char *hostname, *portnum;
if ( count != 3 )
{
printf("usage: %s <hostname> <portnum>\n", strings[0]);
exit(0);
}
SSL_library_init();
hostname=strings[1];
portnum=strings[2];
ctx = InitCTX();
LoadCertificates(ctx, "/home/qarun/aparopka/myCA/server_crt.pem", "/home/qarun/aparopka/myCA/server_key.pem");
server = OpenConnection(hostname, atoi(portnum));
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
int sd = SSL_get_fd(ssl);
int flip=1;
printf("\nsd: <%d>", sd);
if ( SSL_connect(ssl) == FAIL ) /* perform the connection */
ERR_print_errors_fp(stderr);
else
{ //char *msg = "Hello???";
if(SSL_do_handshake(ssl) <= 0){
printf("\n client SSL_do_handshake failed....\n");
}
char msg[1024];
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
ShowCerts(ssl); /* get any certs */
while(1){
bzero(msg, 1024);
bzero(buf, 1024);
printf("\nEnter message: ");
fgets(msg, 1024, stdin);
//SSL_write(ssl, msg, strlen(msg)); /* encrypt & send message */
send(sd, msg, strlen(msg), 0); //MSG_NOSIGNAL | MSG_DONTWAIT); //MSG_CONFIRM);
//bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
//bytes = read(sd, buf, sizeof(buf));
bytes = recv(sd, buf, sizeof(buf), 0);
/* read again for TLS 1.3 only for first time */
/*char *imethod=getenv("TLS_METHOD");
if(imethod!=NULL && strncmp(imethod, "1.3", 3)==0
&& flip){
bytes = read(sd, buf, sizeof(buf));
flip=0;
}*/
buf[bytes] = 0;
printf("Received: \"%s\"\n", buf);
}
SSL_free(ssl); /* release connection state */
}
close(server); /* close socket */
SSL_CTX_free(ctx); /* release context */
return 0;
}
TLS 1.2的服务器和客户端输出
**$ ./ssl_server_working 2023**
Setting TLS1.2 method
Connection: 10.250.14.23:41152
sd: <4>No certificates.
Client msg: "first
"
Client msg: "second
"
Client msg: "third
"
**./ssl_client_working 10.250.14.23 2023**
Setting TLS1.2 method
sd: <3>Connected with ECDHE-RSA-AES256-GCM-SHA384 encryption
Server certificates:
Subject: /CN=MyOwn Root Certificate Authority/ST=CA/C=US/emailAddress=amit.paropkari@quest.com/O=SharePlex/OU=IT Department
Issuer: /CN=MyOwn Root Certificate Authority/ST=CA/C=US/emailAddress=amit.paropkari@quest.com/O=SharePlex/OU=IT Department
Enter message: first
Received: "<html><body><pre>first
</pre></body></html>
"
Enter message: second
Received: "<html><body><pre>second
</pre></body></html>
"
Enter message: third
Received: "<html><body><pre>third
</pre></body></html>
"
TLS 1.3的服务器和客户端输出:请注意,第一个客户端请求的响应为空,它将在第二个请求的下一个响应中接收。
export TLS_METHOD=1.3
**./ssl_server_working 2024**
Setting TLS1.3 method
Connection: 10.250.14.23:34012
sd: <4>No certificates.
Client msg: "first
"
Client msg: "second
"
Client msg: "third
"
**./ssl_client_working 10.250.14.23 2024**
Setting TLS1.3 method
sd: <3>Connected with TLS_AES_256_GCM_SHA384 encryption
Server certificates:
Subject: /CN=MyOwn Root Certificate Authority/ST=CA/C=US/emailAddress=amit.paropkari@quest.com/O=SharePlex/OU=IT Department
Issuer: /CN=MyOwn Root Certificate Authority/ST=CA/C=US/emailAddress=amit.paropkari@quest.com/O=SharePlex/OU=IT Department
Enter message: first
Received: ""
Enter message: second
Received: "<html><body><pre>first
</pre></body></html>
"
Enter message: third
Received: "<html><body><pre>second
</pre></body></html>
"
1条答案
按热度按时间nxagd54h1#
我们得到了这个问题的答案。原来TLS 1.3增加了一个握手步骤,在服务器完成消息之后,客户端再次发送服务器完成消息,服务器验证它,并发送握手后协议级别的消息,称为'NewSessionTicket消息'。我们可以在启动SSL服务器之前,使用SSL_CTX_set_num_tickets方法禁用它。
对于担心这样做不安全的人来说,在我们的需求中,我们只需要初始的安全认证,然后我们进行会话隧道。在此之后,如果我们对每个事务使用SSL_write SSL_read(这些事务的数量和时间都很大),加密解密步骤将降低性能。因此,我们使用send & recv发送数据。