SSL原理介紹

SSL原理介紹

SSL——安全套接字層(Secure Sockers Layer)協議由著名的Netscape公司開發。爲了保證通信雙方建立安全可靠的傳輸隧道,SSL使用PKI中的數字證書技術對通信雙方進行身份認證;使用對稱加密來保證數據保密性;使用消息認證碼(MAC)來保證數據完整性。

SSL位於TCP/IP和各種應用層協議間,如圖1所示,分爲記錄層協議和握手層協議。

SSL位於TCP/IP和各種應用層協議間

圖1

握手層負責對服務器和客戶進行認證,並確定數據加密傳輸採用的密鑰、加密參數和加密算法等。記錄層負責具體的加密解密、計算和驗證MAC等操作,然後將加密後的數據交付給傳輸層。

在具體的應用場景裏,某個客戶端試圖接入服務器時,它將通過握手層與服務器進行算法協商、身份認證、確定通信密鑰等操作。然後,記錄層根據協商的壓縮算法,對數據進行分片壓縮處理;用共享密鑰,根據下面公式計算MAC:hash(MAC_write_secret+pad_2+hash(MAC_write_secret+pad_1+seq_num+SSLCompressed.type+SSLCompressed.length+SSLCompressed.fragment))。計算MAC後,加密壓縮數據和MAC 形成密文。服務器方做相反的處理,在此就不贅述了。

安全通信程序設計

這裏我們採用C/S模式,上層應用只是簡單的收發數據,目的主要是介紹如何利用OPENSSL函數接口,編程實現SSL/TLS協議,用戶可以根據自己的需要跟上層應用相結合,如HTTPS等。涉及到的代碼以服務器端爲例子,服務端流程圖如圖2所示,客戶端類似,不再贅述。

SSL服務端流程圖

圖2

常用函數及數據結構介紹

1)初始化SSL算法庫函數:“int SSL_library_init(void);”。

2)初始化SSL上下文環境變量函數:“SSL_CTX *SSL_CTX_new(SSL_METHOD *meth);”。傳入SSL協議算法,調用成功後返回SSL_CTX結構體指針,否則返回空。這裏涉及到了一個重要的數據結構 SSL_CTX,這個數據結構定義的內容非常多,主要是SSL上下文環境,包括SSL握手中的證書文件和私鑰、協議版本、隨機數、主密鑰、讀寫MAC密鑰等信息,後面通過完整代碼可以看出來。

3)以文件形式設置SSL證書函數。
int SSL_CTX_use_certificate_file(SSL_CTX *ctx,const char *file,int type);

這裏, file用於設置證書文件的路徑;type則是設置證書的編碼類型。證書的編碼類型一般分爲兩種:PEM格式和ASN1格式,即Base64編碼格式和DER編碼文件,它們分別傳入SSL_FILETYPE_PEM、SSL_FILETYPE_ASN1。

4)以文件形式設置SSL私鑰。
int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx,const char *file,int type);

參數與設置證書一樣,這裏就不重複了。這裏是SSL初始化時涉及到的重要的函數。下面以服務器爲例,給出初始化的代碼。初始化後,就可以開始建立SSL連接了。

//初始化OpenSSL環境
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
SSL_METHOD *meth;
meth = SSLv23_server_method();
//使用SSL V2或V3協議
ctx = SSL_CTX_new (meth);
//初始化SSL上下文
if (!ctx)
{
return FALSE;
}
//設置驗證客戶端(SSL中,服務器對客戶端的驗證時可選的,默認模式是不驗證客戶端證書的)
//SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT,verify_callback_server//驗證回調函數);//如果驗證客戶端
SSL_CTX_set_verify(ctx,SSL_VERIFY_FAIL_IF_NO_PEER_CERT,0);
//如果不驗證客戶端
SSL_CTX_load_verify_locations(ctx,ROOTCERTF,NULL);
//若驗證,則放置CA證書
SSL_CTX_set_verify_depth(ctx,1);
SSL_CTX_set_cipher_list(ctx,"RC4-MD5");
//設置服務器證書
if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0)
{
return FALSE;
}
//設置服務器私鑰
if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0)
{
return FALSE;
}
//檢查服務器私鑰和證書是否匹配
if (!SSL_CTX_check_private_key(ctx))
{
return FALSE;
}

5)新建SSL句柄函數:“SSL* SSL_new(SSL_CTX* ctx);”。這個函數利用前面初始化好的SSL_CTX數據結構,來形成一個SSL數據結構,用於後面的通信。

6)綁定SSL與Socket句柄函數:“int SSL_set_fd(SSL* ssl,int fd);”。參數中,ssl就是用調用SSL_new後返回的SSL結構體指針,fd爲Socket鏈接句柄。

7)建立SSL連接函數,其中“int SSL_accept(SSL *ssl);”用於服務器,接受一個SSL鏈接,類似Socket中的accept函數;“int SSL_connect(SSL *ssl);”用於客戶端,連接服務器,類似Socket中的connect函數。

傳入上述綁定完成的SSL結構體指針後,則可建立SSL連接。如果成功,返回1,否則爲0。下面以服務器爲例,給出創建連接的代碼。

//新建socket句柄
listen_sd = socket (AF_INET, SOCK_STREAM, 0);
//初始化sockaddr_in結構體,設置TCP協議和端口
memset (&sa_serv, '\0', sizeof(sa_serv));
sa_serv.sin_family = AF_INET;
sa_serv.sin_addr.s_addr = INADDR_ANY;
sa_serv.sin_port = htons (port);
//綁定端口
err = bind(listen_sd, (struct sockaddr*) &sa_serv,
sizeof (sa_serv));
if(err < 0)
{
//錯誤處理……
return;
}
//偵聽,TCP連接
err = listen (listen_sd, 5); 
if(err < 0)
{
//錯誤處理……
return;
}
//接收連接
clientFd = accept(sockFd, NULL, NULL);
……
//新建SSL連接句柄
if((ssl = SSL_new(ctx)) == NULL)
{
return;
}
//設置SSL連接Socket句柄
SSL_set_fd(ssl, clientFd);
//接收SSL連接
if(SSL_accept(ssl) == 0)
{
return;
}

客戶端與服務器核心部分代碼類似,在此就不贅述了。建立SSL安全連接後,我們可以進行數據交換。

8)發送SSL讀取/數據函數。
int SSL_write(SSL *ssl,const void *buf,int num);
int SSL_read(SSL *ssl,const void *buf,int num);

上述函數類似Socket編程中的write和read函數,其中ssl爲SSL連接句柄,buf爲數據緩衝區指針,num爲長度。

最後調用SSL_free(SSL *ssl)函數釋放連接。到此爲止,一個SSL協議基本搭建完成,加上多線程技術,一個基於SSL的安全通信軟件就完成了。

此外還可以通過OPENSSL中的函數,讀取對方證書名稱、單位以及協議的安全指標等具體內容。服務器端代碼如下:

/*打印所有加密算法的信息(可選)*/
strcpy(msg,SSL_get_cipher (ssl));
//自定義顯示……
/*得到客戶端的證書並打印些信息(可選) */
client_cert = SSL_get_peer_certificate (ssl);
if (client_cert != NULL)
{
strcpy(msg,"Client certificate:");
//自定義顯示……
}
//得到對方證書信息
str=X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);
strcpy(msg,"subject:");
//自定義顯示……
OPENSSL_free (str);
str = X509_NAME_oneline (X509_get_issuer_name  (client_cert), 0, 0);
strcpy(msg,"issuer:");
//自定義顯示……
OPENSSL_free (str);

總結

本文主要向大家介紹了利用OPENSSL實現SSL/TLS編程。本文附帶的程序是一個多線程的通信軟件,因爲代碼過長,上文只貼出了涉及到SSL/TLS的核心部分,具體代碼見附帶工程文件。爲了方便區分,我還設計了一個連接狀態欄和數據交換欄,運行界面如圖3和圖4所示。

SSL通信軟件客戶端

圖3

SSL通信軟件服務端

圖4

對於身份驗證用到的數字證書,文中沒有介紹,我會在以後單獨介紹數字證書的原理和應用,以及OPENSSL中對數字證書的操作,敬請關注。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章