TLS + OpenSSL + Engine + PKCS#11 + softhsm2 安全通信

06-28 1096阅读

引擎库路径只有在 /lib 下才能被 "LOAD" 识别到,OpenSSL的ReadMe给的示例在/lib,大概是在构建OpenSSL时默认的configure指定了lib路径

TLS + OpenSSL + Engine + PKCS#11 + softhsm2 安全通信
(图片来源网络,侵删)
// #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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
// #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 1024
void 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 certificate
    if (!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 certificate
    if (!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 engine
    ENGINE *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 certificate
    if (!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))  

使用参数

./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博客

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]