zoukankan      html  css  js  c++  java
  • 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);

     

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

  • 相关阅读:
    基本技能训练之线程
    关于UEditor的使用配置(图片上传配置)
    PAT 乙级练习题1002. 写出这个数 (20)
    codeforces 682C Alyona and the Tree DFS
    codeforces 681D Gifts by the List dfs+构造
    codeforces 678E Another Sith Tournament 概率dp
    codeforces 680E Bear and Square Grid 巧妙暴力
    codeforces 678D Iterated Linear Function 矩阵快速幂
    codeforces 679A Bear and Prime 100 交互
    XTUOJ 1248 TC or CF 搜索
  • 原文地址:https://www.cnblogs.com/ahuo/p/1282753.html
Copyright © 2011-2022 走看看