zoukankan      html  css  js  c++  java
  • TLS编程

    最近测试广州电信的电话会议平台,该平台接入采用HTTPS协议,于是有了本文。09年培训时写过一个简单的TLS C/S结构交互,采用openssl的ssl相关接口,但与生产相去胜远。本文采用openssl提供的BIO。

    长链接还是短链接?

    测试过程中发现长连接在一段时间内没有数据交互会被服务方释放,无法重新连接。根据自身业务选择。

    BIO设置为阻塞还是非阻塞?

    本场景下都为http同步请求,故设置为阻塞。代码实现时必须考虑阻塞的等待时间(测试结果是默认阻塞BIO为60s超时)对性能和业务的影响。

    读写出错控制

    如果写出错,需要校验BIO_should_retry,如果为true,需等待片刻后重新写,阻塞的BIO一般不会出现;

    如果读出错,同样要校验BIO_should_retry,非阻塞的BIO可能会影响性能。

    相关头文件:

    #include <openssl/bio.h>
    #include <openssl/ssl.h>
    #include <openssl/err.h>
    /* Initializing OpenSSL */
    SSL_library_init();
    SSL_load_error_strings();
    ERR_load_BIO_strings();
    OpenSSL_add_all_algorithms();
    
    SSL_CTX *m_ctx =SSL_CTX_new(SSLv23_client_method());
    if (m_ctx == NULL)
    {
    exit(1);
    }
    //加载pem 该pem是openssl源码库里自带的
    if(! SSL_CTX_load_verify_locations(m_ctx, "./certs/demo/ca-cert.pem", NULL))
    {
    exit(1);
    }
    

    下面四个函数封装了BIO的创建、释放、读和写,可以满足基本的需求了。

    
    BIO *
    bio_new ()
    {
      SSL *ssl;
      BIO *bio = BIO_new_ssl_connect (m_ctx);
      BIO_get_ssl (bio, &amp;
               ssl);
      if (!ssl)
        {
          BIO_free_all (bio);
          return NULL;
        }
      SSL_set_mode (ssl, SSL_MODE_AUTO_RETRY);    //自动重试
      BIO_set_conn_hostname (bio, "xxx.com:443");
      if (BIO_do_connect (bio) & lt; = 0)
        {
          BIO_free_all (bio);
          return NULL;
        }
    
    //校验失败是非致命的
      if (SSL_get_verify_result (ssl) != X509_V_OK)
        {
          /* Handle the failed verification */
        }
    
      if (BIO_do_handshake (bio) & lt; = 0)
        {                //ssl握手
          BIO_free_all (bio);
          return NULL;
        }
      return bio;
    }
    
    int
    bio_write (BIO * bio, const char *buf, int len)
    {
      if (buf == NULL)
        {
          return PROC_FAILED;
        }
      if (BIO_write (bio, buf, len) & lt; = 0)
        {
          if (!BIO_should_retry (bio))
        {
    /* Handle failed write here */
          return PROC_FAILED;
        }
    /* Do something to handle the retry */
          return PROC_FAILED;
        }
      return PROC_SUCCESS;
    }
    
    int
    bio_read (BIO * bio, char *buf, int len)
    {
      if (buf == NULL)
        {
          return PROC_FAILED;
        }
      int x = BIO_read (bio, buf, len);
      if (x == 0)
        {
    /* Handle closed connection */
          return PROC_FAILED;
        }
      else if (x & lt; 0)
        {
          if (!BIO_should_retry (bio))
        {
    /* Handle failed read here */
          return PROC_FAILED;
        }
    /* Do something to handle the retry */
          return PROC_FAILED;
        }
      return x;
    }
    
    int
    bio_close (BIO * bio)
    {
      if (bio != NULL)
        BIO_free_all (bio);
      return PROC_SUCCESS;
    }
    
    BIO * bio = bio_new ();
    if (bio == NULL)
      {
        return PROC_FAILED;
      }
    
    //发送数据
    if (bio_write (bio, buff, strlen (buff)) == PROC_FAILED)
      {
        bio_close (bio);
        return PROC_FAILED;
      }
    
    char response[8192] = { 0x00 };
    
    int len = 0;
    
    //接收数据
    
    if ((len = bio_read (bio, response, 8192)) == PROC_FAILED)
      {
        bio_close (bio);
        return PROC_FAILED;
      }
    bio_close (bio);
    
    

    参考资料:

    https://www.openssl.org/docs/crypto/BIO_f_ssl.html

    https://www.openssl.org/docs/crypto/BIO_should_retry.html

    另:BIO也很多种类型,感觉功能很强大,本人c++菜鸟,没仔细研究...

  • 相关阅读:
    如何完全删除Linux应用
    IP地址获取工具类
    日期处理工具类
    Cookies的工具类
    权限管理系统学习笔记
    SpringBoot中JPA的一些基本操作
    Mysql和Java的数据类型对应表
    MySQL中的tinyint
    幂等性浅谈
    链接
  • 原文地址:https://www.cnblogs.com/cqvoip/p/8079004.html
Copyright © 2011-2022 走看看