OpenSSL-TLS重协商
来源:互联网 发布:玫琳凯经销商收入算法 编辑:程序博客网 时间:2024/06/06 05:30
一、什么是重协商
大部分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;16451646 s->new_session = 1; 16471648 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);38693870 if (s->s3->flags &SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)3871 return (0);38723873 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); 38213822 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;38803881 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 renegotiate3888 * 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 handshake105 */ 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_metho()和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 called3839 * ssl3_read_bytes to read handshakedata. However, ssl3_read_bytes3840 * actually found application data andthinks that application data3841 * makes sense here; so disablehandshake processing and try to read3842 * 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 } else3850 s->s3->in_read_app_data = 0;3851 3852 return (ret);3853 }38543855 intssl3_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 }280281 s->server = server;…380 st->state = MSG_FLOW_WRITING;381 init_write_state_machine(s);382 st->read_state_first_init = 1;383 }384385 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 }412413 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;713714 cb = get_callback(s);715716 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 else736 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;747748 default:749 return SUB_STATE_ERROR;750 }751 break;752753 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;757758 case WORK_FINISHED_CONTINUE:759 st->write_state =WRITE_STATE_SEND;760 break;761762 case WORK_FINISHED_STOP:763 returnSUB_STATE_END_HANDSHAKE;764 }765 if (construct_message(s) == 0)766 return SUB_STATE_ERROR;767768 /* Fall through */769770 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 */781782 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;786787 case WORK_FINISHED_CONTINUE:788 st->write_state =WRITE_STATE_TRANSITION;789 break;790791 case WORK_FINISHED_STOP:792 returnSUB_STATE_END_HANDSHAKE;793 }794 break;795796 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 {…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't1325 * 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);...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消息。这个流程的详细分析恕不展开。
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, add2929 * 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, 02935 };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; 14711472 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 }14761477 /*-1478 * check for enough space.1479 * 4 bytes for the reneg type andextension length1480 * + reneg data length1481 */1482 if (CHECKLEN(ret, 4 + el, limit)) 1483 return NULL;14841485 s2n(TLSEXT_TYPE_renegotiate, ret);1486 s2n(el, ret); 14871488 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 }14921493 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 }100101 *len = s->s3->previous_client_finished_len102 + s->s3->previous_server_finished_len + 1;103104 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 */ 23012302 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: 26272628 /* 2629 * Determine if we need to see RI. Strictly speaking if we want to avoid2630 * an attack we should *always* see RI even on initial server hello2631 * because the client doesn't see any renegotiation during an attack.2632 * However this would mean we could not connect to any server which2633 * doesn't support RI so for the immediate future tolerate RI absence2634 */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 right109 */110 int ssl_parse_serverhello_renegotiate_ext(SSL *s, PACKET *pkt, int *al)111 {112 unsigned int expected_len = s->s3->previous_client_finished_len113 + 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 }280281 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't350 * 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't1325 * 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 avoid2630 * an attack we should *always* see RI even on initial server hello2631 * because the client doesn't see any renegotiation during an attack.2632 * However this would mean we could not connect to any server which2633 * doesn't support RI so for the immediate future tolerate RI absence2634 */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 widely2471 * 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不要支持发起重协商。
- OpenSSL-TLS重协商
- 干货|白话SSL/TLS默认重协商漏洞原理与安全重协商对抗机制
- openssl DH密钥协商
- SSL/TLS协商过程详解
- TLS握手协商流程解析
- OpenSSL握手重协商过程中存在漏洞可导致拒绝服务
- SSL/TLS密钥协商(握手)过程
- TLS重新协商显示扩展,RFC5746
- openssl 学习之SSL/TLS
- openssl 学习之SSL/TLS
- SSL VPN (原理三 重协商)
- OpenSSL引擎机制与加密套件协商的应用研究
- 用openssl编写SSL,TLS程序
- 用openssl编写SSL,TLS程序
- 用openssl编写SSL,TLS程序
- 用OpenSSL编写SSL,TLS程序
- 用openssl编写SSL,TLS程序
- 用OpenSSL编写SSL,TLS程序(1)
- PHP 关于无符号整形Unsigned
- Java设计模式--解释器模式【Interpreter Pattern】
- HTML5新特性教程
- 修改gif图片文件大小
- 绑定小程序数据助手,查看小程序的统计数据-微信小程序开发-视频教程22
- OpenSSL-TLS重协商
- 友盟,错误分析工具的使用
- JS宝典学习笔记
- HTML标签
- C语言程序设计习题1-19 编写函数reverse(s),实现字符串的倒序,并用该函数每次颠倒一个输入行中的字符顺序
- spriing boot 启动报错:Cannot determine embedded database driver class for database type NONE
- 【C语言】if else
- C# SplitContainer 控件详细用法
- 【distinct-subsequences】