`

openssl多线程实例

 
阅读更多

本示例用多线程实现了一个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);

分享到:
评论

相关推荐

    openssl 结合 IOCP的例子

    在IT领域,网络通信是核心部分之一,而高效、安全的网络通信往往依赖于底层的协议和编程模型。本文将详细解析"openssl 结合 IOCP的例子",...同时,这也是一种很好的学习多线程编程、网络编程以及加密技术的实践案例。

    OPENSSL源码.rar

    同时,OpenSSL还支持多线程,可以充分利用多核处理器的优势。 9. **API设计**:OpenSSL提供了一组丰富的应用程序接口(API),供开发者在自己的应用中集成加密和安全功能。理解和使用这些API是开发安全软件的基础。...

    Openssl编程指导手册

    - **多线程安全**:在多线程环境下正确使用OpenSSL,避免数据竞争和上下文污染。 10. **编程实例** - **客户端实现**:创建一个简单的SSL/TLS客户端,连接到服务器并进行安全通信。 - **服务器实现**:构建一个...

    windowsOpenssl1.0.2和1.1.0

    2. **性能提升**:OpenSSL 1.1.0 在多个方面进行了优化,比如内存管理、多线程支持和算法性能,这使得新版本在处理加密和解密任务时可能更快。 3. **TLS 协议支持**:1.1.0 版本增加了对较新 TLS 版本的支持,如 ...

    openssl-1.1.1p

    公共和私有DRBG实例每线程锁定自由操作 (3)支持各种新的加密算法 SHA3,SHA512 / 224,SHA512 / 256 EdDSA(包括Ed25519和Ed448) X448(添加到1.1.0中的现有X25519支持) 多素数RSA SM2,SM3,SM4 SipHash...

    linux下用C写的基于SSL 的TCP例子代码!

    具体的实现细节可能因实际需求而略有不同,例如添加错误处理代码、实现多线程支持等。在实际项目中,你可能还需要处理如证书链、客户端认证、异步I/O等更复杂的情况。通过阅读OpenSSL的文档和示例代码,你可以深入...

    iocp开发一个最简单的例子

    在Windows操作系统中,I/O完成端口(I/O Completion Ports,简称IOCP)是一种高效的多线程I/O模型,尤其适用于处理大量的并发I/O请求。本篇文章将通过一个最简单的IOCP示例,深入探讨其工作原理和使用方法。 首先,...

    C++ Builder网络开发实例

    C++ Builder支持原生的C++多线程,以及VCL提供的TThread类,简化了多线程应用的开发。 通过深入学习以上知识点,并结合"C++ Builder网络开发实例"中的具体代码示例,开发者可以迅速掌握C++ Builder进行网络编程的...

    CURL多线程使用http代理访问WS/WSS-易语言

    "例子.e"、"curl.e"和"append.e"是易语言的源代码文件,其中包含了实现CURL多线程访问的示例代码。"多线程式时钟1.1.ec"可能是用于多线程同步和控制的易语言组件,而"append.ec"可能是扩展类库,提供了一些易语言...

    cpp-httplib:仅C ++标头的HTTPHTTPS服务器和客户端库

    注意:这是一个多线程的“阻止” HTTP库。 如果您正在寻找“非阻塞”库,那么这不是您想要的。简单的例子服务器# define CPPHTTPLIB_OPENSSL_SUPPORT# include " path/to/httplib.h "// HTTPhttplib::Server svr;//...

    一些VC++网络编程实例源代码

    5. **多线程**:网络编程往往需要处理多个并发连接,因此源码可能包含多线程编程的例子,每个线程对应一个客户端连接。 6. **错误处理**:任何网络程序都需要处理各种可能出现的错误,例如连接失败、超时、数据传输...

    CppSQLite + sqlcipher + sqlite_3.33.0实现数据库加密

    `CppSQLiteDemoMT`可能是一个多线程的演示程序,展示了如何在多线程环境中使用`CppSQLite`库。在多线程应用中,数据库访问的并发控制是必须考虑的问题,`CppSQLiteDemoMT`可能包含了解决这些问题的示例代码。 `...

    MFC网络聊天程序

    在这个“MFC网络聊天程序”中,开发者利用MFC的特性实现了一个功能丰富的聊天应用,其中包含了多线程、socket通信以及文件操作等关键技术。 一、MFC与用户界面设计 在MFC中,我们可以利用对话框(Dialog)类来创建...

    Apache+MySQL+PHP 配置过程

    在这个例子中,使用的是httpd-2.2.21-win32-x86-openssl-0.9.8r.msi。安装过程中,你可以自定义配置,如Network Domain、ServerName和Administrator’s Email Address,这些信息主要是为了服务器识别和管理,但对...

    Visual C++网络程序设计实例详解

    4. 多线程编程:在Windows网络编程中,多线程常常被用于处理并发连接,提高服务器性能。VC++提供了一套完整的多线程支持,包括CreateThread()函数创建线程,以及互斥量(mutex)、事件对象(event)等同步机制。 5....

    《VC++网络通信编程实例案例精选》光盘源代码 第二部分

    2. **多线程编程**:在网络编程中,为了处理多个并发连接,通常会使用多线程技术。VC++的`&lt;thread&gt;`库可以帮助创建和管理线程,提高程序的并发能力。 3. **异步I/O**:使用异步I/O可以在等待网络操作完成的同时执行...

    VC++网络通信编程实例

    4. **多线程编程**:在网络编程中,多线程技术常常用来处理并发连接,提高系统效率。VC++提供了丰富的多线程支持,包括创建线程、同步线程操作(如互斥量、信号量和事件对象)等。 5. **异步I/O**:为了解决阻塞I/O...

    基于TCP/IP的Linux文件传输系统

    基于Tcp/IP的Linux文件传输系统,分为服务器和客户端模块...系统中涉及到多线程,线程同步,线程池,网络通信,协议设计等知识,是本人和其他极为兄弟一起完成的练习作品,也是一个不错的学习例子,分享给大家一起学习

    ssl客户端和服务端代码vc6

    总之,"ssl客户端和服务端代码vc6"是一个用于学习和实践SSL通信的实例,它可以帮助开发者掌握在老版本的Visual Studio环境下使用SSL的基本技巧,这对于那些仍然需要维护旧系统或者对低级网络编程感兴趣的开发者来说...

    android调用jni实例

    此外,NDK还支持更复杂的功能,如多线程、OpenSSL、OpenCV等库的集成,使得开发者能够充分利用C++的性能优势来优化Android应用的关键部分。不过,需要注意的是,过度依赖本地代码可能会增加应用的复杂性和体积,因此...

Global site tag (gtag.js) - Google Analytics