当前位置: 首页 > news >正文

ubuntu18.04 + openssl + engine + pkcs11+ softhsm2 双向认证测试

安装环境

openssl 1.1.1
pkcs11-tool (由sudo apt-get install opensc 安装)
libpksc11 (需源码安装apt install 只有libp11, 源码安装才有 libpksc11.so -> pkcs11.so)
softhsm2 (由sudo apt-get install softhsm2 libsofthsm2-dev pkcs11-dump 安装)

配置引擎

vim /etc/ssl/openssl.cnfline 1 openssl_conf = openssl_initline n[openssl_init]engines=engine_section[engine_section]pkcs11 = pkcs11_section[pkcs11_section]engine_id = pkcs11dynamic_path = /usr/lib/x86_64-linux-gnu/engines-1.1/libpkcs11.soMODULE_PATH = /usr/lib/softhsm/libsofthsm2.soinit = 0
line end

验证配置

$ openssl engine -t
(rdrand) Intel RDRAND engine[ available ]
(dynamic) Dynamic engine loading support[ unavailable ]
(pkcs11) pkcs11 engine[ available ]

 一次完整RSA加解密

# 需要Slot Token Pin So-Pin
softhsm2-util --init-token --slot 0 --label "mytoken" --pin 1234 --so-pin 12345
# 生成密钥
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --login --keypairgen --key-type rsa:2048 --id 1 --label "mytoken" --pin 1234
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so -l      -k           --key-type rsa:2048 --id 2 --label "mytoken" --pin 1234# get the public key first
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --read-object --type pubkey --id 1 --output-file public.der# 公钥加密
echo 'NetHSM rulez!NetHSM rulez!' | openssl pkeyutl -encrypt -pubin -inkey public.der -keyform DER -out data.crypt# 私钥解密
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --decrypt --id 1 --mechanism RSA-PKCS --input-file data.crypt

双向认证

# 生成根证书私钥(pem文件)
openssl genrsa -out root.key 2048
# 生成根证书签发申请文件(csr文件)
openssl req -new -key root.key -out root.csr -subj "/CN=localhost/C=CN/ST=rootprovince/L=rootcity/O=rootorganization/OU=rootgroup"
# 自签发根证书(cer文件)
openssl x509 -req -days 365 -extensions v3_ca -signkey root.key -in root.csr -out root.crt# 生成服务端私钥   
openssl genrsa -out server.key 2048
# 生成证书请求文件 
openssl req -new -key server.key -out server.csr -subj "/CN=localhost/C=CN/ST=serverprovince/L=servercity/O=serverorganization/OU=servergroup"
# 使用根证书签发服务端证书
openssl x509 -req -days 365 -extensions v3_req -CA root.crt -CAkey root.key -CAserial root.srl -CAcreateserial -in server.csr -out server.crt
# 使用CA证书验证服务端证书
openssl verify -CAfile root.crt server.crt# 须先执行softhsm的步骤
# 生成client密钥对 //module 为pkcs11格式的硬件驱动 id、label和pin要记住
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --login --keypairgen --key-type rsa:2048 --id 2 --label "mytoken" --pin 1234
# 生成请求文件
openssl req -new -subj "/CN=localhost/C=CN/ST=clientprovince/L=clientcity/O=clientorganization/OU=clientgroup" -engine pkcs11 -keyform engine -key "pkcs11:token=mytoken;object=mytoken;type=private;pin-value=12345" -out client.csr
# 使用根证书签发客户端证书
openssl x509 -req -days 365 -extensions v3_req -CA root.crt -CAkey root.key -CAserial root.srl -CAcreateserial -in client.csr -out client.crt
# 使用CA证书验证客户端证书
openssl verify -CAfile root.crt client.crt
# 将cert写入softhsm中
pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so -l --id 1 --label mytoken -y cert -w client.crt --pin 1234

代码加载引擎使用hsm计算

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/engine.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/evp.h>#define PKCS11_ENGINE_PATH "/usr/lib/x86_64-linux-gnu/engines-1.1/pkcs11.so"
// #define PKCS11_MODULE_PATH "/usr/lib/softhsm/libsofthsm2.so"
#define PKCS11_MODULE_PATH "/home/ubuntu/Documents/openssl_engine/p11_engine_module/build/lib/libmypkcs11.so"#define TOKEN_LABEL "mytoken"
#define PIN "12345"
#define KEY_ID "mytoken"int main() {ENGINE *e = NULL;EVP_PKEY *pkey = NULL;EVP_PKEY_CTX *ctx = NULL;unsigned char *plaintext = (unsigned char *)"Hello, PKCS#11!!!!!";unsigned char ciphertext[256];unsigned char decryptedtext[256];size_t ciphertext_len, decryptedtext_len;// 初始化 OpenSSL 引擎ENGINE_load_dynamic();e = ENGINE_by_id("dynamic");if (!e) {fprintf(stderr, "Failed to load dynamic engine\n");return 1;}if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", PKCS11_ENGINE_PATH, 0) ||!ENGINE_ctrl_cmd_string(e, "ID", "pkcs11", 0) ||!ENGINE_ctrl_cmd_string(e, "LIST_ADD", "1", 0) ||!ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) {fprintf(stderr, "Failed to configure PKCS#11 engine\n");ENGINE_free(e);return 1;}// 设置 PKCS#11 模块if (!ENGINE_ctrl_cmd_string(e, "MODULE_PATH", PKCS11_MODULE_PATH, 0)) {fprintf(stderr, "Failed to set PKCS#11 module path\n");ENGINE_free(e);return 1;}// 初始化引擎if (!ENGINE_init(e)) {fprintf(stderr, "Failed to initialize PKCS#11 engine\n");ENGINE_free(e);return 1;}// 设置 PINif (!ENGINE_ctrl_cmd_string(e, "PIN", PIN, 0)) {fprintf(stderr, "Failed to set PIN\n");ENGINE_free(e);return 1;}// 显示使用的引擎printf("Using engine: %s\n", ENGINE_get_name(e));// 加载私钥char key_id[256];snprintf(key_id, sizeof(key_id), "pkcs11:token=%s;object=%s", TOKEN_LABEL, KEY_ID);pkey = ENGINE_load_private_key(e, key_id, NULL, NULL);if (!pkey) {fprintf(stderr, "Failed to load private key\n");ENGINE_free(e);return 1;}// 创建 EVP_PKEY_CTX 用于加密ctx = EVP_PKEY_CTX_new(pkey, e);if (!ctx) {fprintf(stderr, "Failed to create EVP_PKEY_CTX for encryption\n");EVP_PKEY_free(pkey);ENGINE_free(e);return 1;}// 初始化加密操作if (EVP_PKEY_encrypt_init(ctx) <= 0) {fprintf(stderr, "Failed to initialize encryption\n");EVP_PKEY_CTX_free(ctx);EVP_PKEY_free(pkey);ENGINE_free(e);return 1;}// 计算密文长度if (EVP_PKEY_encrypt(ctx, NULL, &ciphertext_len, plaintext, strlen((char *)plaintext)) <= 0) {fprintf(stderr, "Failed to calculate ciphertext length\n");EVP_PKEY_CTX_free(ctx);EVP_PKEY_free(pkey);ENGINE_free(e);return 1;}// 执行加密操作if (EVP_PKEY_encrypt(ctx, ciphertext, &ciphertext_len, plaintext, strlen((char *)plaintext)) <= 0) {fprintf(stderr, "Failed to encrypt data\n");EVP_PKEY_CTX_free(ctx);EVP_PKEY_free(pkey);ENGINE_free(e);return 1;}// 输出加密后的数据printf("Ciphertext (%zu bytes):\n", ciphertext_len);for (size_t i = 0; i < ciphertext_len; i++) {printf("%02x", ciphertext[i]);}printf("\n");// 解密操作// 创建 EVP_PKEY_CTX 用于解密EVP_PKEY_CTX *dctx = EVP_PKEY_CTX_new(pkey, e);if (!dctx) {fprintf(stderr, "Failed to create EVP_PKEY_CTX for decryption\n");EVP_PKEY_CTX_free(ctx);EVP_PKEY_free(pkey);ENGINE_free(e);return 1;}// 初始化解密操作if (EVP_PKEY_decrypt_init(dctx) <= 0) {fprintf(stderr, "Failed to initialize decryption\n");EVP_PKEY_CTX_free(dctx);EVP_PKEY_CTX_free(ctx);EVP_PKEY_free(pkey);ENGINE_free(e);return 1;}// 计算解密后的长度if (EVP_PKEY_decrypt(dctx, NULL, &decryptedtext_len, ciphertext, ciphertext_len) <= 0) {fprintf(stderr, "Failed to calculate decrypted text length\n");EVP_PKEY_CTX_free(dctx);EVP_PKEY_CTX_free(ctx);EVP_PKEY_free(pkey);ENGINE_free(e);return 1;}// 执行解密操作if (EVP_PKEY_decrypt(dctx, decryptedtext, &decryptedtext_len, ciphertext, ciphertext_len) <= 0) {fprintf(stderr, "Failed to decrypt data\n");EVP_PKEY_CTX_free(dctx);EVP_PKEY_CTX_free(ctx);EVP_PKEY_free(pkey);ENGINE_free(e);return 1;}// 输出解密后的数据printf("Decrypted text (%zu bytes):\n", decryptedtext_len);printf("%.*s\n", (int)decryptedtext_len, decryptedtext);const EVP_MD *md;ENGINE *used_engine = NULL;// Load the SHA-256 digest methodmd = EVP_get_digestbyname("SHA256");if (!md) {fprintf(stderr, "Error loading SHA256 digest method\n");}// Check which engine is used for SHA-256used_engine = ENGINE_get_digest_engine(EVP_MD_type(md));if (used_engine) {printf("SHA-256 is provided by engine: %s\n", ENGINE_get_id(used_engine));} else {printf("SHA-256 is provided by the default OpenSSL implementation\n");}// 释放资源EVP_PKEY_CTX_free(dctx);EVP_PKEY_CTX_free(ctx);EVP_PKEY_free(pkey);ENGINE_free(e);return 0;
}

pkcs11模块

#ifndef MYPKCS11_H
#define MYPKCS11_H#include <pkcs11.h>/* Define your own structures and global variables here */
typedef struct {CK_SESSION_HANDLE handle;CK_BBOOL active;
} SESSION;/* Function prototypes */
CK_RV C_Initialize(CK_VOID_PTR pInitArgs);
CK_RV C_Finalize(CK_VOID_PTR pReserved);
CK_RV C_GetInfo(CK_INFO_PTR pInfo);
CK_RV C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession);
CK_RV C_CloseSession(CK_SESSION_HANDLE hSession);
CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo);#endif /* MYPKCS11_H */
#include "mypkcs11.h"
#include <stdio.h>
#include <string.h>/* Global variables */
static CK_BBOOL initialized = CK_FALSE;
static SESSION sessions[16] = {0};  /* Example session storage */// Define our PKCS#11 function list
CK_FUNCTION_LIST functionList;/* C_Initialize initializes the Cryptoki library */
CK_RV C_Initialize(CK_VOID_PTR pInitArgs) {printf("[bgk][module] C_Initialize\n");if (initialized) {return CKR_CRYPTOKI_ALREADY_INITIALIZED;}/* Perform initialization */memset(sessions, 0, sizeof(sessions));initialized = CK_TRUE;return CKR_OK;
}/* C_Finalize finalizes the Cryptoki library */
CK_RV C_Finalize(CK_VOID_PTR pReserved) {printf("[bgk][module] C_Finalize\n");if (!initialized) {return CKR_CRYPTOKI_NOT_INITIALIZED;}/* Perform cleanup */initialized = CK_FALSE;return CKR_OK;
}/* C_GetInfo returns general information about the Cryptoki library */
CK_RV C_GetInfo(CK_INFO_PTR pInfo) {printf("[bgk][module] C_GetInfo\n");if (!initialized) {return CKR_CRYPTOKI_NOT_INITIALIZED;}if (pInfo == NULL) {return CKR_ARGUMENTS_BAD;}pInfo->cryptokiVersion.major = 2;pInfo->cryptokiVersion.minor = 40;strcpy((char*)pInfo->manufacturerID, "MyCompany");pInfo->flags = 0;strcpy((char*)pInfo->libraryDescription, "My PKCS#11 Library");pInfo->libraryVersion.major = 1;pInfo->libraryVersion.minor = 0;return CKR_OK;
}/* C_OpenSession opens a session between an application and a token */
CK_RV C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession) {printf("[bgk][module] C_OpenSession\n");if (!initialized) {return CKR_CRYPTOKI_NOT_INITIALIZED;}for (int i = 0; i < 16; i++) {if (!sessions[i].active) {sessions[i].handle = i + 1;sessions[i].active = CK_TRUE;*phSession = sessions[i].handle;return CKR_OK;}}return CKR_SESSION_COUNT;
}/* C_CloseSession closes a session between an application and a token */
CK_RV C_CloseSession(CK_SESSION_HANDLE hSession) {printf("[bgk][module] C_CloseSession\n");if (!initialized) {return CKR_CRYPTOKI_NOT_INITIALIZED;}for (int i = 0; i < 16; i++) {if (sessions[i].handle == hSession && sessions[i].active) {sessions[i].active = CK_FALSE;return CKR_OK;}}return CKR_SESSION_HANDLE_INVALID;
}/* C_GetSessionInfo returns information about the session */
CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) {printf("[bgk][module] C_GetSessionInfo\n");if (!initialized) {return CKR_CRYPTOKI_NOT_INITIALIZED;}if (pInfo == NULL) {return CKR_ARGUMENTS_BAD;}for (int i = 0; i < 16; i++) {if (sessions[i].handle == hSession && sessions[i].active) {pInfo->slotID = 1;  /* Example slot ID */pInfo->state = CKS_RO_USER_FUNCTIONS;  /* Example state */pInfo->flags = 0;  /* Example flags */pInfo->ulDeviceError = 0;return CKR_OK;}}return CKR_SESSION_HANDLE_INVALID;
}CK_RV C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) {// Initialize digest operationif (pMechanism->mechanism != CKM_SHA256) {return CKR_MECHANISM_INVALID;}return CKR_OK;
}CK_RV C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) {// Perform SHA-256 digest calculationif (pDigest == NULL) {*pulDigestLen = 32; // SHA-256 produces 32-byte digestsreturn CKR_OK;}if (*pulDigestLen < 32) {return CKR_BUFFER_TOO_SMALL;}// Mock SHA-256 computation (replace with actual SHA-256 implementation)memset(pDigest, 0xAA, 32); // Dummy hash value*pulDigestLen = 32;return CKR_OK;
}/* Module entry point */
CK_FUNCTION_LIST function_list = {{ 2, 40 },  /* version */C_Initialize,C_Finalize,C_GetInfo,NULL, /* C_GetFunctionList */NULL, /* C_GetSlotList */NULL, /* C_GetSlotInfo */NULL, /* C_GetTokenInfo */NULL, /* C_GetMechanismList */NULL, /* C_GetMechanismInfo */NULL, /* C_InitToken */NULL, /* C_InitPIN */NULL, /* C_SetPIN */C_OpenSession,C_CloseSession,NULL, /* C_CloseAllSessions */C_GetSessionInfo,NULL, /* C_GetOperationState */NULL, /* C_SetOperationState */NULL, /* C_Login */NULL, /* C_Logout */NULL, /* C_CreateObject */NULL, /* C_CopyObject */NULL, /* C_DestroyObject */NULL, /* C_GetObjectSize */NULL, /* C_GetAttributeValue */NULL, /* C_SetAttributeValue */NULL, /* C_FindObjectsInit */NULL, /* C_FindObjects */NULL, /* C_FindObjectsFinal */NULL, /* C_EncryptInit */NULL, /* C_Encrypt */NULL, /* C_EncryptUpdate */NULL, /* C_EncryptFinal */NULL, /* C_DecryptInit */NULL, /* C_Decrypt */NULL, /* C_DecryptUpdate */NULL, /* C_DecryptFinal */C_DigestInit, /* C_DigestInit */C_Digest, /* C_Digest */NULL, /* C_DigestUpdate */NULL, /* C_DigestKey */NULL, /* C_DigestFinal */NULL, /* C_SignInit */NULL, /* C_Sign */NULL, /* C_SignUpdate */NULL, /* C_SignFinal */NULL, /* C_SignRecoverInit */NULL, /* C_SignRecover */NULL, /* C_VerifyInit */NULL, /* C_Verify */NULL, /* C_VerifyUpdate */NULL, /* C_VerifyFinal */NULL, /* C_VerifyRecoverInit */NULL, /* C_VerifyRecover */NULL, /* C_DigestEncryptUpdate */NULL, /* C_DecryptDigestUpdate */NULL, /* C_SignEncryptUpdate */NULL, /* C_DecryptVerifyUpdate */NULL, /* C_GenerateKey */NULL, /* C_GenerateKeyPair */NULL, /* C_WrapKey */NULL, /* C_UnwrapKey */NULL, /* C_DeriveKey */NULL, /* C_SeedRandom */NULL, /* C_GenerateRandom */NULL, /* C_GetFunctionStatus */NULL, /* C_CancelFunction */NULL, /* C_WaitForSlotEvent */
};/* Define other PKCS#11 functions here... */
/* Module entry point */
__attribute__((visibility("default")))
CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) {printf("[bgk][module] C_GetFunctionList\n");if (ppFunctionList == NULL) {return CKR_ARGUMENTS_BAD;}*ppFunctionList = &function_list;return CKR_OK;
}

执行代码

$ sudo ./bin/p11_engine_app 
[sudo] password for ubuntu: 
[bgk][libp11] engine_ctrl
[bgk][libp11][ctrl] ctx_engine_ctrl, cmd = 201
[bgk][libp11][ctrl] ctx_ctrl_set_module 0, ctx->module = (null)
[bgk][libp11][ctrl] ctx_ctrl_set_module 1, ctx->module = (null), modulename = /home/ubuntu/Documents/openssl_engine/p11_engine_module/build/lib/libmypkcs11.so
[bgk][libp11][ctrl] ctx_ctrl_set_module 1, ctx->module = /home/ubuntu/Documents/openssl_engine/p11_engine_module/build/lib/libmypkcs11.so
[bgk][libp11] engine_init
[bgk][libp11] engine_ctrl
[bgk][libp11][ctrl] ctx_engine_ctrl, cmd = 202
Using engine: pkcs11 engine
[bgk][module] C_GetFunctionList
[bgk][module] C_Initialize
[bgk][module] C_GetInfo
Segmentation fault

执行libsofthsm.so模块

$ sudo ./bin/p11_engine_app 
[bgk][libp11] engine_ctrl
[bgk][libp11][ctrl] ctx_engine_ctrl, cmd = 201
[bgk][libp11][ctrl] ctx_ctrl_set_module 0, ctx->module = (null)
[bgk][libp11][ctrl] ctx_ctrl_set_module 1, ctx->module = (null), modulename = /usr/lib/softhsm/libsofthsm2.so
[bgk][libp11][ctrl] ctx_ctrl_set_module 1, ctx->module = /usr/lib/softhsm/libsofthsm2.so
[bgk][libp11] engine_init
[bgk][libp11] engine_ctrl
[bgk][libp11][ctrl] ctx_engine_ctrl, cmd = 202
Using engine: pkcs11 engine
Ciphertext (256 bytes):
b0847d8e84c56d368afaeb83c08f285274daaaac08a4347c0ce282ff9b09a8f4cc57143281d05470477ed25f65fb67ddea840c902a24ebb3d7c9b97eaf5e737b638e0224077664e048482922930bd283f125395b474b09cfc933b21cd287bdeaaf3316625e4cf271fdbec9d686d6354eee6f45aef66a6909a61da34519cda034a739018a6b614b45d0e32d9ad871952c98c8c83358884d110d7eec7444430cf3bb9c57fc69b2a666a306da4860ed39ea3982d9bae7f3c7022d29a50c8d6fb3a3c89fdf56a21ed1d48bc06f063ac8ead56be4b0bb80e8d8a8505c7d15ea199f35ebd8cbcfb9330882238c938de861dba99dffece4bcfab5fd86fe4f2bd421c9d3
Decrypted text (19 bytes):
Hello, PKCS#11!!!!!

Reference:

openssl + engine + pkcs11 双向认证测试_pkcs11-tool-CSDN博客

pkcs11 工具 - Nitrokey Documentation

Liunx Softhsm2的安装和使用-CSDN博客

https://zhuanlan.zhihu.com/p/476163845

OpenSC team · GitHub

http://www.lryc.cn/news/379919.html

相关文章:

  • 【C++】类和对象2.0
  • 【LLM之KG】KoPA论文阅读笔记
  • UI设计速成课:理解模态窗口与非模态窗口的区别
  • 【Linux】基础IO_4
  • C++模板类原理讲解
  • scratch编程03-反弹球
  • postgresql数据库进阶知识
  • 关于HTTP劫持,该如何理解、防范和应对
  • System.Data.OracleClient.OracleException:“ORA-12571: TNS: 包写入程序失败
  • saas产品运营案例 | 联盟营销计划如何帮助企业提高销售额?
  • 模式分解算法-满足3NF的无损且保持函数依赖的分解算法、满足BCNF的无损连接分解算法
  • 荷兰与法国战平,双方能携手出现?
  • 数据可视化实验二:回归分析、判别分析与聚类分析
  • FL论文专栏|设备异构、异步联邦
  • 【Java毕业设计】基于JavaWeb的礼服租赁系统
  • 代码随想录训练营Day 66|卡码网101.孤岛的总面积、102.沉没孤岛、103.水流问题、104.建造最大岛屿
  • 根据状态转移写状态机-二段式
  • PyTorch C++扩展用于AMD GPU
  • Hadoop archive
  • R语言——R语言基础
  • VFB电压反馈和CFB电流反馈运算放大器(运放)选择指南
  • elasticsearch安装(centos7)
  • Java高手的30k之路|面试宝典|精通JVM(二)
  • JVM专题六:JVM的内存模型
  • 学习java第一百零七天
  • k8s上尝试滚动更新和回滚
  • GitHub Copilot 登录账号激活,已经在IntellJ IDEA使用
  • 进程知识点(二)
  • 【线性代数】【一】1.6 矩阵的可逆性与线性方程组的解
  • 基于大型语言模型的全双工语音对话方案