2007年6月29日星期五

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

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++;
// 重新读数据
  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++ = *src++;
   len--; s->s3->handshake_fragment_len--;
   n++;
   }
  /* move any remaining fragment bytes: */
  for (k = 0; k < s->s3->handshake_fragment_len; k++)
   s->s3->handshake_fragment[k] = *src++;
  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[rr->off]),n);
  if (!peek)
   {
// 如果不是peek,移动记录缓冲的数据偏移指针,长度减
   rr->length-=n;
   rr->off+=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)++] = rr->data[rr->off++];
    rr->length--;
    }
   if (*dest_len < dest_maxlen)
    goto start; /* fragment was too small */
   }
  }
 /* s->s3->handshake_fragment_len == 4  iff  rr->type == SSL3_RT_HANDSHAKE;
  * s->s3->alert_fragment_len == 2      iff  rr->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[0] == SSL3_MT_HELLO_REQUEST) &&
  (s->session != NULL) && (s->session->cipher != NULL))
  {
// 本地是客户端
// 握手碎片长度至少是4字节, 类型是HELLO的握手信息时进行处理
  s->s3->handshake_fragment_len = 0;
  if ((s->s3->handshake_fragment[1] != 0) ||
   (s->s3->handshake_fragment[2] != 0) ||
   (s->s3->handshake_fragment[3] != 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[0];
  int alert_descr = s->s3->alert_fragment[1];
  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[16];
   s->rwstate=SSL_NOTHING;
   s->s3->fatal_alert = alert_descr;
   SSLerr(SSL_F_SSL3_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr);
   BIO_snprintf(tmp,sizeof tmp,"%d",alert_descr);
   ERR_add_error_data(2,"SSL alert number ",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[0] != 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;

没有评论: