发现生活之美

linux c++ curl https 请求并双向验证SSL证书

1、配置curl https请求需要提供 CA证书、客户端证书和客户端秘钥,这三个文件的pem格式。

  分别对应 curl_easy_setopt() 函数的 下面三个参数:

  CURLOPT_CAINFO - path to Certificate Authority (CA) bundle
  CURLOPT_SSLKEY - specify private keyfile for TLS and SSL client cert
  CURLOPT_SSLCERT - set SSL client certificate

一般创建SSL证书时会生成 ca.crt , client.crt, client.key, server.crt, server.key 等,而 curl客户端请求,只需要将 ca.crt , client.crt, client.key转成相应的 pem格式 使用。转换方法如下:

  1)将 CRT 转成 PEM---
    不能直接将 .crt 转成 .pem,需要经过 .der 中转

   openssl x509 -in client.crt -out client.der -outform der
   openssl x509 -in client.der -inform der -outform pem -out client.pem

   openssl x509 -in ca.crt -out ca.der -outform der
   openssl x509 -in ca.der -inform der -outform pem -out ca_info.pem

  2)将 .key 转成 .pem

    不能直接将 .key 转成 .pem,需要经过 .der 中转    

   openssl rsa -in client.key -out client.der -outform DER
    openssl rsa -inform DER -outform PEM -in client.der -out client_key.pem

2、配置 curl https请求

  1) 官方例程如下:
  curl 接口文档说明:
   https://curl.haxx.se/libcurl/c/curl_easy_setopt.html
   https://curl.haxx.se/libcurl/c/CURLOPT_CAINFO.html
      https://curl.haxx.se/libcurl/c/https.html

  CURLOPT_CAINFO - path to Certificate Authority (CA) bundle
  CURLOPT_SSLKEY - specify private keyfile for TLS and SSL client cert
  CURLOPT_SSLCERT - set SSL client certificate

按下面代码部分进行配置,即可访问

    CURL *curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");

      // 下面两个为验证对方和验证主机名,若为0,则跳过验证,我这个服务器必须验证才能得到请求数据
      curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L); 
      curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 1L);    
    
        // 配置 https 请求所需证书
      curl_easy_setopt(curl, CURLOPT_CAINFO, "/etc/certs/cabundle.pem");
      curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem");
      curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem");
      curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret");

      ret = curl_easy_perform(curl);
      curl_easy_cleanup(curl);
  }     

  2)我的代码如下

  这是一个完整的 curl 发送 https get 请求,并带中文参数  

#include <iostream>
#include <sstream>
#include <jsoncpp/json/json.h>
#include <curl/curl.h>
#include <exception>
#include <string>
#include <iostream>
#include <stdlib.h>

int writer(char *data, size_t size, size_t nmemb, string *writerData)
{
  unsigned long sizes = size * nmemb;
  if (writerData == NULL)
  return -1;

  writerData->append(data, sizes);
  return sizes;
}

string parseJsonResponse_question(string input)
{
    Json::Value root;
    Json::Reader reader;
    bool parsingSuccessful = reader.parse(input, root);
    if(!parsingSuccessful)
    {
        std::cout<<"!!! Failed to parse the response data"<< std::endl;
        return "";
    }
    const Json::Value text = root["obj"]["question"];
    string result = text.asString(); 
    return result;
}

string HttpsGetRequest_question(string input)
{
    string buffer, ling_result;

    // 对请求参数中的中文和特殊字符(如空格等)进行处理,方可使用
    char * escape_control = curl_escape(input.c_str(), input.size());
    input = escape_control;
    curl_free(escape_control);

    string str_url= "https://*.*.*.*/question?question=" + input; // alter *.*.*.* by your server address
    
    try
    {
        CURL *pCurl = NULL;
        CURLcode res;

        // In windows, this will init the winsock stuff
        curl_global_init(CURL_GLOBAL_ALL); 
        // get a curl handle
        pCurl = curl_easy_init();
        if (NULL != pCurl)
        {
            // 设置超时时间为8秒
            curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, 8); 
            curl_easy_setopt(pCurl, CURLOPT_URL, str_url.c_str());

            // 下面两个为验证对方和验证主机名,若为0,则跳过验证,我这个服务器必须验证才能得到请求数据
            curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 1L); 
            curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, 1L);

            // 配置 https 请求所需证书
            curl_easy_setopt(pCurl,CURLOPT_CAINFO,"/etc/msc/ca_info.pem"); 
            curl_easy_setopt(pCurl, CURLOPT_SSLCERT, "/etc/msc/client.pem");
            curl_easy_setopt(pCurl, CURLOPT_SSLKEY, "/etc/msc/client_key.pem");
            curl_easy_setopt(pCurl, CURLOPT_KEYPASSWD, "your_key_password");

            curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, writer); 
            curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &buffer);

            // Perform the request, res will get the return code
            res = curl_easy_perform(pCurl);
            // Check for errors
            if (res != CURLE_OK)
            {
                printf("curl_easy_perform() failed:%s\n", curl_easy_strerror(res));
            }
            curl_easy_cleanup(pCurl);
        }
        curl_global_cleanup();
    }
    catch (std::exception &ex)
    {
        printf("curl exception %s.\n", ex.what());
    }
    if(buffer.empty())
    {
        std::cout<< "!!! ERROR The sever response NULL" << std::endl;
    }
    else
    {
        ling_result = parseJsonResponse_question(buffer);
    }
    return ling_result;
}

参考:

  http://blog.csdn.net/rztyfx/article/details/6919220
  https://segmentfault.com/a/1190000011709784

posted on 2017-12-22 10:38  发现生活之美  阅读(20055)  评论(1编辑  收藏  举报

导航