TLS + OpenSSL + Engine + PKCS#11 + softhsm2 安全通信
引擎库路径只有在 /lib 下才能被 "LOAD" 识别到,OpenSSL的ReadMe给的示例在/lib,大概是在构建OpenSSL时默认的configure指定了lib路径
// #define PKCS11_ENGINE_PATH "/usr/lib/x86_64-linux-gnu/engines-1.1/pkcs11.so"
#define PKCS11_ENGINE_PATH "/lib/pkcs11.so"
本以为通过配置有效
./Configure --prefix=/usr/local/openssl \--openssldir=/usr/local/openssl
或者改Makefile有效,但是
old="ENGINESDIR=\$(libdir)\/engines-1.1"
new="ENGINESDIR=\/usr\/lib\/engine-1.1"
sed -i "s/$old/$new/g" Makefile
构建出来还是
# openssl engine pkcs11 -t
281473798283296:error:25066067:DSO support routines:dlfcn_load:could not load the shared library:crypto/dso/dso_dlfcn.c:118:filename(/home/test0923/Documents/optee_three_part/openssl/out/lib/engines-1.1/pkcs11.so): /home/test0923/Documents/optee_three_part/openssl/out/lib/engines-1.1/pkcs11.so: cannot open shared object file: No such file or directory
281473798283296:error:25070067:DSO support routines:DSO_load:could not load the shared library:crypto/dso/dso_lib.c:162:
281473798283296:error:260B6084:engine routines:dynamic_load:dso not found:crypto/engine/eng_dyn.c:434:
281473798283296:error:2606A074:engine routines:ENGINE_by_id:no such engine:crypto/engine/eng_list.c:421:id=pkcs11
但只找到了export方法
export OPENSSL_ENGINES=/usr/lib/engines-1.1
客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <openssl/err.h>
#include <openssl/engine.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>// #define PKCS11_ENGINE_PATH "/usr/lib/x86_64-linux-gnu/engines-1.1/pkcs11.so"
#define PKCS11_ENGINE_PATH "/lib/pkcs11.so"
#define PKCS11_MODULE_PATH "/usr/lib/softhsm/libsofthsm2.so"#define CERT_FILE "../hsm_pem/client.crt"
#define CA_CERT_FILE "../hsm_pem/ca.crt"#define TOKEN_LABEL "mytoken"
#define PIN "1234"
#define KEY_ID "mytoken"#define MAXBUF 1024void initialize_ssl_library() {SSL_library_init();SSL_load_error_strings();OpenSSL_add_all_algorithms();
}void cleanup_ssl_library() {EVP_cleanup();ERR_free_strings();
}ENGINE *load_pkcs11_engine() {ENGINE_load_dynamic();ENGINE *engine = ENGINE_by_id("dynamic");if (!engine) {fprintf(stderr, "Failed to load dynamic engine\n");return NULL;}if (!ENGINE_ctrl_cmd_string(engine, "SO_PATH", PKCS11_ENGINE_PATH, 0) ||!ENGINE_ctrl_cmd_string(engine, "ID", "pkcs11", 0) ||!ENGINE_ctrl_cmd_string(engine, "LIST_ADD", "1", 0) ||!ENGINE_ctrl_cmd_string(engine, "LOAD", NULL, 0)) {fprintf(stderr, "Failed to configure and load PKCS#11 engine\n");ENGINE_free(engine);return NULL;}if (!ENGINE_ctrl_cmd_string(engine, "MODULE_PATH", PKCS11_MODULE_PATH, 0)) {fprintf(stderr, "Failed to set MODULE_PATH\n");ENGINE_free(engine);return NULL;}if (!ENGINE_init(engine)) {fprintf(stderr, "Failed to initialize PKCS#11 engine\n");ENGINE_free(engine);return NULL;}if (!ENGINE_ctrl_cmd_string(engine, "PIN", PIN, 0)) {fprintf(stderr, "Failed to set PIN\n");ENGINE_free(engine);return NULL;}return engine;
}int ShowCerts(SSL * ssl)
{X509 *cert;char *line;cert = SSL_get_peer_certificate(ssl);// SSL_get_verify_result()是重点,SSL_CTX_set_verify()只是配置启不启用并没有执行认证,调用该函数才会真证进行证书认证// 如果验证不通过,那么程序抛出异常中止连接if(SSL_get_verify_result(ssl) == X509_V_OK){printf("收到server X509证书\n");}else{printf("未收到server X509证书\n");return 1;}if (cert != NULL) {printf("server数字证书信息:\n");line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);printf("证书: %s\n", line);free(line);line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);printf("颁发者: %s\n\n", line);free(line);X509_free(cert);printf("对server证书验证通过!!!\n");} else{printf("无证书信息,对server证书验证失败!!!\n");return 1;}return 0;
}int main(int argc, char **argv)
{initialize_ssl_library();SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());if (!ctx) {fprintf(stderr, "Failed to create SSL_CTX\n");return 1;}// 双向验证// SSL_VERIFY_PEER---要求对证书进行认证,没有证书也会放行// SSL_VERIFY_FAIL_IF_NO_PEER_CERT---要求客户端需要提供证书,但验证发现单独使用没有证书也会放行SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);// Load CA certificateif (!SSL_CTX_load_verify_locations(ctx, CA_CERT_FILE, NULL)) {fprintf(stderr, "Failed to load CA certificate\n");SSL_CTX_free(ctx);cleanup_ssl_library();return 1;}// Load client certificateif (!SSL_CTX_use_certificate_file(ctx, CERT_FILE, SSL_FILETYPE_PEM)) {fprintf(stderr, "Failed to load client certificate\n");SSL_CTX_free(ctx);cleanup_ssl_library();return 1;}// Load PKCS#11 engineENGINE *engine = load_pkcs11_engine();if (!engine) {SSL_CTX_free(ctx);cleanup_ssl_library();return 1;}char key_id[256];snprintf(key_id, sizeof(key_id), "pkcs11:token=%s;object=%s", TOKEN_LABEL, KEY_ID);EVP_PKEY *pkey = ENGINE_load_private_key(engine, key_id, NULL, NULL);if (!pkey) {fprintf(stderr, "Failed to load private key from PKCS#11\n");ENGINE_free(engine);SSL_CTX_free(ctx);cleanup_ssl_library();return 1;}if (!SSL_CTX_use_PrivateKey(ctx, pkey)) {fprintf(stderr, "Failed to use private key\n");EVP_PKEY_free(pkey);ENGINE_free(engine);SSL_CTX_free(ctx);cleanup_ssl_library();return 1;}EVP_PKEY_free(pkey);ENGINE_free(engine);// Verify that the private key matches the certificateif (!SSL_CTX_check_private_key(ctx)) {fprintf(stderr, "Private key does not match the certificate public key\n");SSL_CTX_free(ctx);cleanup_ssl_library();return 1;}/* 创建一个 socket 用于 tcp 通信 */int sockfd;struct sockaddr_in dest;if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("Socket");exit(errno);}printf("socket created success!\n");/* 初始化服务器端(对方)的地址和端口信息 */bzero(&dest, sizeof(dest));dest.sin_family = AF_INET;dest.sin_port = htons(atoi(argv[2]));if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) {perror(argv[1]);exit(errno);}printf("address created success!\n");/* 连接服务器 */if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) {perror("Connect ");exit(errno);}printf("server connected success!\n");// Create SSL connectionSSL *ssl = SSL_new(ctx);if (!ssl) {fprintf(stderr, "Failed to create SSL object\n");SSL_CTX_free(ctx);cleanup_ssl_library();return 1;}SSL_set_fd(ssl, sockfd);// Perform SSL/TLS handshake with the serverif (SSL_connect(ssl) <= 0) {fprintf(stderr, "SSL/TLS handshake failed\n");SSL_free(ssl);SSL_CTX_free(ctx);cleanup_ssl_library();return 1;}printf("SSL/TLS handshake successful\n");ShowCerts(ssl);char send_buffer[MAXBUF + 1];char recv_buffer[MAXBUF + 1];int len;while(1){//使用SSL_write函数发送数据printf("请输入要发送给服务器的内容:\n");scanf("%s", send_buffer);if(!strncmp(send_buffer,"+++",3))break; //收到+++表示退出/* 发消息给服务器 */len = SSL_write(ssl, send_buffer, strlen(send_buffer));if (len < 0)printf("消息'%s'发送失败!错误代码是%d, 错误信息是'%s'\n",send_buffer, errno, strerror(errno));elseprintf("消息'%s'发送成功,共发送了%d个字节! \n",send_buffer, len);memset(send_buffer,0,sizeof(send_buffer));/* 使用SSL_read函数接收数据,接收对方发过来的消息,最多接收 MAXBUF 个字节 */len = SSL_read(ssl, recv_buffer, MAXBUF);if (len > 0)printf("接收消息成功:'%s',共%d个字节的数据\n",recv_buffer, len);else {printf("消息接收失败!错误代码是%d, 错误信息是'%s'\n",errno, strerror(errno));break;}memset(recv_buffer,0,sizeof(recv_buffer));}SSL_free(ssl);SSL_CTX_free(ctx);cleanup_ssl_library();return 0;
}
使用参数
./ssl_server 7838 1 ./pem/server.crt ./pem/server.key ./pem/ca.crt
./ssl_client 127.0.0.1 7838
测试结果,服务端
./ssl_server 7838 1 ./pem/server.crt ./pem/server.key ./pem/ca.crt
socket created success!
binded success!
begin listen,waitting for client connect...
server: got connection from 127.0.0.1, port 35546, socket 6
收到client X509证书
client数字证书信息:
证书: /CN=localhost/C=CN/ST=clientprovince/L=clientcity/O=clientorganization/OU=clientgroup
颁发者: /CN=MyCA对client证书验证通过!!!等待客户端发送过来的消息:
接收client消息成功:'saddfsafijd',共11个字节的数据
请输入要发送给客户端的内容:
asfdsa
消息'asfdsa'发送成功,共发送了6个字节!
等待客户端发送过来的消息:
客户端
./ssl_client 127.0.0.1 7838
socket created success!
address created success!
server connected success!
SSL/TLS handshake successful
收到server X509证书
server数字证书信息:
证书: /CN=myserver.com
颁发者: /CN=MyCA对server证书验证通过!!!请输入要发送给服务器的内容:
saddfsafijd
消息'saddfsafijd'发送成功,共发送了11个字节!
接收消息成功:'asfdsa',共6个字节的数据
请输入要发送给服务器的内容:
服务端引用
基于openssl实现https双向身份认证及安全通信_基于openssl身份认证-CSDN博客
相关文章:
TLS + OpenSSL + Engine + PKCS#11 + softhsm2 安全通信
引擎库路径只有在 /lib 下才能被 "LOAD" 识别到,OpenSSL的ReadMe给的示例在/lib,大概是在构建OpenSSL时默认的configure指定了lib路径 // #define PKCS11_ENGINE_PATH "/usr/lib/x86_64-linux-gnu/engines-1.1/pkcs11.so" #define …...
Unity实现简单的MVC架构
文章目录 前言MVC基本概念示例流程图效果预览后话 前言 在Unity中,MVC(Model-View-Controller)框架是一种架构模式,用于分离游戏的逻辑、数据和用户界面。MVC模式可以帮助开发者更好地管理代码结构,提高代码的可维护性…...
【简单讲解下OneFlow深度学习框架】
🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…...
FastGPT 调用Qwen 测试Hello world
Ubuntu 安装Qwen/FastGPT_fastgpt message: core.chat.chat api is error or u-CSDN博客 参考上面文档 安装FastGPT后 登录, 点击右上角的 新建 点击 这里,配置AI使用本地 ollama跑的qwen模型 问题:树上有3只鸟,开了一枪&#…...
Golang-GMP
GMP调度 golang-GMP语雀笔记整理 GMP调度设计目的,为何设计GMP?GMP的底层实现几个核心数据结构GMP调度流程 设计目的,为何设计GMP? 无论是多进程、多线程目的都是为了并发提高cpu的利用率,但多进程、多线程都存在局限性。比如多进程通过时…...
【PythonWeb开发】Flask自定义模板路径和静态资源路径
在大型的 Flask 项目中,确实可能会有多个子应用(Blueprints),每个子应用可能都有自己的静态文件和模板。为了更好地管理和组织这些资源,可以使用static_folder 和template_folder 属性来统一管理。必须同时设置好主应用…...
Java对象创建过程
在日常开发中,我们常常需要创建对象,那么通过new关键字创建对象的执行中涉及到哪些流程呢?本文主要围绕这个问题来展开。 类的加载 创建对象时我们常常使用new关键字。如下 ObjectA o new ObjectA();对虚拟机来讲首先需要判断ObjectA类的…...
Does a vector database maintain pre-vector chunked data for RAG systems?
题意:一个向量数据库是否为RAG系统维护预向量化分块数据? 问题背景: I believe that when using an LLM with a Retrieval-Augmented Generation (RAG) approach, the results retrieved from a vector search must ultimately be presented…...
Rust-11-错误处理
Rust 将错误分为两大类:可恢复的(recoverable)和 不可恢复的(unrecoverable)错误。对于一个可恢复的错误,比如文件未找到的错误,我们很可能只想向用户报告问题并重试操作。不可恢复的错误总是 b…...
自动化测试:使用Postman进行接口测试与脚本编写
Postman 是一种流行的 API 测试工具,广泛应用于开发和测试过程中。它不仅可以用于手动测试,还支持自动化测试和脚本编写,以确保 API 的可靠性和性能。本文将详细介绍如何使用 Postman 进行接口测试与脚本编写,帮助你更高效地进行自…...
ONLYOFFICE 8.1 桌面编辑器测评:引领数字化办公新潮流
目录 前言 下载安装 新功能概述 1.PDF 编辑器的改进 2. 演示文稿中的幻灯片版式 3.语言支持的改进 4. 隐藏“连接到云”板块 5. 页面颜色设置和配色方案 界面设计:简洁大方,操作便捷 性能评测:稳定流畅,高效运行 办公环…...
基于大语言模型LangChain框架:知识库问答系统实践
ChatGPT 所取得的巨大成功,使得越来越多的开发者希望利用 OpenAI 提供的 API 或私有化模型开发基于大语言模型的应用程序。然而,即使大语言模型的调用相对简单,仍需要完成大量的定制开发工作,包括 API 集成、交互逻辑、数据存储等…...
解锁Transformer的鲁棒性:深入分析与实践指南
🛡️ 解锁Transformer的鲁棒性:深入分析与实践指南 Transformer模型自从由Vaswani等人在2017年提出以来,已经成为自然语言处理(NLP)领域的明星模型。然而,模型的鲁棒性——即模型在面对异常、恶意或不寻常…...
mybatis#号和$区别
在MyBatis中,#{}和${}都是用于实现动态SQL的占位符,但它们在使用场景和安全性上有明显的区别: 用途区别: #{}主要用于传递接口传输过来的具体数据,如参数值,它可以防止SQL注入,因为MyBatis会…...
AI绘画 Stable Diffusion【实战进阶】:图片的创成式填充,竖图秒变横屏壁纸!想怎么扩就怎么扩!
大家好,我是向阳。 所谓图片的创成式填充,就是基于原有图片进行扩展或延展,在保证图片合理性的同时实现与原图片的高度契合。是目前图像处理中常见应用之一。之前大部分都是通过PS工具来处理的。今天我们来看看在AI绘画工具 Stable Diffusio…...
Linux内核 -- 汇编结合ko案例之PMU获取cpu cycle技术
ARMv7汇编实现周期计数读取与清空 本文档详细描述了如何在ARMv7平台上使用汇编语言编写周期计数器读取与清空函数,如何在内核模块中导出这些函数供其他模块调用,以及如何使用Netlink接口供用户态程序进行调用。 1. 汇编函数实现 首先,编写…...
探索 Symfony 框架:工作原理、特点及技术选型
目录 1. 概述 2. Symfony 的工作原理 2.1 MVC 架构 2.2 前端控制器模式 2.3 路由机制 2.4 依赖注入容器 2.5 事件驱动架构 3. Symfony 的特点 3.1 高度可扩展性 3.2 强大的社区支持和生态系统 3.3 优秀的性能和可伸缩性 3.4 严格的代码规范和最佳实践 4. Symfony …...
从万里长城防御体系看软件安全体系建设@安全历史03
长城,是中华民族的一张重要名片,是中华民族坚韧不屈、自强不息的精神象征,被联合国教科文组织列入世界文化遗产名录。那么在古代,长城是如何以其复杂的防御体系,一次次抵御外族入侵,而这些防御体系又能给软…...
ISO 19110操作要求类中的/req/operation/formal-definition详细解释
/req/operation/formal-definition 要求: 每个要素操作实体必须具有一个形式定义(formal definition),该定义应明确描述操作的行为和影响。 具体解释 定义 要素操作实体(feature operation entity):这…...
豆包大语言模型API调用错误码一览表
本文介绍了您可能从 API 和官方 SDK 中看到的错误代码。 http code说明 400 原因:错误的请求,例如缺少必要参数,或者参数不符合规范等 解决方法:检查请求后重试 401 原因:认证错误,代表服务无法对请求进…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...
uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...
