基於SSL協議的安全網路通訊程式
基於SSL協議的安全網路通訊程式
****************************************
目錄結構:
1. SSL理解
1.1 SSL的優點
1.2 SSL密文會話的安全機制
1.3 SSL工作過程
(1) SSL分層結構
(2) SSL握手過程
(3) 利用Wireshark分析SSL工作過程
2. X.509證書相關檔案的生成
3. 實現SSL伺服器和客戶端
****************************************
1. SSL理解
1.1 SSL的優點
(1)提供較高的安全性保證。SSL利用資料加密、身份驗證和訊息完整性驗證機制,保證資料傳輸的安全性。
(2)支援各種應用層協議。雖然SSL設計的初衷是為了解決Web安全性問題,但是由於SSL位於應用層和傳輸層之間,它可以為任何基於TCP等可靠連線的應用層協議提供安全性保證。
(3)部署簡單。目前SSL己經成為網路中用來鑑別網站和網頁瀏覽者身份,在客戶端瀏覽器和Web伺服器之間進行密文資料通訊的全球化標準。SSL協議已被整合到大部分的瀏覽器中,如IE、Netscape、Firefox等。這就意味著幾乎任意一臺裝有瀏覽器的計算機都支援SSL連線,不需要安裝額外的客戶端軟體。
1.2 SSL密文會話的安全機制
(1)資料加密傳輸:資料需要加密後再進行傳輸,加密解密演算法為對稱金鑰算法。
(2)身份驗證
(3)訊息完整性驗證:訊息傳輸過程中使用MAC演算法來檢驗訊息的完整性。
l 資料加密傳輸
與非對稱金鑰體制相比,對稱金鑰體制具有計算速度快的優點,通常用於對大量資料進行加密(如對整個資料流加密);而非對稱金鑰體制,一般用於數字簽名和對少量的資訊進行加密。SSL加密管道上的資料加解密使用對稱金鑰體制,目前主要支援的演算法有DES、 3DES、 AES等,這些演算法都可以有效地防止傳輸的資料被竊聽。
l 身份驗證
電子商務和網上銀行等Web應用中必須保證客戶要登入的Web伺服器是真實的,以免重要資訊被非法竊取。SSL安全協議利用數字簽名來進行通訊對端的身份驗證。非對稱金鑰體制可以用來實現數字簽名。由於通過私鑰加密後的資料只能利用對應的公鑰進行解密
SSL客戶端必須驗證SSL伺服器的身份,SSL伺服器是否驗證SSL客戶端的身份,則由SSL伺服器決定。使用數字簽名驗證身份時,需要確保被驗證端的公鑰是真實的,否則,非法使用者可能會冒充被驗證端與驗證端通訊。
l 訊息完整性驗證
為了避免網路中傳輸的資料被非法篡改,SSL利用基於MD5或SHA的MAC(訊息認證碼)演算法來保證訊息的完整性。
MAC演算法要求通訊雙方具有相同的金鑰,否則MAC值附件驗證將會失敗。因此,利用MAC演算法驗證訊息完整性之前,需要在資料通訊的雙方部署相同的金鑰。
l 利用非對稱金鑰演算法保證金鑰本身的安全
SSL利用非對稱金鑰體制加密金鑰的方法來實現金鑰交換,保證非授權的第三方無法獲取相應的金鑰。
利用非對稱金鑰演算法加密對稱金鑰之前,Alice需要獲取Bob的公鑰,並保證該公鑰確實屬於Bob,否則,金鑰可能會被未授權的非法使用者竊取。SSL利用PKI提供的機制保證公鑰的真實性。
l PKI保證公鑰的真實性
數字證書(簡稱證書)是一個包含使用者的公鑰及其身份資訊的檔案,證明了客戶與公鑰的關聯。數字證書由權威機構(CA)簽發,並由CA保證數字證書的真實性。
驗證SSL伺服器/SSL客戶端的身份之前,SSL伺服器和SSL客戶端需要將從CA獲取的證書傳送給通訊對端,對端通過PKI判斷該證書的真實性。如果該證書確實屬於SSL伺服器和SSL客戶端,則通訊對端利用該證書中的公鑰驗證SSL伺服器和SSL客戶端的身份。
1.3 SSL工作過程
(1) SSL分層結構
(2) SSL握手過程
SSL握手協議是SSL協議中最複雜的協議。SSL通過握手過程在客戶端和伺服器之間協商會話引數,並建立會話。會話包含的主要引數有會話ID、對方的證書、加密套件(金鑰交換演算法、資料加密演算法和MAC演算法等)以及主金鑰(mastersecret)。通過SSL會話傳輸的資料,都將採用此次會話的主金鑰和加密套件進行加密、計算MAC值等。
SSL握手協議由一系列報文組成,根據功能基本上可以分為四個階段:
1) 第一階段是建立安全能力。
2) 第二階段是伺服器鑑別和金鑰交換。
3) 第三個階段是客戶鑑別和金鑰交換。
4) 第四個階段是完成握手階段。
(3)利用Wireshark分析SSL工作過程
1.handshake--client hello
註釋:
ECC演算法和DH結合使用,用於金鑰磋商,這個金鑰交換演算法稱為ECDH。
使用RC4加密體制演算法對通訊資料加密(金鑰長度128位)
使用SHA雜湊演算法進行訊息完整性驗證
使用RSA公鑰體制演算法進行證書驗證和對稱金鑰交換
【既然金鑰交換演算法有很多種(RSA 和DH)那SSL握手期間用哪種呢,這個就是之前由選擇的ciphersuit決定的,比如選擇的是SSL_RSA_WITH_RC4_128_MD5 = 0x0004,那就是RSA的金鑰交換演算法即用非對稱加密對稱將金鑰傳送到對方,若選擇的是SSL_DHE_RSA_EXPORT….那就使用DH交換演算法】
2.handshake--server hello
3.S—>C handshake—certificate 伺服器端向客戶端傳送伺服器證書
【Certificate(可選):伺服器發一個證書或一個證書鏈到客戶端,證書鏈開始於伺服器公共鑰匙並結束於證明權威的根證書。該證書用於向客戶端確認伺服器的身份,該訊息是可選的。如果配置伺服器的SSL需要驗證伺服器的身份,會發送該訊息。多數電子商務應用都需要伺服器端身份驗證。】
4.S-->Chandshake—sever key exchange handshake—sever hello done
伺服器傳送公鑰和簽名信息
【如果伺服器傳送的公共金鑰對加密金鑰的交換不是很合適,則傳送一個伺服器金鑰交換訊息。即和客戶端協商金鑰。】
RSA方式金鑰交換訊息則把訊息中的加密用公鑰放入會話快取中,作為客戶端這邊握手階段的寫金鑰而不是用伺服器證書中的公鑰。
DH 方式的訊息就把訊息中的 p,g,Ys三個引數(ECDH金鑰交換情況下是G和A)記錄下來,有這些 client端就可以計算出 pre-master了,只要回頭再把自己這邊的Yc引數發過去, server端就也能計算出相同的 pre-maseter了。
為了防止訊息被惡意篡改,Server Key exchange訊息中還要包含一個對金鑰引數(pubKey)的簽名(Signature)。
(1)serverkey exchange Pubkey signature
(2)Server hello done
5.C->S handshake—clientkey exchange
客戶端產生一個會話金鑰與伺服器共享。在SSL握手協議完成後,客戶端與伺服器端通訊資訊的加密就會使用該會話金鑰。如果使用RSA加密演算法,客戶端將使用伺服器的公鑰將會話金鑰之後再發送給伺服器。伺服器使用自己的私鑰對接收的訊息進行解密得到共享的會話金鑰。
若是 RSA 方式金鑰交換,則產生一個 48 位隨機數作為 pre-master 並用伺服器公鑰加密後發出去若是 DH 方式的金鑰交換,則根據 sever 的 g,p,Ys ,產生 Xa 和 Yc , Xa 和 Ys 能計算出 pre-master ,把產生的 Yc 放入訊息中發給server ,這樣 server 用它的 Xb 和 Yc 也能計算出 pre-master 了。計算出預主密碼後就順便把主密碼 (master secret) 給算出來了。算出主密碼就把對稱金鑰產生出來了(預主要密碼à主密碼à對稱金鑰)
clientkey exchange, change cipher spec ,encrypted handshakemessage
【Change cipher spec:客戶端要求伺服器在後續的通訊中使用加密模式】
6.S->C handshake—new session ticket
New session ticket,change cipher spec,encrypted handshake message
【Change cipher spec:伺服器要求客戶端在後續的通訊中使用加密模式】
“session Ticket”(RFC 5077)取代機制被引入,目標是消除伺服器需要維護每個客戶端的會話狀態快取的要求。相反,如果客戶指示它支援Session Ticket,在TLS握手的最後一步中伺服器將包含一個“NewSession Ticket”資訊,包含了一個加密通訊所需要的資訊,這些資料採用一個只有伺服器知道的金鑰進行加密。
】
以上1-6步,握手完成。下面開始客戶端和伺服器端開始傳輸加密資訊。
7.C-->S 傳送正式資料
【淘寶網登陸頁面SSL連線建立分析】
42.156.196.14 https://login.taobao.com/member/login.jhtml
(1)C-->S client hello
(2)S-->C server hello
Ciphersuite:TLS_RSA_WITH_RC4_128_SHA
(3)S-->C certificate 證書鏈
(4)C-->S Client Key Exchange
RSA Encrypted Secret
(5)C-->S New Session Ticket
2. X.509證書相關檔案的生成
生成數字證書相關檔案的步驟:
1.生成伺服器端的私鑰(key檔案),執行命令
openssl genrsa -des3 -out server.key1024
Enter pass phrase for server.key:123456
2.生成伺服器端的csr檔案
openssl req -new -key server.key -outserver.csr -config openssl.cnf
===拷貝 openssl\apps 下的openssl.cnf文件到out32dll目錄下,就可以使用 Openssl了。
Enter pass phrase for server.key:123456
A challenge password:147258
3.客戶端生成key檔案
openssl genrsa -des3 -out client.key1024
Enter pass phrase for client.key:123456
4.生成客戶端的csr檔案
openssl req -new -key client.key -outclient.csr -config openssl.cnf
Enter pass phrase for client.key:123456
A challenge password:147258
5.生成自己的CA
openssl req -new -x509 -keyout ca.key -outca.crt -config openssl.cnf
Enter PEM pass phrase:123456
生成ca.key和ca.crt證書檔案
6.用生成的ca給伺服器的csr檔案簽名,生成伺服器端的證書
openssl ca -in server.csr -out server.crt-cert ca.crt -keyfile ca.key -config openssl.cnf
===將apps目錄下的demoCA目錄以及根目錄下的crypto目錄複製到out32dll目錄下;並在demoCA目錄下新建資料夾newcerts.
Enter pass phrase for ca.key:123456
7.用生成的ca給客戶端的csr檔案簽名,生成客戶端的證書
openssl ca -in client.csr -out client.crt-cert ca.crt -keyfile ca.key -config openssl.cnf
===清空index.txt檔案內容後正常生成
Enter pass phrase for ca.key:123456
生成的相關檔案如下圖所示:
3. 實現SSL伺服器和客戶端
對於上面的證書生成過程中,SSL伺服器和客戶端中所需要使用的只有五個檔案,分別是ca.crt,client.crt,client.key,server.crt和server.key。
客戶端需要ca.crt,client.crt,client.key這三個檔案,
伺服器端需要ca.crt,server.crt,server.key這三個檔案。
原始碼:
SSL Server端:
//
#include "openssl/rsa.h"
#include "openssl/crypto.h"
#include "openssl/x509.h"
#include "openssl/pem.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "openssl/rand.h"
#include <iostream>
using namespace std;
#pragma comment(lib, "libeay32.lib")
#pragma comment(lib, "ssleay32.lib")
/*所有需要的引數資訊都在此處以#define的形式提供*/
#define CERTF "D:\\openssl-1.0.1e\\out32dll\\server.crt" /*客戶端的證書(需經CA簽名)*/
#define KEYF "D:\\openssl-1.0.1e\\out32dll\\server.key" /*客戶端的私鑰(建議加密儲存)*/
#define CACERT "D:\\openssl-1.0.1e\\out32dll\\ca.crt" /*CA 的證書*/
#define PORT 7758 /*服務端的埠*/
#define CHK_NULL(x) if ((x)==NULL) { printf("null\n"); }
#define MAXLEN 4096
int main ()
{
int err;
int ListenSock;//監聽套接字
int ConnectSock;//連線套接字
SSL_CTX* ctx;
SSL* ssl;
X509* client_cert;
// char* str;
char buf [MAXLEN] = {0};
// char szMsg[4096] = {0};
//SSL_METHOD *meth;
WSADATA wsaData;
system("title SSL_SERVER");
system("color 0a");
if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0){
printf("WSAStartup()fail:%d\n",GetLastError());
return -1;
}
OpenSSL_add_ssl_algorithms(); /*初始化*/
SSL_load_error_strings(); /*為列印除錯資訊作準備*/
//注意這裡是server和和客戶端不同
//meth=TLSv1_server_method();
ctx = SSL_CTX_new (TLSv1_server_method()); //採用什麼協議(SSLv2/SSLv3/TLSv1)在此指定
CHK_NULL(ctx);
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /*驗證與否*/
SSL_CTX_load_verify_locations(ctx,CACERT,NULL); /*若驗證,則放置CA證書*/
if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0)
{
cout<<"伺服器端證書檢查失敗!"<<endl;
exit(0);
}
if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0)
{
cout <<"伺服器端key檢查失敗!"<<endl;
system("pause");
exit(0);
}
else
{
cout<<"伺服器端key檢查成功!"<<endl;
}
if (!SSL_CTX_check_private_key(ctx))
{
cout << "伺服器端證書和key不匹配!"<<endl;
exit(0);
}
SSL_CTX_set_cipher_list(ctx,"AES128-SHA");//*********加密方式 1.4******
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); //不需要任何重試請求
//建立監聽套接字
ListenSock = socket (AF_INET, SOCK_STREAM, 0);
if(ListenSock == INVALID_SOCKET)
{
cout << "監聽套接字建立失敗" << endl;
exit(0);
}
//建立地址
sockaddr_in sin = {0};
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons (PORT); //Servert Port Number
//套接字繫結
err = bind(ListenSock, (struct sockaddr*)&sin,sizeof(sin));
if(err == -1)
{
cout << "監聽套接字繫結失敗" << endl;
exit(0);
}
/*接受TCP連結*/
err = listen (ListenSock, 5); //等待連線的佇列的最大長度為5
if(err == -1)
{
cout << "監聽套接字開啟監聽失敗" << endl;
exit(0);
}
//接受客戶端連線
struct sockaddr_in sa_client;
int len=sizeof(struct sockaddr);
ConnectSock = accept(ListenSock, (struct sockaddr *)&sa_client, &len);
if(err == -1)
{
cout << "監聽套接字accept失敗" << endl;
exit(0);
}
cout<<"Connection from "<<inet_ntoa(sa_client.sin_addr)<<",port:"<<ntohs(sa_client.sin_port)<<"............"<<endl;
closesocket (ListenSock); //**********
/*--------------------TCP連線已建立,進行服務端的SSL過程.--------------- */
cout << "TCP連線建立,建立SSL連線中....\n" << endl;
//從初始化的ctx新建SSL
ssl = SSL_new (ctx);
if(ssl == NULL)
{
cout << "SSL建立失敗" << endl;
exit(0);
}
//(連線)套接字和SSL繫結 //<------------key
SSL_set_fd (ssl, ConnectSock);
// SSL連線建立
err = SSL_accept (ssl);//等待一個TLS / SSL客戶端啟動TLS / SSL握手,類似於socket中的accept。
if(err == -1)
{
cout << "建立SSL連線失敗" << endl;
exit(0);
}
else
{
cout << "建立SSL連線成功" << endl;
}
/*列印所有加密演算法的資訊(可選)*/
cout << "SSL連線演算法資訊:" << SSL_get_cipher (ssl) << endl;
/*得到客戶端的證書並列印些資訊(可選) */
client_cert = SSL_get_peer_certificate (ssl);
if (client_cert != NULL) {
cout << "客戶端證書:" << endl;
cout << "subject:" <<X509_NAME_oneline(X509_get_subject_name (client_cert), 0, 0)<< endl;
cout << "issuer:" <<X509_NAME_oneline(X509_get_issuer_name (client_cert),0,0) << endl;
// CHK_NULL(str);
X509_free (client_cert);/*如不再需要,需將證書釋放 */
}
else cout << "客戶端沒有證書資訊!" << endl; //客戶端認證失敗
//SSL通訊,用SSL_write,SSL_read代替send和recv
while(true)
{
//接收訊息
err = SSL_read (ssl, buf, sizeof(buf) - 1);
if(err == -1)
{
cout << "SSL_read接收訊息失敗" << endl;
exit(0);
}
buf[err] = '\0';
cout << "【Client】:" << buf << endl;
//傳送訊息
cout << "請輸入要傳送的訊息:";
gets(buf);//end with CRLF or EOF
err = SSL_write(ssl, buf, strlen(buf));
if(err == -1)
{
cout << "SSL_write傳送訊息失敗" << endl;
exit(0);
}
cout << "【Server】:" << buf << endl;
}
//關閉套接字和ssl
SSL_shutdown (ssl);
shutdown (ConnectSock,2);
SSL_free (ssl);
SSL_CTX_free (ctx);
closesocket(ConnectSock);
return 0;
}
SSL Client 端:
//
#include "openssl/rsa.h"
#include "openssl/crypto.h"
#include "openssl/x509.h"
#include "openssl/pem.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "openssl/rand.h"
#include <iostream>
using namespace std;
#pragma comment(lib, "libeay32.lib")
#pragma comment(lib, "ssleay32.lib")
/*所有需要的引數資訊都在此處以#define的形式提供*/
#define CERTF "D:\\openssl-1.0.1e\\out32dll\\client.crt" /*客戶端的證書(需經CA簽名)*/
#define KEYF "D:\\openssl-1.0.1e\\out32dll\\client.key" /*客戶端的私鑰(建議加密儲存)*/
#define CACERT "D:\\openssl-1.0.1e\\out32dll\\ca.crt" /*CA 的證書*/
#define PORT 7758 /*服務端的埠*/
#define CHK_NULL(x) if ((x)==NULL) { printf("null\n"); }
#define MAXLEN 4096
int main ()
{
int err;
int sd;
struct sockaddr_in sa;
SSL_CTX* ctx;
SSL* ssl;
X509* server_cert;
// char* str;
char buf [MAXLEN] = {0};
// char szMsg[MAXLEN] = {0};
//SSL_METHOD *meth;
//int seed_int[100]; /*存放隨機序列*/
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0){
printf("WSAStartup()fail:%d\n",GetLastError());
return -1;
}
system("title SSL_CLIENT");
system("color 0a");
OpenSSL_add_ssl_algorithms(); /*1.SSL初始化*/
SSL_load_error_strings(); /*2.SSL錯誤資訊初始化 為列印除錯資訊作準備*/
//注意這裡是client和和伺服器不同
ctx = SSL_CTX_new (TLSv1_client_method()); //3.建立本次會話所使用的協議(TLSv1); 4.申請SSL會話的環境
CHK_NULL(ctx);
//SSL_VERIFY_PEER:希望驗證對方的證書
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /*驗證與否*/ //5.設定會話的握手方式
SSL_CTX_load_verify_locations(ctx,CACERT,NULL); /*若驗證,則放置CA證書*/ //6.並載入CA證書
if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) //7.載入自己(客戶端)的整數
{
cout << "客戶端證書檢查失敗!" << endl;
exit(0);
}
if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) //8.載入客戶端的私鑰
{
cout << "客戶端key檢查失敗!" << endl;
system("pause");
exit(0);
}
else
{
cout<<"客戶端證key檢查成功!"<<endl;
}
if (!SSL_CTX_check_private_key(ctx))//9.檢查自己的證書和私鑰是否匹配
{
cout << "客戶端證書和key不匹配!" << endl;
exit(0);
}
//10.加密方式
// SSL_CTX_set_cipher_list(ctx, "RC4-MD5");
SSL_CTX_set_cipher_list(ctx, "AES128-SHA");
//處理握手多次
//設定ssl的模式為SSL_MODE_AUTO_RETRY,使用這個選項進行設定,如果伺服器突然希望進行一次新的握手,那麼OpenSSL可以在後臺處理它。
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
/*構建隨機數生成機制,WIN32平臺必需*/
/* srand( (unsigned)time( NULL ) );
for( int i = 0; i < 100;i++ ) seed_int[i] = rand();
RAND_seed(seed_int, sizeof(seed_int));*/
//11.建立TCP連線請求
sd = socket (AF_INET, SOCK_STREAM, 0);
if(sd == INVALID_SOCKET)
{
cout << "套接字建立失敗!" << endl;
exit(0);
}
memset(&sa,'\0', sizeof(sa));
sa.sin_family = AF_INET;
// 獲取本地地址資訊
// unsigned int SrcIp;
/* char szLocalName[MAXLEN]={0};
gethostname(szLocalName,MAXLEN);
hostent* pHost=gethostbyname(szLocalName);
if(pHost!=NULL)
memcpy(&(sa.sin_addr.s_addr),pHost->h_addr_list[0],pHost->h_length);
else
exit(0);*/
sa.sin_addr.s_addr = inet_addr ("127.0.0.1");
// sa.sin_addr.s_addr = inet_addr ("192.168.146.1");
sa.sin_port = htons (PORT); /* Server Port number *///SERVER PORT
//TCP連線 等待伺服器的響應
cout<<"等待連線中..."<<endl;
int try_count=0;
while(1)
{
err = connect(sd, (struct sockaddr*) &sa,sizeof(sa));
if(try_count>5)
{
cout<<"TCP 連線超時..."<<endl;
system("pause");
exit(1);
}
else
{
if(err == -1)
{
// cout << "TCP連線失敗!" << endl;
try_count++;
continue;
}
else
{
cout << "TCP連線成功!" << endl;
break;
}
}
}
/* 12.TCP 連結已建立.開始 SSL 握手過程.......................... */
//SSL連線
//新建SSL
ssl = SSL_new (ctx); //利用SSL會話的環境ctx申請SSL
if(ssl == NULL)
{
cout << "新建SSL失敗!" << endl;
exit(0);
}
//13. 套接字sd和SSL繫結
SSL_set_fd (ssl, sd);
//14.SLL連線(SSL handshake)
//設定等待伺服器響應的超時時間
while(1)
{
err = SSL_connect (ssl);
if(err == -1)
{
cout << "SSL連線失敗" << endl;
continue;
}
else
{
cout << "SSL連線成功" << endl;
break;
}
}
//列印連線資訊
cout << "SSL連線演算法資訊:" << SSL_get_cipher (ssl) << endl;
/*得到服務端的證書並列印些資訊(可選) */
server_cert = SSL_get_peer_certificate (ssl);//從SSL套接字中提取對方的證書資訊,這些資訊已經被SSL驗證過了
if (server_cert != NULL) {
cout << "伺服器證書:" << endl;
cout << "subject:" << X509_NAME_oneline( X509_get_subject_name (server_cert), 0, 0)<< endl;//得到證書所用者的名字
cout << "issuer:" << X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0) << endl;
// CHK_NULL(str);
X509_free (server_cert);/*如不再需要,需將證書釋放 */
}
else cout << "伺服器沒有證書資訊!" << endl; //伺服器端認證失敗
//SSL通訊,用SSL_write,SSL_read代替send和recv
while(true)
{
//傳送訊息 int SSL_write(SSL *ssl,const void *buf,int num);
cout << "請輸入要傳送的訊息:";
gets(buf);
err = SSL_write(ssl, buf, strlen(buf));
if(err == -1)
{
cout << "SSL_write傳送訊息失敗" << endl;
exit(0);
}
cout << "【Client】:" << buf << endl;
//接收訊息 int SSL_read(SSL *ssl,void *buf,int num);
err = SSL_read (ssl, buf, sizeof(buf) - 1);
if(err == -1)
{
cout << "SSL_read接收訊息失敗" << endl;
exit(0);
}
buf[err] = '\0';
cout << "【Server】:" << buf << endl;
}
/* 收尾工作 */
SSL_shutdown (ssl);//關閉SSL套接字
//shutdown( SOCKET s, int how); 0關閉套接字的讀功能 1關閉套接字的寫功能 2關閉套接字的讀寫功能
//請注意shutdown()函式並不關閉套介面,且套介面所佔有的資源將被一直保持到closesocket()呼叫。
//shutdown (sd,2);//
SSL_free (ssl);//釋放SSL套接字
SSL_CTX_free (ctx);//釋放SSL會話環境
closesocket(sd);//
return 0;
}
執行結果示例: