TLS1.3上的网络数据包读取问题|Openssl C语言程序

xuo3flqw  于 2022-11-14  发布在  其他
关注(0)|答案(1)|浏览(247)

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

  1. #include <errno.h>
  2. #include <unistd.h>
  3. #include <malloc.h>
  4. #include <string.h>
  5. #include <arpa/inet.h>
  6. #include <sys/socket.h>
  7. #include <sys/types.h>
  8. #include <netinet/in.h>
  9. #include <resolv.h>
  10. #include "/usr/include/openssl/ssl.h"
  11. #include "/usr/include/openssl/crypto.h"
  12. #include "/usr/include/openssl/err.h"
  13. #define FAIL -1
  14. int OpenListener(int port)
  15. { int sd;
  16. struct sockaddr_in addr;
  17. sd = socket(PF_INET, SOCK_STREAM, 0);
  18. bzero(&addr, sizeof(addr));
  19. addr.sin_family = AF_INET;
  20. addr.sin_port = htons(port);
  21. addr.sin_addr.s_addr = INADDR_ANY;
  22. if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
  23. {
  24. perror("can't bind port");
  25. abort();
  26. }
  27. if ( listen(sd, 10) != 0 )
  28. {
  29. perror("Can't configure listening port");
  30. abort();
  31. }
  32. return sd;
  33. }
  34. int isRoot()
  35. {
  36. if (getuid() != 0)
  37. {
  38. return 0;
  39. }
  40. else
  41. {
  42. return 1;
  43. }
  44. }
  45. SSL_CTX* InitServerCTX(void)
  46. { SSL_METHOD *method;
  47. SSL_CTX *ctx;
  48. OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
  49. SSL_load_error_strings(); /* load all error messages */
  50. char *imethod=getenv("TLS_METHOD");
  51. if(imethod!=NULL && strncmp(imethod, "1.3", 3)==0){
  52. printf("\nSetting TLS1.3 method\n");
  53. fflush(stdout);
  54. method = TLS_server_method(); /* create new server-method instance */
  55. }
  56. else{
  57. printf("\nSetting TLS1.2 method\n");
  58. fflush(stdout);
  59. method = TLSv1_2_server_method(); /* create new server-method instance */
  60. }
  61. ctx = SSL_CTX_new(method); /* create new context from method */
  62. if ( ctx == NULL )
  63. {
  64. ERR_print_errors_fp(stderr);
  65. abort();
  66. }
  67. if(imethod!=NULL && strncmp(imethod, "1.3", 3)==0)
  68. 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);
  69. return ctx;
  70. }
  71. void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
  72. {
  73. SSL_CTX_load_verify_locations(ctx, "01.pem", "/home/qarun/aparopka/myCA/signedcerts");
  74. /* set the local certificate from CertFile */
  75. if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
  76. {
  77. ERR_print_errors_fp(stderr);
  78. abort();
  79. }
  80. /* set the private key from KeyFile (may be the same as CertFile) */
  81. if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
  82. {
  83. ERR_print_errors_fp(stderr);
  84. abort();
  85. }
  86. /* verify private key */
  87. if ( !SSL_CTX_check_private_key(ctx) )
  88. {
  89. fprintf(stderr, "Private key does not match the public certificate\n");
  90. abort();
  91. }
  92. //New lines - Force the client-side have a certificate
  93. /*SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL);
  94. SSL_CTX_set_verify_depth(ctx, 2);*/
  95. //End new lines
  96. }
  97. void ShowCerts(SSL* ssl)
  98. { X509 *cert;
  99. char *line;
  100. cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
  101. if ( cert != NULL )
  102. {
  103. printf("Server certificates:\n");
  104. line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
  105. printf("Subject: %s\n", line);
  106. free(line);
  107. line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
  108. printf("Issuer: %s\n", line);
  109. free(line);
  110. X509_free(cert);
  111. }
  112. else
  113. printf("No certificates.\n");
  114. }
  115. void Servlet(SSL* ssl) /* Serve the connection -- threadable */
  116. { char buf[1024];
  117. char reply[1024];
  118. int sd, bytes;
  119. const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";
  120. sd = SSL_get_fd(ssl); /* get socket connection */
  121. printf("\nsd: <%d>", sd);
  122. if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */
  123. ERR_print_errors_fp(stderr);
  124. else
  125. {
  126. /*if(SSL_do_handshake(ssl) <= 0){
  127. printf("\n SSL_do_handshake failed....\n");
  128. }*/
  129. ShowCerts(ssl); /* get any certificates */
  130. do{
  131. //bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
  132. //bytes = read(sd, buf, sizeof(buf));
  133. bytes = recv(sd, buf, sizeof(buf), 0);
  134. if ( bytes > 0 )
  135. {
  136. buf[bytes] = 0;
  137. printf("Client msg: \"%s\"\n", buf);
  138. sprintf(reply, HTMLecho, buf); /* construct reply */
  139. //SSL_write(ssl, reply, strlen(reply)); /* send reply */
  140. send(sd, reply, strlen(reply), 0); // MSG_NOSIGNAL | MSG_DONTWAIT); //MSG_CONFIRM);
  141. }
  142. else
  143. ERR_print_errors_fp(stderr);
  144. }while(bytes>0);
  145. }
  146. SSL_free(ssl); /* release SSL state */
  147. close(sd); /* close connection */
  148. }
  149. int main(int count, char *strings[])
  150. { SSL_CTX *ctx;
  151. int server;
  152. char *portnum;
  153. if(!isRoot())
  154. {
  155. printf("This program must be run as root/sudo user!!");
  156. //exit(0);
  157. }
  158. if ( count != 2 )
  159. {
  160. printf("Usage: %s <portnum>\n", strings[0]);
  161. exit(0);
  162. }
  163. SSL_library_init();
  164. portnum = strings[1];
  165. ctx = InitServerCTX(); /* initialize SSL */
  166. LoadCertificates(ctx, "/home/qarun/aparopka/myCA/server_crt.pem", "/home/qarun/aparopka/myCA/server_key.pem"); /* load certs */
  167. server = OpenListener(atoi(portnum)); /* create server socket */
  168. while (1)
  169. { struct sockaddr_in addr;
  170. socklen_t len = sizeof(addr);
  171. SSL *ssl;
  172. int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */
  173. printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
  174. ssl = SSL_new(ctx); /* get new SSL state with context */
  175. SSL_set_fd(ssl, client); /* set connection socket to SSL state */
  176. Servlet(ssl); /* service connection */
  177. }
  178. close(server); /* close server socket */
  179. SSL_CTX_free(ctx); /* release context */
  180. }

client.c

  1. #include <stdio.h>
  2. #include <errno.h>
  3. #include <unistd.h>
  4. #include <malloc.h>
  5. #include <string.h>
  6. #include <sys/socket.h>
  7. #include <resolv.h>
  8. #include <netdb.h>
  9. #include <openssl/ssl.h>
  10. #include <openssl/err.h>
  11. #define FAIL -1
  12. //Added the LoadCertificates how in the server-side makes.
  13. void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
  14. {
  15. /* set the local certificate from CertFile */
  16. if ( SSL_CTX_use_certificate_chain_file(ctx, CertFile ) <= 0 )
  17. {
  18. ERR_print_errors_fp(stderr);
  19. abort();
  20. }
  21. /* set the private key from KeyFile (may be the same as CertFile) */
  22. if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
  23. {
  24. ERR_print_errors_fp(stderr);
  25. abort();
  26. }
  27. /* verify private key */
  28. if ( !SSL_CTX_check_private_key(ctx) )
  29. {
  30. fprintf(stderr, "Private key does not match the public certificate\n");
  31. abort();
  32. }
  33. }
  34. int OpenConnection(const char *hostname, int port)
  35. { int sd;
  36. struct hostent *host;
  37. struct sockaddr_in addr;
  38. if ( (host = gethostbyname(hostname)) == NULL )
  39. {
  40. perror(hostname);
  41. abort();
  42. }
  43. sd = socket(PF_INET, SOCK_STREAM, 0);
  44. bzero(&addr, sizeof(addr));
  45. addr.sin_family = AF_INET;
  46. addr.sin_port = htons(port);
  47. addr.sin_addr.s_addr = *(long*)(host->h_addr);
  48. if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
  49. {
  50. close(sd);
  51. perror(hostname);
  52. abort();
  53. }
  54. return sd;
  55. }
  56. SSL_CTX* InitCTX(void)
  57. { SSL_METHOD *method;
  58. SSL_CTX *ctx;
  59. OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
  60. SSL_load_error_strings(); /* Bring in and register error messages */
  61. char *imethod=getenv("TLS_METHOD");
  62. if(imethod!=NULL && strncmp(imethod, "1.3", 3)==0){
  63. printf("\nSetting TLS1.3 method\n");
  64. fflush(stdout);
  65. method = TLS_client_method(); /* create new server-method instance */
  66. }
  67. else{
  68. printf("\nSetting TLS1.2 method\n");
  69. fflush(stdout);
  70. method = TLSv1_2_client_method(); /* create new server-method instance */
  71. }
  72. ctx = SSL_CTX_new(method); /* Create new context */
  73. if ( ctx == NULL )
  74. {
  75. ERR_print_errors_fp(stderr);
  76. abort();
  77. }
  78. if(imethod!=NULL && strncmp(imethod, "1.3", 3)==0)
  79. 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);
  80. return ctx;
  81. }
  82. void ShowCerts(SSL* ssl)
  83. { X509 *cert;
  84. char *line;
  85. cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
  86. if ( cert != NULL )
  87. {
  88. printf("Server certificates:\n");
  89. line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
  90. printf("Subject: %s\n", line);
  91. free(line); /* free the malloc'ed string */
  92. line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
  93. printf("Issuer: %s\n", line);
  94. free(line); /* free the malloc'ed string */
  95. X509_free(cert); /* free the malloc'ed certificate copy */
  96. }
  97. else
  98. printf("Info: No client certificates configured.\n");
  99. }
  100. int main(int count, char *strings[])
  101. { SSL_CTX *ctx;
  102. int server;
  103. SSL *ssl;
  104. char buf[1024];
  105. int bytes;
  106. char *hostname, *portnum;
  107. if ( count != 3 )
  108. {
  109. printf("usage: %s <hostname> <portnum>\n", strings[0]);
  110. exit(0);
  111. }
  112. SSL_library_init();
  113. hostname=strings[1];
  114. portnum=strings[2];
  115. ctx = InitCTX();
  116. LoadCertificates(ctx, "/home/qarun/aparopka/myCA/server_crt.pem", "/home/qarun/aparopka/myCA/server_key.pem");
  117. server = OpenConnection(hostname, atoi(portnum));
  118. ssl = SSL_new(ctx); /* create new SSL connection state */
  119. SSL_set_fd(ssl, server); /* attach the socket descriptor */
  120. int sd = SSL_get_fd(ssl);
  121. int flip=1;
  122. printf("\nsd: <%d>", sd);
  123. if ( SSL_connect(ssl) == FAIL ) /* perform the connection */
  124. ERR_print_errors_fp(stderr);
  125. else
  126. { //char *msg = "Hello???";
  127. if(SSL_do_handshake(ssl) <= 0){
  128. printf("\n client SSL_do_handshake failed....\n");
  129. }
  130. char msg[1024];
  131. printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
  132. ShowCerts(ssl); /* get any certs */
  133. while(1){
  134. bzero(msg, 1024);
  135. bzero(buf, 1024);
  136. printf("\nEnter message: ");
  137. fgets(msg, 1024, stdin);
  138. //SSL_write(ssl, msg, strlen(msg)); /* encrypt & send message */
  139. send(sd, msg, strlen(msg), 0); //MSG_NOSIGNAL | MSG_DONTWAIT); //MSG_CONFIRM);
  140. //bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
  141. //bytes = read(sd, buf, sizeof(buf));
  142. bytes = recv(sd, buf, sizeof(buf), 0);
  143. /* read again for TLS 1.3 only for first time */
  144. /*char *imethod=getenv("TLS_METHOD");
  145. if(imethod!=NULL && strncmp(imethod, "1.3", 3)==0
  146. && flip){
  147. bytes = read(sd, buf, sizeof(buf));
  148. flip=0;
  149. }*/
  150. buf[bytes] = 0;
  151. printf("Received: \"%s\"\n", buf);
  152. }
  153. SSL_free(ssl); /* release connection state */
  154. }
  155. close(server); /* close socket */
  156. SSL_CTX_free(ctx); /* release context */
  157. return 0;
  158. }

TLS 1.2的服务器和客户端输出

  1. **$ ./ssl_server_working 2023**
  2. Setting TLS1.2 method
  3. Connection: 10.250.14.23:41152
  4. sd: <4>No certificates.
  5. Client msg: "first
  6. "
  7. Client msg: "second
  8. "
  9. Client msg: "third
  10. "
  11. **./ssl_client_working 10.250.14.23 2023**
  12. Setting TLS1.2 method
  13. sd: <3>Connected with ECDHE-RSA-AES256-GCM-SHA384 encryption
  14. Server certificates:
  15. Subject: /CN=MyOwn Root Certificate Authority/ST=CA/C=US/emailAddress=amit.paropkari@quest.com/O=SharePlex/OU=IT Department
  16. Issuer: /CN=MyOwn Root Certificate Authority/ST=CA/C=US/emailAddress=amit.paropkari@quest.com/O=SharePlex/OU=IT Department
  17. Enter message: first
  18. Received: "<html><body><pre>first
  19. </pre></body></html>
  20. "
  21. Enter message: second
  22. Received: "<html><body><pre>second
  23. </pre></body></html>
  24. "
  25. Enter message: third
  26. Received: "<html><body><pre>third
  27. </pre></body></html>
  28. "

TLS 1.3的服务器和客户端输出:请注意,第一个客户端请求的响应为空,它将在第二个请求的下一个响应中接收。

  1. export TLS_METHOD=1.3
  2. **./ssl_server_working 2024**
  3. Setting TLS1.3 method
  4. Connection: 10.250.14.23:34012
  5. sd: <4>No certificates.
  6. Client msg: "first
  7. "
  8. Client msg: "second
  9. "
  10. Client msg: "third
  11. "
  12. **./ssl_client_working 10.250.14.23 2024**
  13. Setting TLS1.3 method
  14. sd: <3>Connected with TLS_AES_256_GCM_SHA384 encryption
  15. Server certificates:
  16. Subject: /CN=MyOwn Root Certificate Authority/ST=CA/C=US/emailAddress=amit.paropkari@quest.com/O=SharePlex/OU=IT Department
  17. Issuer: /CN=MyOwn Root Certificate Authority/ST=CA/C=US/emailAddress=amit.paropkari@quest.com/O=SharePlex/OU=IT Department
  18. Enter message: first
  19. Received: ""
  20. Enter message: second
  21. Received: "<html><body><pre>first
  22. </pre></body></html>
  23. "
  24. Enter message: third
  25. Received: "<html><body><pre>second
  26. </pre></body></html>
  27. "
nxagd54h

nxagd54h1#

我们得到了这个问题的答案。原来TLS 1.3增加了一个握手步骤,在服务器完成消息之后,客户端再次发送服务器完成消息,服务器验证它,并发送握手后协议级别的消息,称为'NewSessionTicket消息'。我们可以在启动SSL服务器之前,使用SSL_CTX_set_num_tickets方法禁用它。

  1. SSL_set_num_tickets(ssl, 0); /* Disable post-handshake token */
  2. sd = SSL_get_fd(ssl); /* get socket connection */
  3. if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */
  4. ERR_print_errors_fp(stderr);

对于担心这样做不安全的人来说,在我们的需求中,我们只需要初始的安全认证,然后我们进行会话隧道。在此之后,如果我们对每个事务使用SSL_write SSL_read(这些事务的数量和时间都很大),加密解密步骤将降低性能。因此,我们使用send & recv发送数据。

相关问题