一、什麼是重協商
大部分TLS連接都以handshake爲開始,經過應用數據的交換,最後關閉會話。如果在第一次handshake之後(可能經歷了應用數據的交換也可能沒有)請求重新協商,就會發起一次新的handshake,對新的安全參數達成一致。重協商的handshake的消息都是全部加密的,這與第一次handshake明顯不同。
重協商功能應用場景舉例:
*) Client證書:可以設置訪問網站的根路徑不要求client攜帶證書,而在client訪問特定子區域時server發起重協商請求,要求client攜帶證書;
*) 隱藏消息:由於重協商的handshake消息是加密的,被動攻擊者無法監視協商過程,這樣就可以隱藏一些敏感信息(比如證書中包含的身份識別信息)。
二、怎樣發起重協商
有兩種方式可以發起重協商:
*)Client發起:TLS協議允許client在任意時間簡單地發送新的ClientHello消息請求重新協商,就如同建立一個新的連接一樣;
*)Server發起:如果server希望重新協商,它會發送HelloRequest消息給client,這個消息通知client停止發送應用數據,並開始新的handshake。
三、重協商的安全性
重協商機制並不安全,針對重協商的攻擊類型如下:
3.1 DoS攻擊
TLS的handshake過程需要使用非對稱算法進行身份認證和密鑰協商,這個過程需要很多計算資源。Handshake本來只在TLS連接開始建立時執行一次,但由於重協商機制的引入,使得client被允許不斷髮起新的handshake。由於client可以使用較少的資源來執行handshake(比如:不檢查server的證書,這樣可以避免校驗簽名的開銷),這樣攻擊者就可以更容易地耗盡server的資源導致其拒絕爲其它用戶的請求提供服務。
這種攻擊與分佈式拒絕服務攻擊(DDoS)的不同之處在於,它不需要大量的攻擊來消耗網絡帶寬,而僅僅通過一臺主機的一個TCP/IP socket來耗盡server的資源(這樣就會導致當前的DoS和DDoS防禦策略無效)。例如,一臺server通常能執行150-300次/s握手,而一個client可以發起多達1000次/s握手請求。
防禦方法:
1) 禁用重協商功能:不推薦,因爲這樣會導致依賴重協商的特性無法使用;
2) 禁止client發起重協商:目前看來似乎是個不錯的選擇;
3) 速率限制:對新到來的TLS連接和重協商的速率進行限制;
4) 使用SSL加速卡:通過極大地提高server對handshake的處理能力來增加攻擊的成本,但可能攻擊者只增加一到兩臺主機進行攻擊就可以使得此措施無效。
3.2 中間人攻擊
由於TLS的重協商前後的兩條TLS連接之間沒有關聯(即使它們發生在同一條TCP連接上),而且應用層(如HTTP)與加密層很少交互(例如,如果重協商發生在HTTP請求的過程中,上層應用是得不到通知的),導致TLS層面發生的事情與上層應用瞭解到的信息不匹配。
因此,一箇中間人(man-in-the-middle,MITM)攻擊者就可以通過如下步驟來利用這個漏洞:
1) 攔截一個client到server的TCP連接,截住其TLS handshake請求;
2) 新建一個到server的TLS連接,在handshake之後發送攻擊負載;
3) 將1)中攔截的handshake請求通過與server的TLS連接發送過去,這樣在server看來是重協商,而在client看來是一條全新的TLS連接。一旦重協商完成,client與server開始交換應用層數據,攻擊者的攻擊負載和client的正常數據就會被server合併處理,從而使得攻擊成功。
攻擊過程(舉例)的示意圖如下:
這種攻擊會使得server執行攻擊者制定的任意GET請求。
對於這種MITM攻擊,即使禁止了client發起重協商,依賴於client證書校驗和支持SGC的網站仍然容易遭到攻擊。因爲攻擊者只需要調查網站在哪些情況下是需要進行重協商的,如果條件得到滿足則攻擊者就可以開展攻擊行爲。
防禦方法:
1)禁用重協商功能:不推薦,除了會使得依賴重協商的特性無法使用外,還會導致增加了網絡上重協商功能的不確定性,使得client無法有效保護自己【注1】
2)使用“安全重協商”功能:通過關聯重協商前後的TLS連接來阻止非法數據注入;詳見第四節。
【注1】:重協商的安全缺陷對client的威脅在於:攻擊者可以通過控制服務器來攻擊與之通信的client。由於在攻擊發生時client並未參與到重協商的過程中,故對於client唯一可行的保護自己的方法就是隻於支持安全重協商的server建立連接。對於禁用了重協商功能的server,client不希望自己無法連接它們,但client無法區分server是禁用了重協商還是不支持安全重協商。所以server禁用重協商的行爲會導致client很難使用有效的方法來保護自己。
四、安全重協商
爲了解決中間人攻擊的問題,【RFC5764】提出了“安全重協商”機制。本質很簡單,就是關聯兩次握手,方式是提供了一個新的擴展(renegotiation_info)。SSLv3/TLS 1.0不支持擴展,爲了使其支持安全重協商,client需要發送TLS_EMPTY_RENEGOTIATION_INFO_SCSV(0xFF)密碼套件(縮寫爲SCSV)。
安全重協商的流程如下:
1) 在某個連接的第一次握手期間,雙方通過renegotiation_info擴展或SCSV套件通知對方自己支持安全重協商;
2) 在handshake過程中,client和server都分別記錄Finish消息之中的client_verify_data和server_verify_data;
3)重協商時client在ClientHello中包含client_verify_data,server在ServerHello中包含client_verify_data和server_verify_data。對於受害者,如果協商中不會攜帶這些數據則連接無法建立。由於Finished消息總是加密的,攻擊者無法得到client_verify_data和server_verify_data的值。
五、OpenSSL中的重協商(基於OpenSSL-1.1.0f)
5.1 發起重協商
5.1.1 SSL_renegotiate
Client和server只需調用SSL_renegotiate(ssl)函數即可完成發起重協商的設置。SSL_renegotiate()函數定義如下:
1641 int SSL_renegotiate(SSL *s)
1642 {
1643 if (s->renegotiate == 0)
1644 s->renegotiate = 1;
1645
1646 s->new_session = 1;
1647
1648 return (s->method->ssl_renegotiate(s));
1649 }
對於TLS_client_method()和TLS_server_method(),s->method->ssl_renegotiate指向ssl3_renegotiate():3865 int ssl3_renegotiate(SSL *s)
3866 {
3867 if (s->handshake_func == NULL)
3868 return (1);
3869
3870 if (s->s3->flags &SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)
3871 return (0);
3872
3873 s->s3->renegotiate = 1;
3874 return (1);
3875 }
可見,SSL_renegotiate()函數只是將s->s3->renegotiate設置爲1而已,並不是發送重協商報文(Handshake,HelloRequest)。發送重協商報文是在SSL_write()或SSL_read()函數被調用的時候進行的:5.1.2 發送第一個消息
先來看SSL_write()函數。對於TLS_client_method()和TLS_server_method(),SSL_write()最終都會調用ssl3_write()函數:
3816 int ssl3_write(SSL *s, const void *buf, int len)
3817 {
3818 clear_sys_error();
3819 if (s->s3->renegotiate)
3820 ssl3_renegotiate_check(s);
3821
3822 return s->method->ssl_write_bytes(s,SSL3_RT_APPLICATION_DATA, buf, len);
3823 }
由於之前調用的SSL_renegotiate()函數將s->s3->renegotiate設置爲1,故會在3820行調用到ssl3_renegotiate_check()函數:3877 int ssl3_renegotiate_check(SSL *s)
3878 {
3879 int ret = 0;
3880
3881 if (s->s3->renegotiate) {
3882 if(!RECORD_LAYER_read_pending(&s->rlayer)
3883 &&!RECORD_LAYER_write_pending(&s->rlayer)
3884 && !SSL_in_init(s)) {
3885 /*
3886 * if we are the server, and wehave sent a 'RENEGOTIATE'
3887 * message, we need to set thestate machine into the renegotiate
3888 * state.
3889 */
3890 ossl_statem_set_renegotiate(s);
3891 s->s3->renegotiate = 0;
3892 s->s3->num_renegotiations++;
3893 s->s3->total_renegotiations++;
3894 ret = 1;
3895 }
3896 }
3897 return (ret);
3898 }
其中的關鍵代碼是3890行ossl_statem_set_renegotiate()函數:103 /*
104 * Set the state machine up ready for arenegotiation handshake
105 */
106 void ossl_statem_set_renegotiate(SSL *s)
107 {
108 s->statem.state = MSG_FLOW_RENEGOTIATE;
109 s->statem.in_init = 1;
110 }
調用完ssl3_renegotiate_check()函數之後,ssl3_write()會調用s->method->ssl_write_bytes指向的ssl3_write_bytes()函數:343 int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
344 {
…
379 if (SSL_in_init(s) &&!ossl_statem_get_in_handshake(s)) {
380 i = s->handshake_func(s);
381 if (i < 0)
382 return (i);
383 if (i == 0) {
384 SSLerr(SSL_F_SSL3_WRITE_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
385 return -1;
386 }
387 }
…
其中SSL_in_init(s)的返回值會是1:69 int SSL_in_init(SSL *s)
70 {
71 return s->statem.in_init;
72 }
由於是在handshake結束之後調用,故ossl_statem_get_in_handshake(s)的返回值會是0:141 int ossl_statem_get_in_handshake(SSL *s)
142 {
143 return s->statem.in_handshake;
144 }
故ssl3_write_bytes()會執行380行s->handshake_func(s)。再來看SSL_read()。對於TLS_client_method()和TLS_server_method(),這個函數最終會調用ssl3_read():
3825 static int ssl3_read_internal(SSL *s, void *buf, int len, int peek)
3826 {
3827 int ret;
3828
3829 clear_sys_error();
3830 if (s->s3->renegotiate)
3831 ssl3_renegotiate_check(s);
3832 s->s3->in_read_app_data = 1;
3833 ret =
3834 s->method->ssl_read_bytes(s,SSL3_RT_APPLICATION_DATA, NULL, buf, len,
3835 peek);
3836 if ((ret == -1) &&(s->s3->in_read_app_data == 2)) {
3837 /*
3838 * ssl3_read_bytes decided to calls->handshake_func, which called
3839 * ssl3_read_bytes to read handshakedata. However, ssl3_read_bytes
3840 * actually found application data andthinks that application data
3841 * makes sense here; so disablehandshake processing and try to read
3842 * application data again.
3843 */
3844 ossl_statem_set_in_handshake(s, 1);
3845 ret =
3846 s->method->ssl_read_bytes(s,SSL3_RT_APPLICATION_DATA, NULL, buf,
3847 len,peek);
3848 ossl_statem_set_in_handshake(s, 0);
3849 } else
3850 s->s3->in_read_app_data = 0;
3851
3852 return (ret);
3853 }
3854
3855 int ssl3_read(SSL *s, void *buf, int len)
3856 {
3857 return ssl3_read_internal(s, buf, len, 0);
3858 }
調用SSL_renegotiate()後3831行會被執行,其影響見上文對SSL_write()函數的分析。s->method->ssl_read_bytes()指向ssl3_read_bytes():975 int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
976 int len, int peek)
977 {
…
1029 if (!ossl_statem_get_in_handshake(s)&& SSL_in_init(s)) {
1030 /* type == SSL3_RT_APPLICATION_DATA */
1031 i = s->handshake_func(s);
1032 if (i < 0)
1033 return (i);
1034 if (i == 0) {
1035 SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
1036 return (-1);
1037 }
1038 }
…
最後SSL_read()會執行1031行代碼。可見在調用SSL_renegotiate()開啓協商功能後,SSL_write()和SSL_read()都會調用s->handshake_func(s),對於client會調用到ossl_statem_connect:168 int ossl_statem_connect(SSL *s)
169 {
170 return state_machine(s, 0);
171 }
對於server則會調用ossl_statem_accept():173 int ossl_statem_accept(SSL *s)
174 {
175 return state_machine(s, 1);
176 }
它們都會調用state_machine():218 static int state_machine(SSL *s, int server)
219 {
…
276 if (st->state == MSG_FLOW_UNINITED ||st->state == MSG_FLOW_RENEGOTIATE) {
277 if (st->state == MSG_FLOW_UNINITED){
278 st->hand_state =TLS_ST_BEFORE;
279 }
280
281 s->server = server;
…
380 st->state = MSG_FLOW_WRITING;
381 init_write_state_machine(s);
382 st->read_state_first_init = 1;
383 }
384
385 while (st->state != MSG_FLOW_FINISHED){
386 if (st->state == MSG_FLOW_READING){
387 ssret = read_state_machine(s);
388 if (ssret == SUB_STATE_FINISHED) {
389 st->state =MSG_FLOW_WRITING;
390 init_write_state_machine(s);
391 } else {
392 /* NBIO or error */
393 goto end;
394 }
395 } else if (st->state ==MSG_FLOW_WRITING) {
396 ssret = write_state_machine(s);
397 if (ssret == SUB_STATE_FINISHED) {
398 st->state =MSG_FLOW_READING;
399 init_read_state_machine(s);
400 } else if (ssret ==SUB_STATE_END_HANDSHAKE) {
401 st->state =MSG_FLOW_FINISHED;
402 } else {
403 /* NBIO or error */
404 goto end;
405 }
406 } else {
407 /* Error */
408 ossl_statem_set_error(s);
409 goto end;
410 }
411 }
412
413 st->state = MSG_FLOW_UNINITED;
414 ret = 1;
由於執行了380行,故396行write_state_machine()會執行:704 static SUB_STATE_RETURN write_state_machine(SSL *s)
705 {
706 OSSL_STATEM *st = &s->statem;
707 int ret;
708 WRITE_TRAN(*transition) (SSL *s);
709 WORK_STATE(*pre_work) (SSL *s, WORK_STATEwst);
710 WORK_STATE(*post_work) (SSL *s, WORK_STATEwst);
711 int (*construct_message) (SSL *s);
712 void (*cb) (const SSL *ssl, int type, intval) = NULL;
713
714 cb = get_callback(s);
715
716 if (s->server) {
717 transition =ossl_statem_server_write_transition;
718 pre_work =ossl_statem_server_pre_work;
719 post_work =ossl_statem_server_post_work;
720 construct_message =ossl_statem_server_construct_message;
721 } else {
722 transition =ossl_statem_client_write_transition;
723 pre_work =ossl_statem_client_pre_work;
724 post_work =ossl_statem_client_post_work;
725 construct_message =ossl_statem_client_construct_message;
726 }
727
728 while (1) {
729 switch (st->write_state) {
730 case WRITE_STATE_TRANSITION:
731 if (cb != NULL) {
732 /* Notify callback of an impending statechange */
733 if (s->server)
734 cb(s, SSL_CB_ACCEPT_LOOP,1);
735 else
736 cb(s, SSL_CB_CONNECT_LOOP,1);
737 }
738 switch (transition(s)) {
739 case WRITE_TRAN_CONTINUE:
740 st->write_state =WRITE_STATE_PRE_WORK;
741 st->write_state_work =WORK_MORE_A;
742 break;
743
744 case WRITE_TRAN_FINISHED:
745 return SUB_STATE_FINISHED;
746 break;
747
748 default:
749 return SUB_STATE_ERROR;
750 }
751 break;
752
753 case WRITE_STATE_PRE_WORK:
754 switch (st->write_state_work =pre_work(s, st->write_state_work)) {
755 default:
756 return SUB_STATE_ERROR;
757
758 case WORK_FINISHED_CONTINUE:
759 st->write_state =WRITE_STATE_SEND;
760 break;
761
762 case WORK_FINISHED_STOP:
763 returnSUB_STATE_END_HANDSHAKE;
764 }
765 if (construct_message(s) == 0)
766 return SUB_STATE_ERROR;
767
768 /* Fall through */
769
770 case WRITE_STATE_SEND:
771 if (SSL_IS_DTLS(s) &&st->use_timer) {
772 dtls1_start_timer(s);
773 }
774 ret = statem_do_write(s);
775 if (ret <= 0) {
776 return SUB_STATE_ERROR;
777 }
778 st->write_state =WRITE_STATE_POST_WORK;
779 st->write_state_work =WORK_MORE_A;
780 /* Fall through */
781
782 case WRITE_STATE_POST_WORK:
783 switch (st->write_state_work =post_work(s, st->write_state_work)) {
784 default:
785 return SUB_STATE_ERROR;
786
787 case WORK_FINISHED_CONTINUE:
788 st->write_state =WRITE_STATE_TRANSITION;
789 break;
790
791 case WORK_FINISHED_STOP:
792 returnSUB_STATE_END_HANDSHAKE;
793 }
794 break;
795
796 default:
797 return SUB_STATE_ERROR;
798 }
799 }
800 }
由於state_machine ()函數在381行調用了init_write_state_machine(),使得在write_state_machine()函數的while循環中會從731行還是的WRITE_STATE_TRANSITIONcase塊開始執行(狀態變遷),然後順次執行754行開始的WRITE_STATE_PRE_WORK cse塊(構建handshake消息),771行開始的WRITE_STATE_SENDcase塊(發送handshake消息),783行開始的WRITE_STATE_POST_WORK case塊(發送消息之後的處理工作)。然後根據狀態機變遷的結果重複上述操作(安裝次序發送handshake報文)。但對於第一個重協商消息(client是ClientHello,server是HelloRequest),發送完畢後會跳出循環。這裏有一個關鍵的問題:write_state_machine()函數如何區分client和server併爲它們發送不同的重協商消息呢?主要取決於transition函數和construct_message函數的選擇。
對於client,transition =ossl_statem_client_write_transition:
273 /*
274 *client_write_transition() works out what handshake state to move to next
275 *when the client is writing messages to be sent to the server.
276 */
277 WRITE_TRAN ossl_statem_client_write_transition(SSL *s)
278 {
279 OSSL_STATEM *st = &s->statem;
280
281 switch (st->hand_state) {
282 case TLS_ST_OK:
283 /* Renegotiation - fall through */
284 case TLS_ST_BEFORE:
285 st->hand_state = TLS_ST_CW_CLNT_HELLO;
286 return WRITE_TRAN_CONTINUE;
...
在285行st->hand_state會被設置爲TLS_ST_CW_CLNT_HELLO。而construct_message= ossl_statem_client_construct_message: 513 int ossl_statem_client_construct_message(SSL *s)
514 {
515 OSSL_STATEM *st = &s->statem;
516
517 switch (st->hand_state) {
518 case TLS_ST_CW_CLNT_HELLO:
519 return tls_construct_client_hello(s);
這樣會使得client發送的第一個重協商消息爲ClientHello。對於server,transition =ossl_statem_server_write_transition:
306 /*
307 *server_write_transition() works out what handshake state to move to next
308 *when the server is writing messages to be sent to the client.
309 */
310 WRITE_TRAN ossl_statem_server_write_transition(SSL *s)
311 {
312 OSSL_STATEM *st = &s->statem;
313
314 switch (st->hand_state) {
315 case TLS_ST_BEFORE:
316 /* Just go straight to trying to read from the client */
317 return WRITE_TRAN_FINISHED;
318
319 case TLS_ST_OK:
320 /* We must be trying to renegotiate */
321 st->hand_state = TLS_ST_SW_HELLO_REQ;
322 return WRITE_TRAN_CONTINUE;
…
st->hand_state被設置爲TLS_ST_SW_HELLO_REQ。對於server,construct_message = ossl_statem_server_construct_message:
615 /*
616 *Construct a message to be sent from the server to the client.
617 *
618 *Valid return values are:
619 * 1: Success
620 * 0: Error
621 */
622 int ossl_statem_server_construct_message(SSL *s)
623 {
624 OSSL_STATEM *st = &s->statem;
625
626 switch (st->hand_state) {
627 case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
628 return dtls_construct_hello_verify_request(s);
629
630 case TLS_ST_SW_HELLO_REQ:
631 return tls_construct_hello_request(s);
…
所以server發送的第一個重協商消息是HelloRequest。5.1.3 接收重協商消息併發送後續消息
對重協商消息的接收是由SSL_read()完成的(SSL_write()函數不能接收重協商消息),它接收到的是HelloRequest或ClientHello消息,對於TLS_client_metho()和TLS_server_method(),這個函數最終會調用ssl3_read_bytes():
975 int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
976 int len, int peek)
977 {
…
1025 /*
1026 * Now s->rlayer.handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE.
1027 */
1028
1029 if (!ossl_statem_get_in_handshake(s) && SSL_in_init(s)) {
1030 /* type == SSL3_RT_APPLICATION_DATA */
1031 i = s->handshake_func(s);
1032 if (i < 0)
1033 return (i);
1034 if (i == 0) {
1035 SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE);
1036 return (-1);
1037 }
1038 }
1039 start:
1040 s->rwstate = SSL_NOTHING;
...
1260 /* If we are a client, check for an incoming 'Hello Request': */
1261 if ((!s->server) &&
1262 (s->rlayer.handshake_fragment_len >= 4) &&
1263 (s->rlayer.handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) &&
1264 (s->session != NULL) && (s->session->cipher != NULL)) {
1265 s->rlayer.handshake_fragment_len = 0;
1266
1267 if ((s->rlayer.handshake_fragment[1] != 0) ||
1268 (s->rlayer.handshake_fragment[2] != 0) ||
1269 (s->rlayer.handshake_fragment[3] != 0)) {
1270 al = SSL_AD_DECODE_ERROR;
1271 SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_BAD_HELLO_REQUEST);
1272 goto f_err;
1273 }
1274
1275 if (s->msg_callback)
1276 s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
1277 s->rlayer.handshake_fragment, 4, s,
1278 s->msg_callback_arg);
1279
1280 if (SSL_is_init_finished(s) &&
1281 !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
1282 !s->s3->renegotiate) {
1283 ssl3_renegotiate(s);
1284 if (ssl3_renegotiate_check(s)) {
1285 i = s->handshake_func(s);
1286 if (i < 0)
1287 return (i);
...
1323 /*
1324 * If we are a server and get a client hello when renegotiation isn't
1325 * allowed send back a no renegotiation alert and carry on. WARNING:
1326 * experimental code, needs reviewing (steve)
1327 */
1328 if (s->server &&
1329 SSL_is_init_finished(s) &&
1330 !s->s3->send_connection_binding &&
1331 (s->version > SSL3_VERSION) &&
1332 (s->rlayer.handshake_fragment_len >= 4) &&
1333 (s->rlayer.handshake_fragment[0] == SSL3_MT_CLIENT_HELLO) &&
1334 (s->session != NULL) && (s->session->cipher != NULL) &&
1335 !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
1336 SSL3_RECORD_set_length(rr, 0);
1337 SSL3_RECORD_set_read(rr);
1338 ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_NO_RENEGOTIATION);
1339 goto start;
1340 }
...
1429 /*
1430 * Unexpected handshake message (Client Hello, or protocol violation)
1431 */
1432 if ((s->rlayer.handshake_fragment_len >= 4)
1433 && !ossl_statem_get_in_handshake(s)) {
1434 if (SSL_is_init_finished(s) &&
1435 !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)) {
1436 ossl_statem_set_in_init(s, 1);
1437 s->renegotiate = 1;
1438 s->new_session = 1;
1439 }
1440 i = s->handshake_func(s);
1441 if (i < 0)
1442 return (i);
...
1029-1036行:如果已經處於Handshake狀態,則直接調用s->handshake_func()函數處理消息:如果收到是handshake消息則直接處理,如果是Application數據(client在發出ClientHello之後可能不會立即回覆ServerHello而是繼續發送App數據,因爲從client發出ClientHello到server收到有時間差),則i應該爲1,從而繼續後續流程。
1261-1287行:如果收到了server發送的HelloRequest,則調用ssl3_renegotiate(),然後調用ssl3_renegotiate_check()和s->handshake_func()。這個流程與client主動發起重協商的步驟是一樣的,只不過是由HelloRequest消息觸發而不是client主動設置的,不再贅述。
1328-1340行:這段代碼允許server拒絕client發起的重協商,這個功能在5.2.1節中詳細描述。
1432-1442行:Server收到ClientHello之後的處理,從中可以看出代碼也會執行到s->handshake_func()。但與server主動發起重協商的不同之處在於沒有通過調用ssl3_renegotiate_check()->ossl_statem_set_renegotiate()將s->statem.state設置爲MSG_FLOW_RENEGOTIATE,而僅僅是通過1436行的代碼將s->statem.in_init設置爲1。這樣導致server在s->handshake_func()中的處理邏輯與主動發起重協商的不同之處在於:
218 static int state_machine(SSL *s, int server)
219 {
…
276 if (st->state == MSG_FLOW_UNINITED || st->state == MSG_FLOW_RENEGOTIATE) {
277 if (st->state == MSG_FLOW_UNINITED) {
278 st->hand_state = TLS_ST_BEFORE;
279 }
280
281 s->server = server;
282 if (cb != NULL)
283 cb(s, SSL_CB_HANDSHAKE_START, 1);
...
85 while (st->state != MSG_FLOW_FINISHED) {
386 if (st->state == MSG_FLOW_READING) {
387 ssret = read_state_machine(s);
388 if (ssret == SUB_STATE_FINISHED) {
389 st->state = MSG_FLOW_WRITING;
390 init_write_state_machine(s);
391 } else {
392 /* NBIO or error */
393 goto end;
394 }
395 } else if (st->state == MSG_FLOW_WRITING) {
396 ssret = write_state_machine(s);
397 if (ssret == SUB_STATE_FINISHED) {
398 st->state = MSG_FLOW_READING;
399 init_read_state_machine(s);
400 } else if (ssret == SUB_STATE_END_HANDSHAKE) {
401 st->state = MSG_FLOW_FINISHED;
402 } else {
403 /* NBIO or error */
404 goto end;
405 }
406 } else {
407 /* Error */
408 ossl_statem_set_error(s);
409 goto end;
410 }
411 }
...
278行會被執行到,導致st->hand_state的值爲TLS_ST_BEFORE;如果是server主動發起重協商則st->hand_state的值爲TLS_ST_OK。在385-406行的處理流程中,如果st->hand_state的值爲TLS_ST_OK則server發出的是HelloRequest消息,如果是TLS_ST_BEFORE則會發ServerHello消息。這個流程的詳細分析恕不展開。
在Client端發出ClientHello之後,以及Server收到並處理完ClientHello之後,SSL_write()也可以處理後續重協商消息。SSL_write()最終會調用ssl3_write_bytes():
339 /*
340 * Call this to write data in records of type 'type' It will return <= 0 if
341 * not all data has been sent or non-blocking IO.
342 */
343 int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
344 {
345 const unsigned char *buf = buf_;
346 int tot;
347 unsigned int n, split_send_fragment, maxpipes;
...
378
379 if (SSL_in_init(s) && !ossl_statem_get_in_handshake(s)) {
380 i = s->handshake_func(s);
381 if (i < 0)
382 return (i);
383 if (i == 0) {
384 SSLerr(SSL_F_SSL3_WRITE_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE);
385 return -1;
386 }
387 }
379-385:如果已經處於Handshake狀態,則直接調用s->handshake_func()函數處理消息;如果沒有讀到handshake消息,i應該爲1,SSL_write()會繼續發送數據。5.2 安全重協商
5.2.1 安全重協商功能協商
OpenSSL 1.1的client在構建ClientHello的cipher list列表時會默認添加SSL3_CK_SCSV。它不是真正的密碼套件(它不對應於任何有效的算法集合),且無法協商。它具有與空的“renegotiation_info”擴展名相同的語義,表示支持安全重協商:
2906 int ssl_cipher_list_to_bytes(SSL *s,STACK_OF(SSL_CIPHER) *sk, unsigned char *p)
2907 {
2908 int i, j = 0;
2909 const SSL_CIPHER *c;
2910 unsigned char *q;
2911 int empty_reneg_info_scsv = !s->renegotiate;
…
2927 /*
2928 * If p == q, no ciphers; caller indicates an error. Otherwise, add
2929 * applicable SCSVs.
2930 */
2931 if (p != q) {
2932 if (empty_reneg_info_scsv) {
2933 static SSL_CIPHER scsv = {
2934 0, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0
2935 };
2936 j = s->method->put_cipher_by_char(&scsv, p);
2937 p += j;
2938 }
...
Server端在處理ClientHello時,如果發現了SSL3_CK_SCSV密碼套件,則記錄下來:3199 STACK_OF(SSL_CIPHER)* ssl_bytes_to_cipher_list(SSL *s,
3200 PACKET *cipher_suites,
3201 STACK_OF(SSL_CIPHER) **skp,
3202 int sslv2format, int *al)
3203 {
3204 const SSL_CIPHER *c;
3205 STACK_OF(SSL_CIPHER) *sk;
3206 int n;
3207 /* 3 = SSLV2_CIPHER_LEN > TLS_CIPHER_LEN = 2. */
3208 unsigned char cipher[SSLV2_CIPHER_LEN];
…
3286 /* Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV */
3287 if ((cipher[n - 2] == ((SSL3_CK_SCSV >> 8) & 0xff)) &&
3288 (cipher[n - 1] == (SSL3_CK_SCSV& 0xff))) {
3289 /* SCSV fatal if renegotiating */
3290 if (s->renegotiate) {
3291 SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST,
3292 SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING);
3293 *al =SSL_AD_HANDSHAKE_FAILURE;
3294 goto err;
3295 }
3296 s->s3->send_connection_binding = 1;
3297 continue;
3298 }
…
在發送ServerHello時添加重協商擴展:1449 unsigned char* ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
1450 unsigned char *limit, int *al)
1451 {
…
1469 if (s->s3->send_connection_binding) {
1470 int el;
1471
1472 if (!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0)) {
1473 SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT,ERR_R_INTERNAL_ERROR);
1474 return NULL;
1475 }
1476
1477 /*-
1478 * check for enough space.
1479 * 4 bytes for the reneg type andextension length
1480 * + reneg data length
1481 */
1482 if (CHECKLEN(ret, 4 + el, limit))
1483 return NULL;
1484
1485 s2n(TLSEXT_TYPE_renegotiate, ret);
1486 s2n(el, ret);
1487
1488 if (!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el)) {
1489 SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
1490 return NULL;
1491 }
1492
1493 ret += el;
1494 }
在第一次handshake時,ServerHello中的重協商擴展爲空: 76 /* Add the server's renegotiationbinding */
77int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
78 intmaxlen)
79 {
80 if (p) {
81 if ((s->s3->previous_client_finished_len +
82 s->s3->previous_server_finished_len + 1) > maxlen) {
83 SSLerr(SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT,
84 SSL_R_RENEGOTIATE_EXT_TOO_LONG);
85 return 0;
86 }
87
88 /* Length byte */
89 *p = s->s3->previous_client_finished_len +
90 s->s3->previous_server_finished_len;
91 p++;
92
93 memcpy(p, s->s3->previous_client_finished,
94 s->s3->previous_client_finished_len);
95 p += s->s3->previous_client_finished_len;
96
97 memcpy(p, s->s3->previous_server_finished,
98 s->s3->previous_server_finished_len);
99 }
100
101 *len = s->s3->previous_client_finished_len
102 + s->s3->previous_server_finished_len + 1;
103
104 return 1;
105 }
第一次handshake時s->s3->previous_client_finished_len和s->s3->previous_server_finished_len都爲0,故重協商擴展的長度爲1字節。
5.2.2 安全重協商功能使用
在client和server構建FINISHED消息時,會分別保存各自消息的Hash值:
60int tls_construct_finished(SSL *s, const char *sender, int slen)
61{
62 unsigned char *p;
63 int i;
64 unsigned long l;
65
66 p = ssl_handshake_start(s);
67
68 i =s->method->ssl3_enc->final_finish_mac(s,
69 sender, slen,
70 s->s3->tmp.finish_md);
71 if (i <= 0)
72 return 0;
73 s->s3->tmp.finish_md_len = i;
74 memcpy(p,s->s3->tmp.finish_md, i);
75 l = i;
76
77 /*
78 * Copy the finished so wecan use it for renegotiation checks
79 */
80 if (!s->server) {
81 OPENSSL_assert(i <=EVP_MAX_MD_SIZE);
82 memcpy(s->s3->previous_client_finished,s->s3->tmp.finish_md, i);
83 s->s3->previous_client_finished_len= i;
84 } else {
85 OPENSSL_assert(i <=EVP_MAX_MD_SIZE);
86 memcpy(s->s3->previous_server_finished,s->s3->tmp.finish_md, i);
87 s->s3->previous_server_finished_len = i;
88 }
…
在client和server收到FINISHED消息時,會分別保存對方消息的Hash值:
195 MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt)
196 {
197 int al, i;
198
199 /* If this occurs, we have missed a message */
200 if (!s->s3->change_cipher_spec) {
201 al = SSL_AD_UNEXPECTED_MESSAGE;
202 SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_GOT_A_FIN_BEFORE_A_CCS);
203 goto f_err;
204 }
205 s->s3->change_cipher_spec = 0;
206
207 i = s->s3->tmp.peer_finish_md_len;
208
209 if ((unsigned long)i != PACKET_remaining(pkt)) {
210 al = SSL_AD_DECODE_ERROR;
211 SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_BAD_DIGEST_LENGTH);
212 goto f_err;
213 }
214
215 if (CRYPTO_memcmp(PACKET_data(pkt), s->s3->tmp.peer_finish_md, i) != 0) {
216 al = SSL_AD_DECRYPT_ERROR;
217 SSLerr(SSL_F_TLS_PROCESS_FINISHED, SSL_R_DIGEST_CHECK_FAILED);
218 goto f_err;
219 }
220
221 /*
222 * Copy the finished so we can use it for renegotiation checks
223 */
224 if (s->server) {
225 OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
226 memcpy(s->s3->previous_client_finished, s->s3->tmp.peer_finish_md, i);
227 s->s3->previous_client_finished_len = i;
228 } else {
229 OPENSSL_assert(i <= EVP_MAX_MD_SIZE);
230 memcpy(s->s3->previous_server_finished, s->s3->tmp.peer_finish_md, i);
231 s->s3->previous_server_finished_len = i;
232 }
233
234 return MSG_PROCESS_FINISHED_READING;
235 f_err:
236 ssl3_send_alert(s, SSL3_AL_FATAL, al);
237 ossl_statem_set_error(s);
238 return MSG_PROCESS_ERROR;
239 }
在發起重協商時,client會在ClientHello中添加重協商擴展: 968 unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf,
969 unsigned char *limit, int *al)
970 {
...
1001 /* Add RI if renegotiating */
1002 if (s->renegotiate) {
1003 int el;
1004
1005 if (!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0)) {
1006 SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
1007 return NULL;
1008 }
1009
1010 if (CHECKLEN(ret, 4 + el, limit))
1011 return NULL;
1012
1013 s2n(TLSEXT_TYPE_renegotiate, ret);
1014 s2n(el, ret);
1015
1016 if (!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el)) {
1017 SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
1018 return NULL;
1019 }
1020
1021 ret += el;
1022 }
...
在這個擴展中client只添加client_finished信息,這與RFC 5746的要求一致: 14 /* Add the client's renegotiationbinding */
15int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len,
16 intmaxlen)
17{
18 if (p) {
19 if ((s->s3->previous_client_finished_len + 1) > maxlen) {
20 SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT,
21 SSL_R_RENEGOTIATE_EXT_TOO_LONG);
22 return 0;
23 }
24
25 /* Length byte */
26 *p = s->s3->previous_client_finished_len;
27 p++;
28
29 memcpy(p, s->s3->previous_client_finished,
30 s->s3->previous_client_finished_len);
31 }
32
33 *len = s->s3->previous_client_finished_len + 1;
34
35 return 1;
36 }
Server收到ClientHello後會檢查重協商擴展:1890 static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al)
1891 {
1892 unsigned int type;
1893 int renegotiate_seen = 0;
1894 PACKET extensions;
…
1955 if (type == TLSEXT_TYPE_renegotiate) {
1956 if(!ssl_parse_clienthello_renegotiate_ext(s, &extension, al))
1957 return 0;
1958 renegotiate_seen = 1;
…
2300 /* Need RI if renegotiating */
2301
2302 if (!renegotiate_seen && s->renegotiate &&
2303 !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
2304 *al = SSL_AD_HANDSHAKE_FAILURE;
2305 SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT,
2306 SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
2307 return 0;
2308 }
第2302-2307行:如果沒有發現重協商擴展或重協商擴展檢查不通過,則renegotiate_seen爲0;如果renegotiate_seen爲0,處於重協商過程中,沒有“設置允許使用不安全重協商”,這三個條件同時滿足,則中止handshake。根據RFC 5746的要求,Server需要檢查client finished信息:
38 /*
39 * Parse the client's renegotiation binding and abort if it's not right
40 */
41 int ssl_parse_clienthello_renegotiate_ext(SSL *s, PACKET *pkt, int *al)
42 {
43 unsigned int ilen;
44 const unsigned char *d;
45
46 /* Parse the length byte */
47 if (!PACKET_get_1(pkt, &ilen)
48 || !PACKET_get_bytes(pkt, &d, ilen)) {
49 SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,
50 SSL_R_RENEGOTIATION_ENCODING_ERR);
51 *al = SSL_AD_ILLEGAL_PARAMETER;
52 return 0;
53 }
54
55 /* Check that the extension matches */
56 if (ilen != s->s3->previous_client_finished_len) {
57 SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,
58 SSL_R_RENEGOTIATION_MISMATCH);
59 *al = SSL_AD_HANDSHAKE_FAILURE;
60 return 0;
61 }
62
63 if (memcmp(d, s->s3->previous_client_finished,
64 s->s3->previous_client_finished_len)) {
65 SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,
66 SSL_R_RENEGOTIATION_MISMATCH);
67 *al = SSL_AD_HANDSHAKE_FAILURE;
68 return 0;
69 }
70
71 s->s3->send_connection_binding = 1;
72
73 return 1;
74 }
檢查通過則重協商handshake正常進行。後續Server會發送ServerHello,並在其中的重協商擴展中添加上次handshake保存的client finished和server finished信息。詳見:ssl_add_serverhello_renegotiate_ext()。Client在收到ServerHello後的會解析重協商擴展:
2354 static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al)
2355 {
2356 unsigned int length, type, size;
2357 int tlsext_servername = 0;
2358 int renegotiate_seen = 0;
…
2400 if (type == TLSEXT_TYPE_renegotiate) {
2401 if(!ssl_parse_serverhello_renegotiate_ext(s, &spkt, al))
2402 return 0;
2403 renegotiate_seen = 1;
…
2626 ri_check:
2627
2628 /*
2629 * Determine if we need to see RI. Strictly speaking if we want to avoid
2630 * an attack we should *always* see RI even on initial server hello
2631 * because the client doesn't see any renegotiation during an attack.
2632 * However this would mean we could not connect to any server which
2633 * doesn't support RI so for the immediate future tolerate RI absence
2634 */
2635 if (!renegotiate_seen && !(s->options &SSL_OP_LEGACY_SERVER_CONNECT)
2636 && !(s->options &SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
2637 *al = SSL_AD_HANDSHAKE_FAILURE;
2638 SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT,
2639 SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
2640 return 0;
2641 }
…
2635-2640行:如果沒有發現重協商擴展或重協商擴展檢查不通過,則renegotiate_seen爲0;如果renegotiate_seen爲0,沒有設置“允許server不支持重協商”(此標籤默認設置),沒有設置“允許使用不安全重協商”,這三個條件同時滿足,則中止handshake。Client在檢查重協商擴展時,如果擴展的內容爲0(第一次handshake)則只是做個標記,如果非空則對比client_finished和server_finished消息:
107 /*
108 * Parse the server's renegotiation binding and abort if it's not right
109 */
110 int ssl_parse_serverhello_renegotiate_ext(SSL *s, PACKET *pkt, int *al)
111 {
112 unsigned int expected_len = s->s3->previous_client_finished_len
113 + s->s3->previous_server_finished_len;
114 unsigned int ilen;
115 const unsigned char *data;
116
117 /* Check for logic errors */
118 OPENSSL_assert(!expected_len || s->s3->previous_client_finished_len);
119 OPENSSL_assert(!expected_len || s->s3->previous_server_finished_len);
120
121 /* Parse the length byte */
122 if (!PACKET_get_1(pkt, &ilen)) {
123 SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,
124 SSL_R_RENEGOTIATION_ENCODING_ERR);
125 *al = SSL_AD_ILLEGAL_PARAMETER;
126 return 0;
127 }
128
129 /* Consistency check */
130 if (PACKET_remaining(pkt) != ilen) {
131 SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,
132 SSL_R_RENEGOTIATION_ENCODING_ERR);
133 *al = SSL_AD_ILLEGAL_PARAMETER;
134 return 0;
135 }
136
137 /* Check that the extension matches */
138 if (ilen != expected_len) {
139 SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,
140 SSL_R_RENEGOTIATION_MISMATCH);
141 *al = SSL_AD_HANDSHAKE_FAILURE;
142 return 0;
143 }
144
145 if (!PACKET_get_bytes(pkt, &data, s->s3->previous_client_finished_len)
146 || memcmp(data, s->s3->previous_client_finished,
147 s->s3->previous_client_finished_len) != 0) {
148 SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,
149 SSL_R_RENEGOTIATION_MISMATCH);
150 *al = SSL_AD_HANDSHAKE_FAILURE;
151 return 0;
152 }
153
154 if (!PACKET_get_bytes(pkt, &data, s->s3->previous_server_finished_len)
155 || memcmp(data, s->s3->previous_server_finished,
156 s->s3->previous_server_finished_len) != 0) {
157 SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,
158 SSL_R_RENEGOTIATION_MISMATCH);
159 *al = SSL_AD_ILLEGAL_PARAMETER;
160 return 0;
161 }
162 s->s3->send_connection_binding = 1;
163
164 return 1;
165 }
如果檢查通過則執行正常的handshake流程。在handshake的最後階段雙方會用本次會話中的FINISHED消息的hash值刷新各自的client_finished和server_finished緩存,留待下次重協商時使用。 六、重協商功能配置策略
6.1 Server禁止|限制client發起重協商
OpenSSL1.1在handshake過程中設置了一個call_back點,允許用戶通過call_back函數來實現定製的操作:
218 static int state_machine(SSL *s, intserver)
219 {
220 BUF_MEM *buf = NULL;
221 unsigned long Time = (unsigned long)time(NULL);
222 void (*cb) (const SSL *ssl, int type, int val) = NULL;
…
236 cb = get_callback(s);
…
276 if (st->state == MSG_FLOW_UNINITED || st->state ==MSG_FLOW_RENEGOTIATE) {
277 if (st->state == MSG_FLOW_UNINITED) {
278 st->hand_state = TLS_ST_BEFORE;
279 }
280
281 s->server = server;
282 if (cb != NULL)
283 cb(s, SSL_CB_HANDSHAKE_START, 1);
…
由這段代碼和5.1.3節中的分析可知,第一次handshake和重協商的handshake都會執行一次283行的call_back函數(如果是server發起的重協商,在發送HelloRequest時也會執行一次call_back)。故可以通過SSL_CTX_set_info_callback(SSL_CTX *ctx, void (*cb) (const SSL *ssl,int type, int val))函數設置call back函數,在server端實現對client發起的重協商進行次數|頻率的限制。Call_back函數舉例:
static void
dv_handshake_callback(const SSL *ssl, int type, int val)
{
...
if (type == SSL_CB_HANDSHAKE_START) {
...
}
...
}
6.2 徹底禁用重協商
從5.1節的代碼可以得知,如果設置SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS標籤,則client和server都不能發起重協商也不能處理重協商消息:
s->s3->flags& SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS
對於OpenSSL 1.0,上述方法沒有問題,但對於OpenSSL1.1,由於結構體的定義被隱藏,而且沒有發現任何能夠設置s->s3->flags的接口,導致OpenSSL的用戶無法直接設置這個標籤,從而無法完全禁用重協商功能(可以使用6.1節中介紹的call_back機制來禁止對端發起重協商)。對此個人的理解是由於OpenSSL 1.1默認開啓安全重協商功能,使得開啓重協商功能帶來的安全威脅大大緩解;而且禁用重協商的代價比較大,故不允許用戶禁用重協商功能。SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS標籤可能留待內部使用。
對於Client,設置此標籤可以忽略Server發來的HelloRequest請求,忽略之後對雙方的數據交互沒有影響;如果Server設置了此標籤,則會忽略Client發送的ClientHello,但Client會一直處於“等待”ServerHello的狀態從而無法發送和接收應用數據。
不推薦此選項。
6.3 允許不安全的重協商
6.3.1 Server端允許不安全的重協商
不支持安全重協商的client在發送ClientHello時不會攜帶SSL3_CK_SCSV密碼族,默認情況下無論是client還是server發起重協商都是不允許的:
Server發送HelloRequest:
218 static int state_machine(SSL *s, intserver)
219 {
…
342 if (server) {
343 if (st->state !=MSG_FLOW_RENEGOTIATE) {
344 s->ctx->stats.sess_accept++;
345 } else if(!s->s3->send_connection_binding &&
346 !(s->options &
347 SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
348 /*
349 * Server attempting torenegotiate with client that doesn't
350 * support securerenegotiation.
351 */
352 SSLerr(SSL_F_STATE_MACHINE,
353 SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
354 ssl3_send_alert(s,SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
355 ossl_statem_set_error(s);
356 goto end;
..
Server接收重協商的ClientHello: 975 int ssl3_read_bytes(SSL *s, int type,int *recvd_type, unsigned char *buf,
976 int len, int peek)
977{
…
1323 /*
1324 * If we are a server and get a client hello when renegotiation isn't
1325 * allowed send back a no renegotiation alert and carry on. WARNING:
1326 * experimental code, needs reviewing (steve)
1327 */
1328 if (s->server &&
1329 SSL_is_init_finished(s) &&
1330 !s->s3->send_connection_binding &&
1331 (s->version > SSL3_VERSION) &&
1332 (s->rlayer.handshake_fragment_len >= 4) &&
1333 (s->rlayer.handshake_fragment[0] == SSL3_MT_CLIENT_HELLO) &&
1334 (s->session != NULL) && (s->session->cipher != NULL)&&
1335 !(s->ctx->options &SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
1336 SSL3_RECORD_set_length(rr, 0);
1337 SSL3_RECORD_set_read(rr);
1338 ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_NO_RENEGOTIATION);
1339 goto start;
1340 }
…
SSL_is_init_finished(s) 爲真意味着第一次handshake已經結束,s->s3->send_connection_binding爲0表示server沒有在ClientHello中發現SCSV密碼族或安全重協商擴展,這兩個條件同時成立意味着server收到的重協商請求(ClientHello)中沒有安全重協商信息。這時需要發送NO_RENEGOTIATION Alert。
如果在重協商的過程中(server 發起重協商),ClientHello中沒有重協商擴展也是不被允許的:
1890 static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al)
1891 {
…
2302 if (!renegotiate_seen && s->renegotiate &&
2303 !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
2304 *al = SSL_AD_HANDSHAKE_FAILURE;
2305 SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT,
2306 SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
2307 return 0;
2308 }
…
由代碼中也可以看出,如果:s->options& SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION爲真,則上述兩種情況下的不安全重協商都是允許的。這個設置可以通過:
SSL_set_options(s,SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
實現。
不推薦此選項。
6.3.2 Client端允許不安全的重協商
與server端不同,client默認允許不安全的重協商。原因是在針對重協商的攻擊中client並未參與重協商流程,如果默認禁止連接所有不支持安全重協商的server則代價太大。
接收ServerHello:
2354 static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al)
2355 {
…
2628 /*
2629 * Determine if we need to see RI. Strictly speaking if we want to avoid
2630 * an attack we should *always* see RI even on initial server hello
2631 * because the client doesn't see any renegotiation during an attack.
2632 * However this would mean we could not connect to any server which
2633 * doesn't support RI so for the immediate future tolerate RI absence
2634 */
2635 if (!renegotiate_seen && !(s->options &SSL_OP_LEGACY_SERVER_CONNECT)
2636 && !(s->options &SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
2637 *al = SSL_AD_HANDSHAKE_FAILURE;
2638 SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT,
2639 SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
2640 return 0;
2641 }
s->options& SSL_OP_LEGACY_SERVER_CONNECT默認爲真:
2349 SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
2350 {
…
2469 /*
2470 * Default is to connect to non-RI servers. When RI is more widely
2471 * deployed might change this.
2472 */
2473 ret->options |= SSL_OP_LEGACY_SERVER_CONNECT;
…
故client默認不會拒絕不支持安全重協商的server。要取消此默認設置可以調用:SSL_CTX_clear_options(ctx,SSL_OP_LEGACY_SERVER_CONNECT);
用戶可根據自身情況設置默認策略。
6.4 Client禁止發起重協商
由於Client發起重協商的條件不明,而且這種應用方式基本絕跡,故建議Client不要支持發起重協商。