SSL 多线程通信 linux openSSL C API编程

一、环境

需要提前准备好服务端和客户端的证书和私钥,以及CA的证书。

OpenSSL 1.1.1f  31 Mar 2020
built on: Wed Nov 24 13:20:48 2021 UTC
platform: debian-amd64
options:  bn(64,64) rc4(16x,int) des(int) blowfish(ptr)

Thread model: posix
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
 

二、实现

2.1 简要步骤

SSL客户端和服务端的实现流程大体一致,只是在多线程处理时不一样,服务器端多了线程管理,从而保证线程安全。

客户端:

SSL_library_init();
OpenSSL_add_all_algorithms(); 
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_load_error_strings();                  
ctx = SSL_CTX_new(SSLv23_client_method()); 
SSL_CTX_use_certificate_file();
SSL_CTX_use_PrivateKey_file();
SSL_CTX_check_private_key(ctx);
SSL_CTX_load_verify_locations();
server = connect_server(ADDR, PORT);
ssl    = SSL_new(ctx);
SSL_set_fd(ssl, server); 
SSL_connect(ssl);
SSL_write(ssl, req, strlen(req));
SSL_free(ssl);
close(server); 
SSL_CTX_free(ctx);

服务端:

SSL_library_init();
OpenSSL_add_all_algorithms(); 
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_load_error_strings();                  
ctx = SSL_CTX_new(SSLv23_client_method()); 
SSL_CTX_use_certificate_file();
SSL_CTX_use_PrivateKey_file();
SSL_CTX_check_private_key(ctx);
SSL_CTX_load_verify_locations();
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); /* verify client cert */
SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(CA_CERT));
server = port_listen(PORT); /* create server socket */
ssl    = SSL_new(ctx);
SSL_set_fd(ssl, server); 
SSL_accept(ssl);
SSL_write(ssl, req, strlen(req));
SSL_read(ssl, buf, sizeof(buf) - 1);
SSL_free(ssl);
close(server); 
SSL_CTX_free(ctx);

2.1 客户端实现

OpenSSL 1.1.1f版本的ssl接口是支持多线程的,因此直接使用pthread编程即可。

以下源码,ssl读写是两个线程,客户端不验证服务端的证书,增加了失败重连机制。

#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>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/bio.h>
#include <stdbool.h>
#include <signal.h> /* sigaction */
#define FAIL                -1
#define PORT                7383
#define SSL_RETRY_DELAY_SEC 300
#define ADDR                "127.0.0.1"
#define CA_CERT             "./cert/ca.crt"
#define CLIENT_CA           "./cert/cert.crt"
#define CLIENT_KEY          "./cert/pri.pem"static bool isServerDisconnect = true;
int connect_server(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* init_ctx(void)
{SSL_CTX* ctx;OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */ERR_load_BIO_strings();ERR_load_crypto_strings();SSL_load_error_strings();                  /* Bring in and register error messages */ctx = SSL_CTX_new(SSLv23_client_method()); /* Create new context *///ctx = SSL_CTX_new(TLSv1_client_method()); /* Create new context */if (ctx == NULL) {ERR_print_errors_fp(stderr);abort();}return ctx;
}
void show_cert_file(const char* certFile)
{BIO* certBio = NULL;X509* cert   = NULL;char* line;//create BIO object to read certificatecertBio = BIO_new(BIO_s_file());//Read certificate into BIOif (!(BIO_read_filename(certBio, certFile))) {printf("reading certificate error in %s\r\n", certFile);BIO_free_all(certBio);exit(EXIT_FAILURE);}if (!(cert = PEM_read_bio_X509(certBio, NULL, 0, NULL))) {fprintf(stderr, "loading certificate error in %s\r\n", certFile);BIO_free_all(certBio);exit(EXIT_FAILURE);}line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);printf("%s\n", line);free(line);      /* free the malloc'ed string */X509_free(cert); /* free the malloc'ed certificate copy */BIO_free_all(certBio);
}
void load_cert_key_ca_file(SSL_CTX* ctx, const char* certFile, const char* keyFile, const char* caFile)
{if (!ctx) {abort();}// load certif (certFile && SSL_CTX_use_certificate_file(ctx, certFile, SSL_FILETYPE_PEM) <= 0) {ERR_print_errors_fp(stderr);abort();}// load private keyif (keyFile && SSL_CTX_use_PrivateKey_file(ctx, keyFile, SSL_FILETYPE_PEM) <= 0) {ERR_print_errors_fp(stderr);abort();}// check private keyif (certFile && keyFile && !SSL_CTX_check_private_key(ctx)) {ERR_print_errors_fp(stderr);abort();}// load ca fileif (caFile && !SSL_CTX_load_verify_locations(ctx, caFile, 0)) {ERR_print_errors_fp(stderr);abort();}return;
}/*! signal handling variables */
volatile bool exit_sig = false;
volatile bool quit_sig = false;
void sig_handler(int sigio)
{if (sigio == SIGQUIT) {quit_sig = true;} else if ((sigio == SIGINT) || (sigio == SIGTERM)) {exit_sig = true;}return;
}
void thread_recv(void* arg)
{char buf[1024];int err;SSL* ssl = (SSL*)arg;while (1) {memset(buf, 0, 1024);err = SSL_read(ssl, buf, sizeof(buf) - 1);if (err < 0) {printf("SSL read error\r\n");} else if (err == 0) {printf("SSL disconnect\r\n");isServerDisconnect = true;return;}printf("SSL recv: %s\r\n", buf);}
}
int main(int count, char* strings[])
{SSL_CTX* ctx;int server;SSL* ssl;char buf[1024];pthread_t pid;int retryTimeSec;struct sigaction sigact;sigemptyset(&sigact.sa_mask);sigact.sa_flags   = 0;sigact.sa_handler = sig_handler;sigaction(SIGQUIT, &sigact, NULL); /* Ctrl-\ */sigaction(SIGINT, &sigact, NULL);  /* Ctrl-C 8*/sigaction(SIGTERM, &sigact, NULL); /* default "kill" command */sigaction(SIGPIPE, &sigact, NULL); /* ignore  SIGPIPE */SSL_library_init();ctx = init_ctx();//SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); /* if need verify server cert */load_cert_key_ca_file(ctx, CLIENT_CA, CLIENT_KEY, CA_CERT);show_cert_file(CLIENT_CA);RETRY:server = connect_server(ADDR, PORT);ssl    = SSL_new(ctx);   /* create new SSL connection state */SSL_set_fd(ssl, server); /* attach the socket descriptor */if (SSL_connect(ssl) == FAIL) { /* perform the connection */printf("SSL handshake error, rerey timeout %ds\r\n", SSL_RETRY_DELAY_SEC);close(server); /* close socket */retryTimeSec = SSL_RETRY_DELAY_SEC;while (retryTimeSec--) {if (!quit_sig && !exit_sig) {SSL_CTX_free(ctx); /* release context */printf("exit client\r\n");}sleep(1);}goto RETRY;} else {printf("SSL handshake success\r\n");const char* req = "jackwang client request";printf("connected with %s encryption\n", SSL_get_cipher(ssl));isServerDisconnect = false;pthread_create(&pid, NULL, (void* (*)(void*))thread_recv, (void*)ssl);while (!quit_sig && !exit_sig && !isServerDisconnect) {/* get any certs */memset(buf, 0, 1024);SSL_write(ssl, req, strlen(req)); /* encrypt & send message */sleep(1);}SSL_free(ssl); /* release connection state */}pthread_cancel(pid);pthread_join(pid, NULL);close(server);     /* close socket */SSL_CTX_free(ctx); /* release context */printf("exit client\r\n");return 0;
}

2.2 服务端

服务端主要多了线程管理和证书校验。以下贴出主程序和线程代码。

void thread_main(void* arg)
{char buf[1024];int clientPort;char clientAddr[PEER_IP_LENGTH];SSL* ssl    = (SSL*)arg;int sock_fd = SSL_get_fd(ssl);int err     = SSL_accept(ssl);clientPort  = getpeer_information(sock_fd, clientAddr);if (err < 0) {printf("%s:%d SSL handshake error\r\n", clientAddr, clientPort);close(sock_fd);SSL_free(ssl);pthread_exit((void*)-1);} else {printf("%s:%d SSL handshake success\r\n", clientAddr, clientPort);threadpool_add_one(pthread_self(), ssl);//printf("total client num:%d\r\n", threadpool_num());}printf("%s:%d SSL connection using %s\n", clientAddr, clientPort, SSL_get_cipher(ssl));show_cert_ssl(ssl);while (1) {memset(buf, 0, 1024);err = SSL_read(ssl, buf, sizeof(buf) - 1);if (err < 0) {printf("%s:%d SSL read error\r\n", clientAddr, clientPort);goto FINISH;} else if (err == 0) {printf("%s:%d SSL disconnect\r\n", clientAddr, clientPort);goto FINISH;}printf("%s:%d SSL recv: %s\n", clientAddr, clientPort, buf);}FINISH:threadpool_remove_one(pthread_self(), ssl);
}int main(int count, char* Argc[])
{SSL_CTX* ctx;int server;pthread_t pid;int ret;//Only root user have the permsion to run the serverif (!is_root()) {printf("This program must be run as root/sudo user!!\r\n");exit(0);}struct sigaction sigact;sigemptyset(&sigact.sa_mask);sigact.sa_flags   = 0;sigact.sa_handler = sig_handler;sigaction(SIGQUIT, &sigact, NULL); /* Ctrl-\ */sigaction(SIGINT, &sigact, NULL);  /* Ctrl-C 8*/sigaction(SIGTERM, &sigact, NULL); /* default "kill" command */sigaction(SIGPIPE, &sigact, NULL); /* ignore  SIGPIPE */threadpool_init(); /* init threadpool */// Initialize the SSL librarySSL_library_init();ctx = init_ctx(); /* initialize SSL */load_cert_key_ca_file(ctx, SERVER_CA, SERVER_KEY, CA_CERT);SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); /* verify client cert */SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(CA_CERT));server = port_listen(PORT); /* create server socket */printf("server listening (%d)\r\n", PORT);while (!sigQuit && !sigExit) {struct sockaddr_in addr;socklen_t len = sizeof(addr);SSL* ssl;int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */if (client > 0) {                                           //printf("connection: %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));ssl = SSL_new(ctx);                                     /* get new SSL state with context */ret = SSL_set_fd(ssl, client);                          /* set connection socket to SSL state */if (ret > 0) {pthread_create(&pid, NULL, (void* (*)(void*))thread_main, (void*)ssl);} else {continue;}}}threadpool_remove_all();close(server);     /* close server socket */SSL_CTX_free(ctx); /* release context */ERR_free_strings();
}

三、编译

客户端:gcc -Wall -o client ssl_client.c -L/usr/lib -lssl -lcrypto -lpthread

服务端:gcc -Wall -o server ssl_server.c -L/usr/lib -lssl -lcrypto -lpthread

若没有ssl和crypto库,则需要安装:apt-get install libssl-dev

 四、公开代码仓库

EiRi_jackmaster/pthread_ssl

等空了维护。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/404571.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分享一个CSS3和jQuery实现的模糊显示效果 - 帮助你的访问用户更好的阅读内容

为什么80%的码农都做不了架构师&#xff1f;>>> 日期&#xff1a;2011/12/20 来源&#xff1a;GBin1.com 在线演示 本地下载 这 个教程将实现一个页面部分内容突出显示效果&#xff0c; 大家可能经常见到一些页面组成内容比较多&#xff0c;可能会分散用户的…

Cracked me --1--Acid_burn

结合ida和od结合效果最好。 打开程序&#xff0c;首先是一个nag窗口&#xff08;去除nag&#xff09; 常用方法&#xff0c;一寻找字符串&#xff0c;发现和以往的 不同&#xff0c;不是对话框句柄的形式。只能第二种方法&#xff0c;单步找到对话框出现的位置。0042fd97-->…

QT 开发openSSL CSR证书请求工具

1、环境 QT 5.15.2 MinGW8.1.0 64Bit OpenSSL 1.1.1f 31 Mar 2020 built on: Wed Nov 24 13:20:48 2021 UTC platform: debian-amd64 options: bn(64,64) rc4(16x,int) des(int) blowfish(ptr) 本机的OpenSSL是随QT安装的。 2、QT使用openSSL 2.1 项目文件添加以下依赖 …

2012网页设计趋势(下)

CSS3 技术 不确定你可以利用CSS3吗&#xff1f;再想想。网络先锋如Andy Clarke 和 Jeremy Keith一直提倡网页设计要“逐步加强”。逐步增强是指在网站设计师时要兼顾到旧版浏览器的可用性&#xff0c;而“增强”则是针对喜欢最新技术的用户。在这样的设计阵营&#xff0c;你利用…

树莓派CM4 装系统和换源

一、系统下载 官网&#xff1a;Operating system images – Raspberry Pi 最新的版本删除了默认账号pi。考虑以前的使用习惯&#xff0c;此处下载以前的buster debian版本。CM4是arm64架构&#xff0c;根据板子的配置容量不同可选相应的版本&#xff0c;我这里选择lite版本。…

C++沉思录

C沉思录 第五章 代理类 : 为了实现容器或数组的多态性。 1 #include <iostream> 2 3 using namespace std; 4 5 class Vehicle 6 { 7 public: 8 virtual void start() const 0 ; 9 virtual Vehicle* copy() const 0 ;10 virtual ~Vehicle() {};11 };12 1…

VC内存泄露检查工具:VisualLeakDetector

From: http://www.xdowns.com/article/170/Article_3060.html 初识Visual Leak Detector 灵活自由是C/C语言的一大特色&#xff0c;而这也为C/C程序员出了一个难题。当程序越来越复杂时&#xff0c;内存的管理也会变得越加复杂&#xff0c;稍有不慎就会出现内存问题。内…

JQuery Easy Ui 可装载组合框 - ComboBox

JQuery Easy Ui 可装载组合框 - ComboBox 可装载组合框 - ComboBox 继承自$.fn.combo.defaults,通过$.fn.combobox.defaults覆盖默认值 combobox显示的是一个可以编辑的文本框和一个下拉列表.允许用户从里面选择一个或者是多个值,用户可以直接输入值到列表顶部,或者可以从列表选…

用SQL实现统计报表中的“小计”和“合计”

客户提出需求&#xff0c;针对某一列分组加上小计&#xff0c;合计汇总。网上找了一些有关SQL加合计的语句。都不是很理想。决定自己动手写。 思路有三个&#xff1a; 1.很多用GROUPPING和ROLLUP来实现。 优点实现代码简洁&#xff0c;要求对GROUPPING和ROLLUP很深的理解。 …

Linux串口驱动程序-termios结构体中的VTIME和VMIN应用

#Linux串口驱动程序-termios结构体中的VTIME和VMIN应用 参考 https://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html 最近在看Unix-linux系统编程一书&#xff0c;做到第六章的时候需要做一个标准输入的超时处理。如下图所示 需要改动的&#xff0c;是原书的play_aga…

C# 线程手册 第一章 线程定义 .NET 和 C# 对线程的支持

由于.NET Framework 支持自由线程&#xff0c;所以自由线程在所有.NET 语言中都存在&#xff0c;包括C#和VB.NET. 在下一部分&#xff0c;我们将着重关注如何提供这种支持以及更多关于线程是如何做到的&#xff0c;而不再关注线程是什么。我们将讨论一些能够进一步帮助区分进程…

前端第一天 HTML基础

前端第一天 HTML基础 1.是什么 HTML里值得记住的就几个点&#xff0c;第一&#xff0c;这东西还有自身也有结构 这东西是个超文本&#xff0c;可以挂载文字图片视频或者别的超文本自身可以通过各种各样的tag进行标记&#xff0c;排版给浏览器提供渲染的依据&#xff0c; 2.…

view2.0移植自定义图标,带颜色修改

1.下载你的iconfont项目 1.将图标添加到项目&#xff0c;修改font-family值 2.下载项目打包文件&#xff0c;解压后如图所示 我们只关心里面的iconfont.css和iconfont.json 我们在这个文件夹&#xff0c;新建一个convert.js,内容如下 //convert.js let path1 "./iconf…

H3C——路由策略和策略路由实例配置

配置如下&#xff1a;[IP]int s0/2/0[IP-Serial0/2/0]ip add 202.112.1.10 28[IP-Serial0/2/0]int s0/2/1[IP-Serial0/2/1]ip add 61.67.1.10 28 [IP-Serial0/2/1]int lo0[IP-LoopBack0]ip add 10.10.10.10 32[IP]ip route-static 0.0.0.0 0 202.112.1.9 指条静态缺省路由到R1 …

功能:人脉(People Hub)7-固定到“开始”屏幕

如果是您的亲人和密友&#xff0c;再或者是领导和重要客户。 您需要经常沟通&#xff0c;可以将他的联系人头像固定在开始屏幕上&#xff0c;方便您的沟通。方法&#xff1a;很简单&#xff0c;“长按该联系人”后&#xff0c;有菜单出现&#xff0c;选择弹出菜单中的“固定到‘…

《OEA - 实体扩展属性系统 - 设计方案说明书》

这篇设计文档是 12 月份写来参加公司的研发峰会的&#xff0c;自己倒是信心满满&#xff0c;不过最后还是没有入围。现在想想也没啥大用&#xff0c;所以贴出来&#xff0c;期待与园友交流。 文档有点长&#xff0c;没全部贴在博客中&#xff0c;有兴趣的可以下载附件中的 PDF。…

Amazon S3 设置对象的生命周期Lifecycle

2019独角兽企业重金招聘Python工程师标准>>> 保存在S3上面的文件&#xff0c;有些是长期保存的&#xff0c;而有一些我们却不希望保存太久&#xff0c;过一段时间后就可以删除了。例如备份文件&#xff0c;太旧的就要删除&#xff1b;又或如日志文件&#xff0c;只保…

Direct3D提高篇:HLSL编程实现PhotoShop滤镜效果 - 伪 HDR/Blow

所谓HDR就是高动态范围的意思。在普通的显示器和位图里&#xff0c;每通道都是8-bit&#xff0c;也就是说RGB分量的范围都是0-255&#xff0c;这用来表示现实中的颜色显然是远远不够的。现实中的图像的动态范围远远大的多&#xff0c;那么如何在现有的显示设备里尽可能的保持更…

Oracle Buffer Cache的keep、recycle、default pool概念图解

Oracle Buffer Cache的keep、recycle、default pool概念图解 转载于:https://blog.51cto.com/maclean/1278284

程序中调用命令行命令,不显示那个黑黑的DOS窗口

From: http://hi.baidu.com/yanqiuge/item/5da466c3d3f18453ad00ef1d 在程序中使用命令行时&#xff0c;会有黑黑的DOS窗口&#xff0c;很不爽&#xff0c;在网上查了一下&#xff0c;写一个有点实用价值的小程序&#xff1a; /****************************** 文件名&#…