cpprestsdk https双向认证小测

server/2024/9/24 5:32:06/

概述

因项目需要在系统中引入https双向认证,由于程序使用C/C++和cpprestsdk库编写,从网上经过一顿检索折腾,总算测试通过,故而博文记录用以备忘。

系统环境

Ubuntu 22.04.3 LTS
libcpprest-dev(jammy,now 2.10.18-1build2 amd64)

步骤

  1. 参考自签名根证书、中间证书、服务器证书生成流程详解,生成根证书、服务器证书以及客户端证书,然后用根证书对服务器、客户端的证书进行签名
  2. 编写代码,具体代码看后面
  3. 测试
    测试可以使用curl
    curl命令
curl -v -k --cacert root_cert.pem --cert client_cert.pem --key client_key.pem https://ip:port/

注意:
使用自签名证书的时候,服务器端的证书Common Name字段一定要填写对应的IP,不然会出现SSL握手失败的情况。

服务端代码

#include <cpprest/http_listener.h>
#include <cpprest/json.h>
#include <string>using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::experimental::listener;
namespace net = boost::asio;
namespace ssl = net::ssl;bool verify_callback(bool preverified, boost::asio::ssl::verify_context& ctx)
{char subject_name[256];X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);std::cout << "subject_name:" << subject_name << std::endl;return true;
}int main(int argc, char *argv[]) {string host = "192.168.25.112";int port = 6000;string url = "https://" + host + ":" + to_string(port);http_listener_config conf;string cert = "./certs/server_cert.pem";string privkey = "./certs/server_key.pem";string rootcert = "./certs/root_cert.pem";conf.set_ssl_context_callback([&cert, &privkey, &rootcert](ssl::context &ctx) {try {ctx.set_options(ssl::context::default_workarounds |ssl::context::no_sslv2 | ssl::context::no_tlsv1 |ssl::context::no_tlsv1_1 | ssl::context::single_dh_use);//设置自签名的根证书ctx.load_verify_file(rootcert);//设置根证书签发的服务器证书ctx.use_certificate_chain_file(cert);//设置服务器证书的私钥ctx.use_private_key_file(privkey, ssl::context::pem);//设置验证模式 - 验证对端证书// boost::asio::ssl::verify_fail_if_no_peer_cert 这个必须设置,不然对端不发送证书的时候,服务器是默认通过ctx.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert);//设置认证回调,具体作用,没太搞懂ctx.set_verify_callback(verify_callback);//私钥有密码的情况,通过该回调返回密码//ctx.set_password_callback([]() { return "PASSWORD";});} catch (exception const &e) {clog << "ERROR: " << e.what() << endl;}});http_listener listener = http_listener(utility::conversions::to_string_t(url), conf);listener.support(methods::GET, [](web::http::http_request request) {request.reply(status_codes::OK,U("hello world"));});listener.open().wait();while(true) {sleep(100);}cout << "Listening for requests at: " << host << ":" << port << endl;
}

客户端代码

#define _TURN_OFF_PLATFORM_STRING
#include <cpprest/http_client.h>
#include <cpprest/json.h>
#include <string>using namespace std;
using namespace web;
using namespace web::http;
using namespace web::http::client;
namespace net = boost::asio;
namespace ssl = net::ssl;int main(int argc, char *argv[])
{string host = "192.168.25.112";int port = 6000;string url = "https://" + host + ":" + (to_string(port));string rootcert = "./certs/root_cert.pem";string privkey = "./certs/client_key.pem";string cert = "./certs/client_cert.pem";http_client_config conf;try{conf.set_ssl_context_callback([&cert, &privkey, &rootcert](boost::asio::ssl::context &ctx){// 加载根证书ctx.load_verify_file(rootcert);// 加载根证书签发的客户端证书ctx.use_certificate_chain_file(cert);// 加载客户端证书的私钥ctx.use_private_key_file(privkey, ssl::context::pem);// 设置验证模式 - 验证对端ctx.set_verify_mode(boost::asio::ssl::verify_peer);// 私钥有密码的情况,通过该回调返回密码// ctx.set_password_callback([]() { return "PASSWORD";});});http_client client(uri_builder(url).to_uri(), conf);http_response response = client.request(methods::GET, "/").get();// Check the status code.if (response.status_code() != 200){throw std::runtime_error("Returned " + std::to_string(response.status_code()));}// Read the response body as a string.auto response_body = response.extract_string().get();// Output the response body for debugging.std::cout << "Response Body: " << response_body << std::endl;}catch (const std::runtime_error &e){std::cerr << "Exception caught: " << e.what() << __FILE__ << __FUNCTION__ << __LINE__ << std::endl;}catch (std::exception const &e){clog << "ERROR: " << e.what() << endl;}
}

注意:
以上代码只是在自签名证书下验证过,对于正式环境签发的证书,请自行尝试。

Q&A

Q: SSL握手返回,alert number 80
A: 我不知道咋出现的,只有服务器证书的Common Name不一致的情况,该问题会出现


Q: SSL握手返回, Unknown CA
A: 通过ctx.load_verify_file(rootcert);加载根证书即可

参考链接

自签名根证书、中间证书、服务器证书生成流程详解
HTTPS client server in unix
联盟链系列 - Https双向验证
基于boost和QT 实现客户端/服务端TCP双向证书认证与SSL加密
https双向认证


http://www.ppmy.cn/server/46232.html

相关文章

【数据结构与算法|栈篇】中缀表达式转变为后缀表达式

1. 前言 假设我们已经知道中缀表达式和后缀表达式的概念. 我们可以用符号栈来实现中缀表达式向后缀表达式的转变. 2. 符号栈实现中缀表达式转变为后缀表达式 (1). 思路 我们设计了可变字符串与符号栈. 如果传入的字符串的字符是数字字符&#xff0c;则直接将该字符append到…

【全开源】自习室在线订座小程序源码(FastAdmin+ThinkPHP+uView)

打造高效学习空间的必备工具 一、引言&#xff1a;自习室订座难题的解决之道 在如今的学习环境中&#xff0c;自习室成为了学生们备战考试、进行深度学习的重要场所。然而&#xff0c;随着学生人数的增加&#xff0c;自习室座位资源变得日益紧张。为了解决这一难题&#xff0…

dolphinScheduler(海豚调度器)分布式机群安装

1、安装包准备 下载好安装包 apache-dolphinscheduler-3.0.0-bin.tar.gz&#xff0c;上传至 /opt 2、解压&#xff0c;重命名 cd /opt tar -zxvf apache-dolphinscheduler-3.0.0-bin.tar.gz mv apache-dolphinscheduler-3.0.0-bin/ dolphin_install 3、在MySQL8中创建dolph…

crossover玩游戏缺少文件怎么办 为什么游戏打开说缺失文件 crossover支持的游戏列表 CrossOver 提示 X 11 缺失怎么办?

CrossOver是一款类虚拟机软件&#xff0c;可以实现在Mac电脑上运行exe程序。不少Mac用户为了玩游戏&#xff0c;选择使用CrossOver这款软件玩Windows平台的游戏。 一、CrossOver支持的软件多吗 CrossOver是一款基于Wine的兼容工具&#xff0c;它可以让你在Mac或Linux上运行许多…

React 组件通信

1.从父组件向子组件传递参数: 父组件可以通过props将数据传递给子组件。子组件通过接收props来获取这些数据。 // 父组件 const ParentComponent () > {const data Hello, Child!;return <ChildComponent childData{data} />; }; ​ // 子组件 const ChildCompone…

有向图的拓扑排序

文章目录 概念及模板例题 杂务 概念及模板 有向图的拓扑排序是指将有向无环图中的所有顶点排成一个线性序列&#xff0c;使得图中任意一对顶点u和v&#xff0c;若边(u, v)在图中&#xff0c;则u在该序列中排在v的前面。 例如&#xff0c;假设有n个任务&#xff0c;这些任务需…

Java项目:92 基于SSM的办公管理系统

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 基于SSM的办公管理系统 1、项目介绍 基于SSM的办公管理系统主要是对于办公用品的申领进行管理&#xff0c;系统分为三种角色&#xff0c;超级管理员、企业 职…

【AVL Design Explorer DOE】

AVL Design Explorer DOE 1、关于DOE的个人理解2、DOE参考资料-知乎2.1 DOE发展及基本类型2.2 DOE应用场景2.3 Mintab 中的 DOE工具3、AVL Design Explorer DOE示例 1、关于DOE的个人理解 仿真和试验一样&#xff0c;就像盲人摸象&#xff0c;在不知道大象的全景之前&#xff…