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.cnf

line 1 
    openssl_conf = openssl_init

line n
    [openssl_init]
    engines=engine_section

    [engine_section]
    pkcs11 = pkcs11_section

    [pkcs11_section]
    engine_id = pkcs11
    dynamic_path = /usr/lib/x86_64-linux-gnu/engines-1.1/libpkcs11.so
    MODULE_PATH = /usr/lib/softhsm/libsofthsm2.so
    init = 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;
    }

    // 设置 PIN
    if (!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 method
    md = EVP_get_digestbyname("SHA256");
    if (!md) {
        fprintf(stderr, "Error loading SHA256 digest method\n");
    }

    // Check which engine is used for SHA-256
    used_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 operation
    if (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 calculation
    if (pDigest == NULL) {
        *pulDigestLen = 32; // SHA-256 produces 32-byte digests
        return 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

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值