• 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/

  • 相关阅读:
    swagger2 Could not resolve pointer: /definitions
    mybatis-plus使用Oracle函数生成主键
    WebLogic安装及部署
    windows下用bat启动jar包,修改cmd标题(title)
    Windows下修改Tomcat黑窗口标题
    jar包注册为Linux服务
    Redis我想入门——数据类型
    Redis我想入门——启动
    JAVA8给我带了什么——Optional和CompletableFuture
    JAVA8给我带了什么——并行流和接口新功能
  • 原文地址:https://www.cnblogs.com/ahuo/p/1282753.html
Copyright © 2020-2023  润新知