OpenSSL-TLS重協商

一、什麼是重協商

    大部分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不要支持發起重協商。

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