zoukankan      html  css  js  c++  java
  • C++ windows客户端支持SSL双向认证

       C++ windows客户端支持SSL双向认证,服务端是JAVA开发的,使用的证书是jks格式的。C++并不支持JKS格式的证书,所以要用openssl进行转换下。

      1、 需要先把jks转成.p12文件

    keytool -importkeystore -srckeystore demo.jks -destkeystore demo.p12 -srcstoretype jks -deststoretype pkcs12
    

     2、然后把.p12文件转成pem文件

    openssl pkcs12 -nodes -in demo.p12 -out demo.pem

    3、拷贝-----BEGIN CERTIFICATE-----

    -----END CERTIFICATE-----到cacert.pem文件里

    如果有cer格式证书文件有可用下面的命令直接转成cacert.pem

    openssl x509 -inform der -in demo.cer -out cacert.pem

    4、提取私有key

    openssl pkcs12 -in demo.p12 -nocerts -nodes -out demo.key;
    openssl rsa -in demo.key -out privkey.pem;

    流程图:

    有几点注意的地方:

    1、SSL_load_error_strings();
     SSL_library_init();
     OpenSSL_add_all_algorithms();

    只需要执行一次即可,即使后面需要重新连接,也不需要再次调用。所以放在构造函数里可以里了。

    2、一般连接的时候,都会把socket设置成非阻塞的,防止服务端不在线,需要连接很久。但是设置非阻塞之后,ssl_connect可能会连接失败,所以需要多次连接。

    所以我自己封装了下:

    int CSslSocketClient::SSL_ShakeHands()
    {
        int ssl_conn_ret = SSL_connect(m_ssl);
        if (ssl_conn_ret == 1)
        {
            return 0;
        }
        else if (ssl_conn_ret == -1)
        {
            int ssl_conn_err = SSL_get_error(m_ssl, ssl_conn_ret);
            if (SSL_ERROR_WANT_READ == ssl_conn_err ||
                SSL_ERROR_WANT_WRITE == ssl_conn_err) {
                //需要再次来进行握手
                return -2;
            }
            else
            {
                return -1;
            }
        }
        else
        {
            return -1;
        }
    }

    外面调用的时候,如果返回值是0,说明成功,如果是-1,说明失败,如果是-2,说明需要再次ssl连接。

    3、因为要支持双向认证,所以在SSL_new之前需要加载下证书,并check下。

        CString strPath;
        strPath.Format("%s\pem\%s", m_strWorkPath, CERT_NAME);
        if (SSL_CTX_use_certificate_file(m_ctx, strPath, SSL_FILETYPE_PEM) <= 0){
            MYTRACE("CSslSocketClient", "certificate file error!");
            DisconnectSocket();
            return -1;
        }
    
        strPath.Format("%s\pem\%s", m_strWorkPath, PRIV_NAME);
        if (SSL_CTX_use_PrivateKey_file(m_ctx, strPath, SSL_FILETYPE_PEM) <= 0){
            MYTRACE("CSslSocketClient", "use privatekey file Error: %s
    ", ERR_reason_error_string(ERR_get_error()));
            DisconnectSocket();
            return -1;
        }
        if (!SSL_CTX_check_private_key(m_ctx)){
            MYTRACE("CSslSocketClient", "Check private key failed!
    ");
            DisconnectSocket();
            return -1;
        }

    4、类的析构函数里释放内存ssl的内存,但是仍然会有2MB左右的内存泄漏,不会也没有关系,反正这时候程序已经退出了。

         // 释放内存
        sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
        CRYPTO_cleanup_all_ex_data();
    
        ERR_remove_state(0);
        CONF_modules_unload(1);
        CONF_modules_free();
        ERR_free_strings();
        ERR_remove_thread_state(NULL);
        EVP_cleanup();

    上面的函数需要头文件

    #include <openssl/err.h>
    #include <openssl/conf.h>
    高山流水,海纳百川!
  • 相关阅读:
    vue中watch的详细用法
    Golang实现请求限流的几种办法
    观察者模式
    原创-阿里云上SLB暴露K8S服务-四层协议/七层协议
    K8S-HPA创建指南
    阿里云k8s-nas挂载指南
    非原创--mysql语言分类
    mysql命令
    MongoDB从节点支持读请求
    MongoDB用户权限管理
  • 原文地址:https://www.cnblogs.com/ahcc08/p/11302798.html
Copyright © 2011-2022 走看看