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合并处理,从而使得攻击成功。

    攻击过程(举例)的示意图如下:

OpenSSL-TLS重协商_第1张图片

    这种攻击会使得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不要支持发起重协商。

你可能感兴趣的:(密码学,SSL/TLS)