openssl多线程实例

摘要:
本示例用多线程实现了一个ssl服务端和一个客户端。

本示例用多线程实现了一个ssl服务端和一个客户端。

服务端代码如下:

#include <stdio.h>

#include <stdlib.h>

#include <memory.h>

#include <errno.h>

#ifndef _WIN32

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>

#include <unistd.h>

#else

#include <winsock2.h>

#include <windows.h>

#endif

#include "pthread.h"

#include <openssl/rsa.h>

#include <openssl/crypto.h>

#include <openssl/x509.h>

#include <openssl/pem.h>

#include <openssl/ssl.h>

#include <openssl/err.h>

#define CERTF "certs/sslservercert.pem"

#define KEYF "certs/sslserverkey.pem"

#define CAFILE "certs/cacert.pem"

pthread_mutex_t mlock=PTHREAD_MUTEX_INITIALIZER;

static pthread_mutex_t *lock_cs;

static long *lock_count;

#define CHK_NULL(x) if ((x)==NULL) { printf("null\n"); }

#define CHK_ERR(err,s) if ((err)==-1) { printf(" -1 \n"); }

#define CHK_SSL(err) if ((err)==-1) { printf(" -1 \n");}

#define CAFILE "certs/cacert.pem"

int verify_callback_server(int ok, X509_STORE_CTX *ctx)

{

printf("verify_callback_server \n");

return ok;

}

int SSL_CTX_use_PrivateKey_file_pass(SSL_CTX *ctx,char *filename,char *pass)

{

EVP_PKEY *pkey=NULL;

BIO *key=NULL;

key=BIO_new(BIO_s_file());

BIO_read_filename(key,filename);

pkey=PEM_read_bio_PrivateKey(key,NULL,NULL,pass);

if(pkey==NULL)

{

printf("PEM_read_bio_PrivateKey err");

return -1;

}

if (SSL_CTX_use_PrivateKey(ctx,pkey) <= 0)

{

printf("SSL_CTX_use_PrivateKey err\n");

return -1;

}

BIO_free(key);

return 1;

}

static int s_server_verify=SSL_VERIFY_NONE;

void * thread_main(void *arg)

{

SOCKET s,AcceptSocket;

WORD wVersionRequested;

WSADATA wsaData;

struct sockaddr_in service;

int err;

size_t client_len; SSL_CTX *ctx;

SSL *ssl;

X509 *client_cert;

char *str;

char buf[1024];

SSL_METHOD *meth;

ssl=(SSL *)arg;

s=SSL_get_fd(ssl);

err = SSL_accept (ssl);

if(err<0)

{

printf("ssl accerr\n");

return ;

}

printf ("SSL connection using %s\n", SSL_get_cipher (ssl));

client_cert = SSL_get_peer_certificate (ssl);

if (client_cert != NULL)

{

printf ("Client certificate:\n");

str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);

CHK_NULL(str);

printf ("\t subject: %s\n", str);

OPENSSL_free (str);

str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0);

CHK_NULL(str);

printf ("\t issuer: %s\n", str);

OPENSSL_free (str);

X509_free (client_cert);

}

else

printf ("Client does not have certificate.\n");

memset(buf,0,1024);

err = SSL_read (ssl, buf, sizeof(buf) - 1);

if(err<0)

{

printf("ssl read err\n");

closesocket(s);

return;

}

printf("get : %s\n",buf);

#if 0

buf[err] = '\0';

err = SSL_write (ssl, "I hear you.", strlen("I hear you.")); CHK_SSL(err);

#endif

SSL_free (ssl);

closesocket(s);

}

pthread_t pthreads_thread_id(void)

{

pthread_t ret;

ret=pthread_self();

return(ret);

}

void pthreads_locking_callback(int mode, int type, char *file,

int line)

{

if (mode & CRYPTO_LOCK)

{

pthread_mutex_lock(&(lock_cs[type]));

lock_count[type]++;

}

else

{

pthread_mutex_unlock(&(lock_cs[type]));

}

}

int main ()

{

int err;

int i;

SOCKET s,AcceptSocket;

WORD wVersionRequested;

WSADATA wsaData;

struct sockaddr_in service;

pthread_tpid;

size_t client_len;

SSL_CTX *ctx;

SSL *ssl;

X509 *client_cert;

char *str;

char buf[1024];

SSL_METHOD *meth;

SSL_load_error_strings();

SSLeay_add_ssl_algorithms();

meth = SSLv3_server_method();

ctx = SSL_CTX_new (meth);

if (!ctx)

{

ERR_print_errors_fp(stderr);

exit(2);

}

if ((!SSL_CTX_load_verify_locations(ctx,CAFILE,NULL)) ||

(!SSL_CTX_set_default_verify_paths(ctx)))

{

printf("err\n");

exit(1);

}

if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0)

{

ERR_print_errors_fp(stderr);

exit(3);

}

if (SSL_CTX_use_PrivateKey_file_pass(ctx, KEYF, "123456") <= 0)

{

ERR_print_errors_fp(stderr);

exit(4);

}

if (!SSL_CTX_check_private_key(ctx))

{

fprintf(stderr,"Private key does not match the certificate public key\n");

exit(5);

}

s_server_verify=SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT|

SSL_VERIFY_CLIENT_ONCE;

SSL_CTX_set_verify(ctx,s_server_verify,verify_callback_server);

SSL_CTX_set_client_CA_list(ctx,SSL_load_client_CA_file(CAFILE));

wVersionRequested = MAKEWORD( 2, 2 );

err = WSAStartup( wVersionRequested, &wsaData );

if ( err != 0 )

{

printf("err\n");

return -1;

}

s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if(s<0) return -1;

service.sin_family = AF_INET;

service.sin_addr.s_addr = inet_addr("127.0.0.1");

service.sin_port = htons(1111);

if (bind( s, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR)

{

printf("bind() failed.\n");

closesocket(s);

return -1;

}

if (listen( s, 1 ) == SOCKET_ERROR)

printf("Error listening on socket.\n");

printf("recv .....\n");

lock_cs=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));

lock_count=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));

for (i=0; i<CRYPTO_num_locks(); i++)

{

lock_count[i]=0;

pthread_mutex_init(&(lock_cs[i]),NULL);

}

CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);

CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);

while(1)

{

struct timeval tv;

fd_set fdset;

tv.tv_sec = 1;

tv.tv_usec = 0;

FD_ZERO(&fdset);

FD_SET(s, &fdset);

select(s+1, &fdset, NULL, NULL, (struct timeval *)&tv);

if(FD_ISSET(s, &fdset))

{

AcceptSocket=accept(s, NULL,NULL);

ssl = SSL_new (ctx);

CHK_NULL(ssl);

err=SSL_set_fd (ssl, AcceptSocket);

if(err>0)

{

err=pthread_create(&pid,NULL,&thread_main,(void *)ssl);

pthread_detach(pid);

}

else

continue;

}

}

SSL_CTX_free (ctx);

return 0;

}

客户端代码如下:

#include <stdio.h>

#include <memory.h>

#include <errno.h>

#ifndef _WIN32

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>

#include <unistd.h>

#else

#include <windows.h>

#endif

#include "pthread.h"

#include <openssl/crypto.h>

#include <openssl/x509.h>

#include <openssl/pem.h>

#include <openssl/ssl.h>

#include <openssl/err.h>

#define MAX_T 1000

#define CLIENTCERT "certs/sslclientcert.pem"

#define CLIENTKEY "certs/sslclientkey.pem"

#define CAFILE "certs/cacert.pem"

static pthread_mutex_t *lock_cs;

static long *lock_count;

pthread_t pthreads_thread_id(void)

{

pthread_t ret;

ret=pthread_self();

return(ret);

}

void pthreads_locking_callback(int mode, int type, char *file,

int line)

{

if (mode & CRYPTO_LOCK)

{

pthread_mutex_lock(&(lock_cs[type]));

lock_count[type]++;

}

else

{

pthread_mutex_unlock(&(lock_cs[type]));

}

}

int verify_callback(int ok, X509_STORE_CTX *ctx)

{

printf("verify_callback\n");

return ok;

}

int SSL_CTX_use_PrivateKey_file_pass(SSL_CTX *ctx,char *filename,char *pass)

{

EVP_PKEY *pkey=NULL;

BIO *key=NULL;

key=BIO_new(BIO_s_file());

BIO_read_filename(key,filename);

pkey=PEM_read_bio_PrivateKey(key,NULL,NULL,pass);

if(pkey==NULL)

{

printf("PEM_read_bio_PrivateKey err");

return -1;

}

if (SSL_CTX_use_PrivateKey(ctx,pkey) <= 0)

{

printf("SSL_CTX_use_PrivateKey err\n");

return -1;

}

BIO_free(key);

return 1;

}

void*thread_main(void *arg)

{

int err,buflen,read;

int sd;

SSL_CTX *ctx=(SSL_CTX *)arg;

struct sockaddr_in dest_sin;

SOCKET sock;

PHOSTENT phe;

WORD wVersionRequested;

WSADATA wsaData;

SSL *ssl;

X509 *server_cert;

char *str;

char buf [1024];

SSL_METHOD *meth;

FILE *fp;

wVersionRequested = MAKEWORD( 2, 2 );

err = WSAStartup( wVersionRequested, &wsaData );

if ( err != 0 )

{

printf("WSAStartup err\n");

return -1;

}

sock = socket(AF_INET, SOCK_STREAM, 0);

dest_sin.sin_family = AF_INET;

dest_sin.sin_addr.s_addr = inet_addr( "127.0.0.1" );

dest_sin.sin_port = htons( 1111 );

again:

err=connect( sock,(PSOCKADDR) &dest_sin, sizeof( dest_sin));

if(err<0)

{

Sleep(1);

goto again;

}

ssl = SSL_new (ctx);

if(ssl==NULL)

{

printf("ss new err\n");

return ;

}

SSL_set_fd(ssl,sock);

err = SSL_connect (ssl);

if(err<0)

{

printf("SSL_connect err\n");

return;

}

printf ("SSL connection using %s\n", SSL_get_cipher (ssl));

server_cert = SSL_get_peer_certificate (ssl);

printf ("Server certificate:\n");

str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0);

printf ("\t subject: %s\n", str);

OPENSSL_free (str);

str = X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0);

printf ("\t issuer: %s\n", str);

OPENSSL_free (str);

X509_free (server_cert);

err = SSL_write (ssl, "Hello World!", strlen("Hello World!"));

if(err<0)

{

printf("ssl write err\n");

return ;

}

#if 0

memset(buf,0,ONE_BUF_SIZE);

err = SSL_read (ssl, buf, sizeof(buf) - 1);

if(err<0)

{

printf("ssl read err\n");

return ;

}

buf[err] = '\0';

printf ("Got %d chars:'%s'\n", err, buf);

#endif

SSL_shutdown (ssl); /* send SSL/TLS close_notify */

SSL_free (ssl);

closesocket(sock);

}

int main ()

{

int err,buflen,read;

int sd;

struct sockaddr_in dest_sin;

SOCKETsock;

PHOSTENT phe;

WORD wVersionRequested;

WSADATA wsaData;

SSL_CTX *ctx;

SSL *ssl;

X509 *server_cert;

char *str;

char buf [1024];

SSL_METHOD *meth;

int i;

pthread_tpid[MAX_T];

SSLeay_add_ssl_algorithms();

meth = SSLv3_client_method();

SSL_load_error_strings();

ctx = SSL_CTX_new (meth);

if(ctx==NULL)

{

printf("ssl ctx new eer\n");

return -1;

}

if (SSL_CTX_use_certificate_file(ctx, CLIENTCERT, SSL_FILETYPE_PEM) <= 0)

{

ERR_print_errors_fp(stderr);

exit(3);

}

if (SSL_CTX_use_PrivateKey_file_pass(ctx, CLIENTKEY, "123456") <= 0)

{

ERR_print_errors_fp(stderr);

exit(4);

}

lock_cs=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));

lock_count=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));

for (i=0; i<CRYPTO_num_locks(); i++)

{

lock_count[i]=0;

pthread_mutex_init(&(lock_cs[i]),NULL);

}

CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);

CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);

for(i=0;i<MAX_T;i++)

{

err=pthread_create(&(pid[i]),NULL,&thread_main,(void *)ctx);

if(err!=0)

{

printf("pthread_create err\n");

continue;

}

}

for (i=0; i<MAX_T; i++)

{

pthread_join(pid[i],NULL);

}

SSL_CTX_free (ctx);

printf("test ok\n");

return 0;

}

上述程序在windows下运行成功,采用了windows下的开源pthread库。

需要注意的是,如果多线程用openssl,需要设置两个回调函数

CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);

CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);

http://www.rayfile.com/files/f3c7ef91-796c-11dd-8b74-0014221b798a/

免责声明:文章转载自《openssl多线程实例》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇中介者模式不同linux禁用nouveau驱动方法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

转载:嵌入式C语言面试题(二)

BSS段 是“Block Started by Symbol”的缩写,意为“以符号开始的块”。   BSS是Unix链接器产生的未初始化数据段。其他的段分别是包含程序代码的“text”段和包含已初始化数据的“data”段。BSS段的变量只有名称和大小却没有值。此名后来被许多文件格式使用,包括PE。“以符号开始的块”指的是编译器处理未初始化数据的地方。BS...

select模型(一 改进客户端)

一、改程序使用select来改进客户端对标准输入和套接字输入的处理,否则关闭服务器之后循环中的内容都要被gets阻塞。原程序中https://www.cnblogs.com/wsw-seu/p/8413290.html,若服务器端先关闭发送FIN,客户端处于CLOSE WAIT状态,服务端到FIN_WAIT2。由于程序阻塞在fgets,因此无法到readl...

C static静态变量使用研究

0x01隐藏 当我们同时编译多个文件时,所有未加 static 前缀的全局变量和函数都具有全局可见性。为理解这句话,我举例来说明。我们要同时编译两个源文件,一个是 a.c,另一个是 main.c。 下面是 a.c 的内容: char a = 'A'; // global variable void msg() { printf("Hello ");...

c#实现多线程代码例子

相信大家都有用过网际快车等下载资源的经历,它里面是可以设置线程数的(近年版本默认是10,曾经默认是5)。它会将文件分成与线程数相同的部分,然后每个线程下载自己的那一部分,这样下载效率就有可能提高。相信大家都有加多线程数,提升下载效率的经历。但细心的用户会发现,在带宽一定的情况下,并不是线程越多,速度越快,而是在某一点达到峰值。在C#中用多线程并不难实现。它...

《C++ Qt设计模式》 第一章 C++ 简介

第1 章 C++简介 内容: 编译相关     Qt提供了一个qmake工具,它会产生Makefile 文件。使用qmake -project 命令产生一个简单的工程文件。当执行这个命令时,qmake 会将当前工作目录下的全部源文件作为SOURCES列出来,而将全部头文件作为HEADERS 列出来     使用make 重新编译那些发生了变化的文件,或...

String和datetime在SQL中和在C#中相互转换方法总结

String和datetime之间相互转换方法总结: SQL中的转换方法: 一,将string转换为datetime,主要是使用Convert方法, 方法,Convert(datetime [ ( length ) ] , expression, [style])           如: convert(datetime,Datetime.Now,120...