2007年6月29日星期五

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

SSL连接建立过程分析(4)
 
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn

2.13 SSL_connect
 
SSL_connect()这个函数完成SSL协商的客户端操作:

/* ssl/ssl_lib.c */
int SSL_connect(SSL *s)
 {
 if (s->handshake_func == 0)
  /* Not properly initialized yet */
  SSL_set_connect_state(s);
 return(s->method->ssl_connect(s));
 }

其中SSL_set_connect_state(s)函数初始化SSL协商处理:

void SSL_set_connect_state(SSL *s)
 {
// 客户端
 s->server=0;
 s->shutdown=0;
// 初始化客户端状态值
 s->state=SSL_ST_CONNECT|SSL_ST_BEFORE;
// 握手函数即是ssl_connect函数
 s->handshake_func=s->method->ssl_connect;
 /* clear the current cipher */
// 清除SSL读写加密算法上下文
 ssl_clear_cipher_ctx(s);
 }

因此最重要的就是ssl_connect()这两个成员函数,是前面SSLv[2][3]_client_method()函数中定义 的,如对于SSLv23方法,处理函数分别为ssl23_connect()函数,其它SSLv2和SSLv3方法分别对应ssl2_connect() 和ssl3_connect(),后两者就没有协商过程了,ssl23_connect()实际在协商确定协议版本后也是调用ssl2[3] _connect()。掌握了服务器端的accept过程,理解客户端的connect过程就简单了。

/* ssl/s23_clnt.c */
int ssl23_connect(SSL *s)
 {
 BUF_MEM *buf=NULL;
 unsigned long Time=time(NULL);
 void (*cb)(const SSL *ssl,int type,int val)=NULL;
 int ret= -1;
 int new_state,state;
// 和服务器端一样进行基本的初始化
 RAND_add(&Time,sizeof(Time),0);
 ERR_clear_error();
 clear_sys_error();
 if (s->info_callback != NULL)
  cb=s->info_callback;
 else if (s->ctx->info_callback != NULL)
  cb=s->ctx->info_callback;

 s->in_handshake++;
 if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
 for (;;)
  {
  state=s->state;
// 在SSL_set_connect_state中s->state被初始化为SSL_ST_CONNECT|SSL_ST_BEFORE
  switch(s->state)
   {
  case SSL_ST_BEFORE:
  case SSL_ST_CONNECT:
  case SSL_ST_BEFORE|SSL_ST_CONNECT:
  case SSL_ST_OK|SSL_ST_CONNECT:
// 进行基本初始化,分配缓冲区
   if (s->session != NULL)
    {
    SSLerr(SSL_F_SSL23_CONNECT,SSL_R_SSL23_DOING_SESSION_ID_REUSE);
    ret= -1;
    goto end;
    }
   s->server=0;
   if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
   /* s->version=TLS1_VERSION; */
   s->type=SSL_ST_CONNECT;
   if (s->init_buf == NULL)
    {
    if ((buf=BUF_MEM_new()) == NULL)
     {
     ret= -1;
     goto end;
     }
    if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH))
     {
     ret= -1;
     goto end;
     }
    s->init_buf=buf;
    buf=NULL;
    }
   if (!ssl3_setup_buffers(s)) { ret= -1; goto end; }
   ssl3_init_finished_mac(s);
// SSL客户端状态转为准备发送HELLO信息
   s->state=SSL23_ST_CW_CLNT_HELLO_A;
   s->ctx->stats.sess_connect++;
   s->init_num=0;
   break;
  case SSL23_ST_CW_CLNT_HELLO_A:
  case SSL23_ST_CW_CLNT_HELLO_B:
// 发送客户端的HELLO信息
   s->shutdown=0;
   ret=ssl23_client_hello(s);
   if (ret <= 0) goto end;
// 转为准备接收服务器端的HELLO状态
   s->state=SSL23_ST_CR_SRVR_HELLO_A;
   s->init_num=0;
   break;
  case SSL23_ST_CR_SRVR_HELLO_A:
  case SSL23_ST_CR_SRVR_HELLO_B:
// 读取服务器端的HELLO信息,完成SSL握手协商
   ret=ssl23_get_server_hello(s);
   if (ret >= 0) cb=NULL;
   goto end;
   /* break; */
  default:
   SSLerr(SSL_F_SSL23_CONNECT,SSL_R_UNKNOWN_STATE);
   ret= -1;
   goto end;
   /* break; */
   }
  if (s->debug) { (void)BIO_flush(s->wbio); }
  if ((cb != NULL) && (s->state != state))
   {
   new_state=s->state;
   s->state=state;
   cb(s,SSL_CB_CONNECT_LOOP,1);
   s->state=new_state;
   }
  }
end:
 s->in_handshake--;
 if (buf != NULL)
  BUF_MEM_free(buf);
 if (cb != NULL)
  cb(s,SSL_CB_CONNECT_EXIT,ret);
 return(ret);
 }
 
ssl23_client_hello()函数发送客户端的HELLO信息:

/* ssl/s23_clnt.c */
static int ssl23_client_hello(SSL *s)
 {
 unsigned char *buf;
 unsigned char *p,*d;
 int i,ch_len;
 int ret;
 buf=(unsigned char *)s->init_buf->data;
 if (s->state == SSL23_ST_CW_CLNT_HELLO_A)
  {
// 准备发送HELLO, 构造发送缓冲区的数据,数据格式见SSL_accept一节中的说明
  p=s->s3->client_random;
  RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE);
  /* Do the message type and length last */
  d= &(buf[2]);
// p指向SSL握手记录头(11字节长)后的第一字节处
  p=d+9;
// 消息类型
  *(d++)=SSL2_MT_CLIENT_HELLO;
// 填写客户端版本号
  if (!(s->options & SSL_OP_NO_TLSv1))
   {
   *(d++)=TLS1_VERSION_MAJOR;
   *(d++)=TLS1_VERSION_MINOR;
   s->client_version=TLS1_VERSION;
   }
  else if (!(s->options & SSL_OP_NO_SSLv3))
   {
   *(d++)=SSL3_VERSION_MAJOR;
   *(d++)=SSL3_VERSION_MINOR;
   s->client_version=SSL3_VERSION;
   }
  else if (!(s->options & SSL_OP_NO_SSLv2))
   {
   *(d++)=SSL2_VERSION_MAJOR;
   *(d++)=SSL2_VERSION_MINOR;
   s->client_version=SSL2_VERSION;
   }
  else
   {
   SSLerr(SSL_F_SSL23_CLIENT_HELLO,SSL_R_NO_PROTOCOLS_AVAILABLE);
   return(-1);
   }
// 填写cipher_specs信息
  /* Ciphers supported */
  i=ssl_cipher_list_to_bytes(s,SSL_get_ciphers(s),p);
  if (i == 0)
   {
   /* no ciphers */
   SSLerr(SSL_F_SSL23_CLIENT_HELLO,SSL_R_NO_CIPHERS_AVAILABLE);
   return(-1);
   }
  s2n(i,d);
  p+=i;
// 填写会话ID
  /* put in the session-id, zero since there is no
   * reuse. */
  s2n(0,d);
  if (s->options & SSL_OP_NETSCAPE_CHALLENGE_BUG)
   ch_len=SSL2_CHALLENGE_LENGTH;
  else
   ch_len=SSL2_MAX_CHALLENGE_LENGTH;
// 填写挑战信息
  /* write out sslv2 challenge */
  if (SSL3_RANDOM_SIZE < ch_len)
   i=SSL3_RANDOM_SIZE;
  else
   i=ch_len;
  s2n(i,d);
  memset(&(s->s3->client_random[0]),0,SSL3_RANDOM_SIZE);
  RAND_pseudo_bytes(&(s->s3->client_random[SSL3_RANDOM_SIZE-i]),i);
  memcpy(p,&(s->s3->client_random[SSL3_RANDOM_SIZE-i]),i);
  p+=i;
// 数据长度
  i= p- &(buf[2]);
  buf[0]=((i>>8)&0xff)|0x80;
  buf[1]=(i&0xff);
// 数据完成,状态转为HELLO B准备发送
  s->state=SSL23_ST_CW_CLNT_HELLO_B;
  /* number of bytes to write */
  s->init_num=i+2;
  s->init_off=0;
  ssl3_finish_mac(s,&(buf[2]),i);
  }
 /* SSL3_ST_CW_CLNT_HELLO_B */
// 发送HELLO数据
 ret = ssl23_write_bytes(s);
 if (ret >= 2)
  if (s->msg_callback)
   s->msg_callback(1, SSL2_VERSION, 0, s->init_buf->data+2, ret-2, s, s->msg_callback_arg); /* CLIENT-HELLO */
 return ret;
 }

ssl23_get_server_hello()接收服务器端的回应,识别服务器的SSL版本,最后再相应调用ssl2_connect()或ssl3_connect()函数。

/* ssl/s23_clnt.c */
static int ssl23_get_server_hello(SSL *s)
 {
 char buf[8];
 unsigned char *p;
 int i;
 int n;
// 读7字节的服务器端数据
 n=ssl23_read_bytes(s,7);
 if (n != 7) return(n);
 p=s->packet;
 memcpy(buf,p,n);
 if ((p[0] & 0x80) && (p[2] == SSL2_MT_SERVER_HELLO) &&
  (p[5] == 0x00) && (p[6] == 0x02))
  {
// 服务器是SSL2版本
#ifdef OPENSSL_NO_SSL2
  SSLerr(SSL_F_SSL23_GET_SERVER_HELLO,SSL_R_UNSUPPORTED_PROTOCOL);
  goto err;
#else
  /* we are talking sslv2 */
  /* we need to clean up the SSLv3 setup and put in the
   * sslv2 stuff. */
  int ch_len;
  if (s->options & SSL_OP_NO_SSLv2)
   {
   SSLerr(SSL_F_SSL23_GET_SERVER_HELLO,SSL_R_UNSUPPORTED_PROTOCOL);
   goto err;
   }
// 初始化SSL结构中的SSL2支持,ssl_connect将为ssl2_connect
  if (s->s2 == NULL)
   {
   if (!ssl2_new(s))
    goto err;
   }
  else
   ssl2_clear(s);
  if (s->options & SSL_OP_NETSCAPE_CHALLENGE_BUG)
   ch_len=SSL2_CHALLENGE_LENGTH;
  else
   ch_len=SSL2_MAX_CHALLENGE_LENGTH;
  /* write out sslv2 challenge */
  i=(SSL3_RANDOM_SIZE < ch_len)
   ?SSL3_RANDOM_SIZE:ch_len;
  s->s2->challenge_length=i;
  memcpy(s->s2->challenge,
   &(s->s3->client_random[SSL3_RANDOM_SIZE-i]),i);
  if (s->s3 != NULL) ssl3_free(s);
  if (!BUF_MEM_grow_clean(s->init_buf,
   SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER))
   {
   SSLerr(SSL_F_SSL23_GET_SERVER_HELLO,ERR_R_BUF_LIB);
   goto err;
   }
  s->state=SSL2_ST_GET_SERVER_HELLO_A;
  if (!(s->client_version == SSL2_VERSION))
   /* use special padding (SSL 3.0 draft/RFC 2246, App. E.2) */
   s->s2->ssl2_rollback=1;
  /* setup the 5 bytes we have read so we get them from
   * the sslv2 buffer */
  s->rstate=SSL_ST_READ_HEADER;
  s->packet_length=n;
  s->packet= &(s->s2->rbuf[0]);
  memcpy(s->packet,buf,n);
  s->s2->rbuf_left=n;
  s->s2->rbuf_offs=0;
  /* we have already written one */
  s->s2->write_sequence=1;
  s->method=SSLv2_client_method();
  s->handshake_func=s->method->ssl_connect;

没有评论: