TLS握手的OpenSSL實現(深度1)

2022-03-20 04:57:55 字數 3419 閱讀 4385

我們跳過握手的總狀態機和讀寫狀態機,因為我認為那是openssl架構方案的乙個敗筆,邏輯非常的不清晰,是程式設計師思維,而不是正常的邏輯思維。與握手邏輯比較相關的在statem_clnt.c和statem_srv.c中。分別是客戶端的握手邏輯和服務端的握手邏輯。

我們以服務端為重點來分析。

乙個簡單的函式列表就能看出來其中的大體邏輯。對於伺服器來說,是被動的處理訊息,響應客戶端請求的一方。所以所有的傳送都是有接收來觸發,接收對應的函式典型的就是tls_process_開頭的函式,而傳送所對應的函式就是tls_construct對應的函式。

我們知道tls 1.2的握手流程,這個流程終將要體現在**之中。並且會同時體現在客戶端的**和服務端的**兩部分。兩部分的**雖然都位於openssl中,但是實際在執行的時候,openssl要麼作為客戶端要麼作為服務端來執行。

服務端在監聽使用者請求的時候,第乙個訊息肯定是接收客戶端傳送來的client hello訊息,並且對應的處理和返回server hello訊息。如果服務端發現了會話復用的可能,在這一步會做出決策,並且直接影響了後續服務端要傳送的訊息型別。如果決定復用會話,服務端就不會傳送server key exchange訊息。整個訊息處理引擎的入口是ossl_statem_server_process_message函式,該函式如下:

msg_process_return ossl_statem_server_process_message(ssl *s, packet *pkt) else else if (s->method->version != dtls_any_version &&

dtls_version_lt(s->client_version, s->version)) else else else else if (i == -1) else else if (s->hit)

comp = null;

else if (ssl_allow_compression(s) && s->ctx->comp_methods) else else else

#endif

#ifndef openssl_no_ec

//橢圓曲線與dh並不衝突。dh是一種金鑰交換演算法,橢圓曲線是一種計算方法。他們可以共同組合成ecdhe這種密碼交換演算法。單獨的dhe就是用的dh的計算演算法,dh的金鑰交換方法來完成金鑰交換。

if (type & (ssl_kecdhe | ssl_kecdhepsk)) else

#endif /* !openssl_no_ec */

al = ssl_ad_handshake_failure;

sslerr(ssl_f_tls_construct_server_key_exchange,

ssl_r_unknown_key_exchange_type);

goto f_err;

for (i = 0; i < 4 && r[i] != null; i++) else else

#endif

s2n(nr[i], p);

bn_bn2bin(r[i], p);

p += nr[i];

#ifndef openssl_no_ec

if (type & (ssl_kecdhe | ssl_kecdhepsk)) else ssl3_enc_method;

這個方法表中的大部分函式我們都看到過了。有的是通用的外層函式,大部分的都是分別位於s3_enc.c和t1_enc.c中的版本相關的函式。這就是不同協議的握手過程的方法表的封裝。從中,我們看到的目前遇到的兩個關鍵的值的函式,乙個是master key,乙個是key block,key block又是從master key中生成的。接下來master key的生成方法會非常讓人吃驚。

int tls1_generate_master_secret(ssl *s, unsigned char *out, unsigned char *p,

int len)

// 首先檢查是否支援擴充套件的master key(簡稱是extms)。是否支援是extms是由使用者決定的,使用者在傳送client hello的時候有乙個tls擴充套件就叫做extended_master_secret擴充套件。如果使用者傳送了這個擴充套件,後續服務端就都會使用這個擴充套件定義的方法來生成master key。現代的瀏覽器一般會啟用這個擴充套件。

if (s->session->flags & ssl_sess_flag_extms) else else {

openssl_assert(i <= evp_max_md_size);

memcpy(s->s3->previous_server_finished, s->s3->tmp.finish_md, i);

s->s3->previous_server_finished_len = i;

if (!ssl_set_handshake_header(s, ssl3_mt_finished, l)) {

sslerr(ssl_f_tls_construct_finished, err_r_internal_error);

return 0;

return 1;

可以清楚的看到finish mac這個包的內容是寫入了乙個雜湊結果,雜湊結果實際是呼叫的s->method->ssl3_enc->final_finish_mac函式完成的。這個函式在方法表裡面有看到,也是乙個區分版本的雜湊結果計算的函式。

int tls1_final_finish_mac(ssl *s, const char *str, int slen, unsigned char *out)

int hashlen;

unsigned char hash[evp_max_md_size];

if (!ssl3_digest_cached_records(s, 0))

return 0;

hashlen = ssl_handshake_hash(s, hash, sizeof(hash));

if (hashlen == 0)

return 0;

if (!tls1_prf(s, str, slen, hash, hashlen, null, 0, null, 0, null, 0,

s->session->master_key, s->session->master_key_length,

out, tls1_finish_mac_length))

return 0;

openssl_cleanse(hash, hashlen);

return tls1_finish_mac_length;

在tls中,這個函式是首先對目前為止的所有收發的資料報進行一次雜湊計算,然後將雜湊的結果和master key還有乙個輸入的label字串,這個label字串預設是空的。實際上就是目前為止收發的資料報的雜湊值和master key的prf計算的結果。

TLS握手過程

客戶端與伺服器商議通訊金鑰的過程稱為tls握手,在握手階段,通訊內容雖然都是明文,但要保證最終商量的金鑰只有客戶端和伺服器知道,其他中間節點無從得知。rsa握手過程說明 生成master secret 以及從master secret中得到session key mastersecret gener...

TLS 握手優化詳解

隨著 http 2 的逐漸普及,以及國內網路環境越來越糟糕 運營商劫持和篡改 https 已經開始成為主流。https 在 tcp 和 http 之間增加了 tls transport layer security,傳輸層安全 提供了內容加密 身份認證和資料完整性三大功能,同時也給 web 效能優化...

TLS協議握手過程分析

比如說bob有乙個 bob.cn,bob生成了一對公私鑰,其把個人身份及公鑰傳送給ca登記機構,ca登記機構驗證bob的身份,比如是個dv證書,就看證書所對應的網域名稱是不是你的,網域名稱是不是指向你的伺服器。登記機構驗證通過之後,就會把證書簽名申請傳送給ca機構,ca機構用其私鑰簽名之後,頒發證書...