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