首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

基於 OpenSSL 實現 X.509 憑證與 SSL/TLS 雙向認證通訊完整指南

     編輯:關於C語言

本文詳細記錄從零開始:安裝 OpenSSL、建立私有 CA、簽發伺服器/客戶端憑證、編寫雙向 TLS 認證的 Client/Server 程式碼,至驗證通訊加密效果的完整流程。

環境建置:Windows 上安裝 OpenSSL

  1. 安裝 ActivePerl (OpenSSL 建置腳本需要)。驗證:perl -v。
  2. 下載 OpenSSL 原始碼 (如 openssl-0.9.8.tar.gz) 解壓至 D:\openssl-0.9.8。
  3. 開啟 Visual Studio 開發人員命令提示字元,進入目錄執行:
    perl Configure VC-WIN32
    ms\do_ms
    nmake -f ms\ntdll.mak
  4. 建立憑證工作目錄 C:\caroot,將 openssl.cnf 複製至此。
  5. 設定環境變數 PATH 加入 D:\openssl-0.9.8\out32dll;VC++ 專案 Include 加入 D:\openssl-0.9.8\include,Library 加入 D:\openssl-0.9.8\out32dll。

建立私有 PKI:CA、伺服器、客戶端憑證

在 C:\caroot 依序執行:

1. 產生 CA 自簽憑證

openssl genrsa -out private\ca.key -rand private\.rnd -des 2048
openssl req -new -x509 -days 3650 -key private\ca.key -out private\ca.crt -config openssl.cnf
openssl x509 -in private\ca.crt -noout -text

2. 產生伺服器憑證

openssl genrsa -out private\server.key 1024
openssl req -new -key private\server.key -out newcerts\server.csr -config openssl.cnf
openssl ca -in newcerts\server.csr -cert private\ca.crt -keyfile private\ca.key -config openssl.cnf -policy policy_anything -out certs\server.crt
openssl x509 -in certs\server.crt -noout -text

3. 產生客戶端憑證

openssl genrsa -out private\client.key 1024
openssl req -new -key private\client.key -out newcerts\client.csr -config openssl.cnf
openssl ca -in newcerts\client.csr -cert private\ca.crt -keyfile private\ca.key -config openssl.cnf -policy policy_anything -out certs\client.crt
openssl x509 -in certs\client.crt -noout -text

檔案對照:

  • ca.crt:CA 根憑證 (雙方皆需信任)
  • server.crt + server.key:伺服器憑證與私鑰
  • client.crt + client.key:客戶端憑證與私鑰

Server 端程式碼核心邏輯

// 初始化 SSL 庫
SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_ssl_algorithms();
SSL_CTX* ctx = SSL_CTX_new(TLSv1_server_method());

// 載入 CA 憑證 (驗證客戶端)
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_load_verify_locations(ctx, "ca.crt", NULL);

// 載入伺服器憑證與私鑰
SSL_CTX_use_certificate_file(ctx, "server.crt", SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(ctx, "server.key", SSL_FILETYPE_PEM);
SSL_CTX_check_private_key(ctx); // 驗證匹配

// 設定加密套件
SSL_CTX_set_cipher_list(ctx, "RC4-MD5");

// TCP Socket 建立、bind、listen、accept...
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
// ... bind, listen, accept -> client_sock

// SSL 握手
SSL* ssl = SSL_new(ctx);
SSL_set_fd(ssl, client_sock);
if (SSL_accept(ssl) <= 0) { /* 錯誤處理 */ }

// 驗證客戶端憑證
X509* client_cert = SSL_get_peer_certificate(ssl);
if (client_cert) {
    char* subject = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);
    char* issuer  = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
    printf("Client Subject: %s\nIssuer: %s\n", subject, issuer);
    OPENSSL_free(subject); OPENSSL_free(issuer); X509_free(client_cert);
}

// 加密通訊
SSL_write(ssl, "Welcome!", 8);
char buf[1024];
int len = SSL_read(ssl, buf, sizeof(buf));
buf[len] = 0; printf("Recv: %s\n", buf);

// 清理
SSL_shutdown(ssl); SSL_free(ssl); SSL_CTX_free(ctx); closesocket(sock);

Client 端程式碼核心邏輯

SSL_CTX* ctx = SSL_CTX_new(TLSv1_client_method());
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
SSL_CTX_load_verify_locations(ctx, "ca.crt", NULL);

// 載入客戶端憑證與私鑰 (雙向認證必須)
SSL_CTX_use_certificate_file(ctx, "client.crt", SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(ctx, "client.key", SSL_FILETYPE_PEM);
SSL_CTX_check_private_key(ctx);

// TCP 連線
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
connect(sock, (sockaddr*)&server_addr, sizeof(server_addr));

// SSL 握手
SSL* ssl = SSL_new(ctx);
SSL_set_fd(ssl, sock);
if (SSL_connect(ssl) <= 0) { /* 錯誤處理 */ }

printf("Connected securely!\n");
// 收發資料...
SSL_read(ssl, buf, sizeof(buf));
SSL_write(ssl, "Hello Server", 12);

// 清理同上

關鍵細節與常見坑

  1. 雙向認證:Server 需 SSL_VERIFY_PEER 並載入 CA;Client 同樣需載入自身憑證/私鑰,Server 才能驗證 Client 身分。
  2. 隨機數種子:Windows 平台 RAND_seed 必須提供足夠熵,否則握手卡死。
  3. 憑證路徑:程式碼使用相對路徑,執行時需將 .crt/.key 放在工作目錄,或改用絕對路徑。
  4. IP 位址顯示:sa_cli.sin_addr.s_addr 為網路位元組序,需 inet_ntoa 轉換顯示。
  5. 錯誤處理:所有 SSL 函數回傳值必須檢查,失敗時呼叫 ERR_print_errors_fp(stderr) 診斷。

驗證結果

啟動 Server,再啟動 Client,雙向 TLS 1.0 握手成功,建立加密通道。Server 端顯示 Client 憑證 Subject/Issuer,雙方可安全收發訊息。

完整程式碼與憑證產生腳本可封裝為專案模板,快速應用於需求加密通訊的嵌入式、物聯網、企業內部系統開發。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved