引擎库路径只能通过/lib下的“LOAD”识别。 OpenSSL 自述文件中的示例位于/lib 下。直到看源码才明白为什么不能任意指定路径。
//#define PKCS11_ENGINE_PATH \’/usr/lib/x86_64-linux-gnu/engines-1.1/pkcs11.so\’
#定义PKCS11_ENGINE_PATH \’/lib/pkcs11.so\’
客户
#include stdio.h
#包括stdlib.h
#include 字符串.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\’
#定义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\’
#definePIN \’1234\’
#define KEY_ID \’mytoken\’
#defineMAXBUF 1024
voidInitialize_ssl_library() {
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
}
无效cleanup_ssl_library(){
EVP_cleanup();
ERR_free_strings();
}
引擎*load_pkcs11_engine() {
ENGINE_load_dynamic();
ENGINE *engine=ENGINE_by_id(\’动态\’);
如果(!引擎){
fprintf(stderr, \’加载动态引擎失败\\n\’);
返回NULL。
}
if (!ENGINE_ctrl_cmd_string(engine, \’SO_PATH\’, PKCS11_ENGINE_PATH, 0) ||
!ENGINE_ctrl_cmd_string(引擎, \’ID\’, \’pkcs11\’, 0) ||
!ENGINE_ctrl_cmd_string(引擎, \’LIST_ADD\’, \’1\’, 0) ||
!ENGINE_ctrl_cmd_string(引擎, \’加载\’, NULL, 0)) {
fprintf(stderr, \’PKCS#11 引擎配置和加载失败\\n\’);
ENGINE_free(引擎);
返回NULL。
}
if (!ENGINE_ctrl_cmd_string(engine, \’MODULE_PATH\’, PKCS11_MODULE_PATH, 0)) {
fprintf(stderr, \’无法设置MODULE_PATH\\n\’);
ENGINE_free(引擎);
返回NULL。
}
如果(!ENGINE_init(引擎)){
fprintf(stderr, \’PKCS#11 引擎初始化失败\\n\’);
ENGINE_free(引擎);
返回NULL。
}
if (!ENGINE_ctrl_cmd_string(引擎, \’PIN\’, PIN, 0)) {
fprintf(stderr, \’无法设置PIN\\n\’);
ENGINE_free(引擎);
返回NULL。
}
返回引擎。
}
int main(int argc, char **argv)
{
初始化_ssl_library();
SSL_CTX *ctx=SSL_CTX_new(TLS_client_method());
如果(!ctx){
fprintf(stderr, \’创建SSL_CTX 失败\\n\’);
返回1。
}
//加载CA证书
if (!SSL_CTX_load_verify_locations(ctx, CA_CERT_FILE, NULL)) {
fprintf(stderr, \’无法加载CA 证书\\n\’);
SSL_CTX_free(ctx);
cleanup_ssl_library();
返回1。
}
//加载客户端证书
if (!SSL_CTX_use_certificate_file(ctx, CERT_FILE, SSL_FILETYPE_PEM)) {
fprintf(stderr, \’无法加载客户端证书\\n\’);
SSL_CTX_free(ctx);
cleanup_ssl_library();
返回1。
}
//加载PKCS#11 引擎
引擎*engine=load_pkcs11_engine();
如果(!引擎){
SSL_CTX_free(ctx);
cleanup_ssl_library();
返回1。
}
字符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(引擎, key_id, NULL, NULL);
如果(!pkey){
fprintf(stderr, \’无法从PKCS#11\\n 加载私钥\’);
ENGINE_free(引擎);
SSL_CTX_free(ctx);
cleanup_ssl_library();
返回1。
}
如果(!SSL_CTX_use_PrivateKey(ctx,pkey)){
fprintf(stderr, \’私钥使用失败\\n\’);
EVP_PKEY_free(pkey);
ENGINE_free(引擎);
SSL_CTX_free(ctx);
cleanup_ssl_library();
返回1。
}
EVP_PKEY_free(pkey);
ENGINE_free(引擎);
//检查私钥与证书是否匹配
如果(!SSL_CTX_check_private_key(ctx)){
fprintf(stderr, \’私钥与证书的公钥不匹配\\n\’);
SSL_CTX_free(ctx);
cleanup_ssl_library();
返回1。
}
/* 创建TCP通信的socket */
int sockfd;
结构体sockaddr_in dest;
if ((sockfd=套接字(AF_INET, SOCK_STREAM, 0)) 0) {
pererror(\’套接字\’);
结束(错误号);
}
printf(\’套接字创建成功!\\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) {
错误(argv[1]);
结束(错误号);
}
printf(\’地址创建成功!\\n\’);
/* 连接到服务器*/
if (connect(sockfd, (struct sockaddr *) dest, sizeof(dest)) !=0) {
pererror(\’连接\’);
结束(错误号);
}
printf(\’服务器连接成功!\\n\’);
//创建SSL连接
SSL *ssl=SSL_new(ctx);
如果(!ssl){
fprintf(stderr, \’无法创建SSL 对象\\n\’);
SSL_CTX_free(ctx);
cleanup_ssl_library();
返回1。
}
SSL_set_fd(ssl, sockfd);
//与服务器执行SSL/TLS 握手
如果(SSL_connect(ssl)=0){
fprintf(stderr, \’SSL/TLS 握手失败\\n\’);
SSL_free(SSL);
SSL_CTX_free(ctx);
cleanup_ssl_library();
返回1。
}
printf(\’SSL/TLS 握手成功\\n\’);
字符send_buffer[MAXBUF + 1];
字符类型recv_buffer[MAXBUF + 1];
int 长度;
同时(1)
{
//使用SSL_write函数发送数据
printf(\’请输入发送到服务器的内容:\\n\’);
scanf(\’%s\’, send_buffer);
if(!strncmp(send_buffer,\’+++\’,3))break //接收++并退出。
/* 向服务器发送消息*/
len=SSL_write(ssl, send_buffer, strlen(send_buffer));
如果(长度0)
printf(\’发送消息\’%s\’失败!错误代码为%d,错误消息为\’%s\’\\n\’, send_buffer, errno, strerror(errno));
除此之外
printf(\’消息\’%s\’成功发送。总共发送%d个字节!\\n\’,send_buffer, len);
memset(send_buffer,0,sizeof(send_buffer));
/* 使用SSL_read函数接收数据,最多可以接收对方MAXBUF字节的消息*/
len=SSL_read(ssl, recv_buffer, MAXBUF);
如果(长度0)
printf(\’消息成功接收:\’%s\’,总共%d字节数据\\n\’,recv_buffer,len);
除此之外
{
printf(\’接收消息失败!错误代码为%d,错误消息为\’%s\’\\n\’,errno, strerror(errno));
休息;
}
memset(recv_buffer,0,sizeof(recv_buffer));
}
SSL_free(SSL);
SSL_CTX_free(ctx);
cleanup_ssl_library();
返回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
成功创建套接字!
你一定会成功的!
开始监听并等待客户端连接.
server: 从127.0.0.1、端口37678、套接字6 获得连接
收到客户端X509 证书
客户数字证书信息:
证书: /CN=localhost/C=CN/ST=clientprovince/L=clientcity/O=clientorganization/OU=clientgroup
发布者: /CN=MyCA
客户端证书验证通过!
等待客户端发送消息:
成功收到客户端消息:\’14673218723187234\’,共17字节数据
输入您要发送给客户的内容:
客户
./ssl_client 127.0.0.1 7838
成功创建套接字!
您已成功创建地址!
服务器连接成功!
SSL/TLS 握手成功
请输入您要发送到服务器的内容:
14673218723187234
消息‘14673218723187234’发送成功,共发送17个字节。
成功接收消息:\’fdsdfsgdfsjk\’(共12字节数据)
请输入您要发送到服务器的内容:
服务器参考
基于openssl的https双向身份认证及安全通信实现博客_基于openssl的身份认证-CSDN
以上关于#TLS + OpenSSL + Engine + PKCS#11 + Softhsm2 安全通信的相关内容来自网络,仅供参考。相关信息请参见官方公告。
原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/92052.html