2007年6月29日星期五

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


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

2.6 SSL_CTX_set_default_passwd_cb[_userdata]()

这个函数比较简单,就是设置SSL要加载的证书的口令,如果不设置的话加载证书时会出提示符要求输入口令的,这样在程序中使用就比较麻烦,该函数就是预先将口令保存,在读证书时自动使用。

实现该功能的有两个函数SSL_CTX_set_default_passwd_cb()和SSL_CTX_set_default_passwd_cb_userdata(),前者是定义一个口令回调函数,要获取口令时口令由该函数获取;后者是直接将口令设置好。

/* ssl/ssl_lib.c */
void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb)
 {
 ctx->default_passwd_callback=cb;
 }
void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx,void *u)
 {
 ctx->default_passwd_callback_userdata=u;
 }

举例:

static int
pass_cb(char *buf, int len, int verify, void *password)
{
    snprintf(buf,len, "123456");
    return strlen(buf);
}
SSL_CTX_set_default_passwd_cb(ctx, pass_cb);
等价于:
SSL_CTX_set_default_passwd_cb_userdata(ctx, "123456");
 
2.7 SSL_CTX_use_certificate_file()

该函数读取证书文件,证书文件通常都进行了加密保护。普及一下,证书文件里肯定是有公钥的,一般没私钥,某些情况会把私钥也包含进去,但那样作太不安全了,原则上私钥是永远不会给别人看到的,就算是进行了加密保护。
/* ssl/ssl_rsa.c */
int SSL_use_certificate_file(SSL *ssl, const char *file, int type)
 {
 int j;
 BIO *in;
 int ret=0;
 X509 *x=NULL;
 in=BIO_new(BIO_s_file_internal());
 if (in == NULL)
  {
  SSLerr(SSL_F_SSL_USE_CERTIFICATE_FILE,ERR_R_BUF_LIB);
  goto end;
  }
 if (BIO_read_filename(in,file) <= 0)
  {
  SSLerr(SSL_F_SSL_USE_CERTIFICATE_FILE,ERR_R_SYS_LIB);
  goto end;
  }
// 根据证书是PEM还是DER分别读取进行解码
// DER是二进制格式,PEM则是对DER用BASE64编码的后的文本格式
 if (type == SSL_FILETYPE_ASN1)
  {
  j=ERR_R_ASN1_LIB;
  x=d2i_X509_bio(in,NULL);
  }
 else if (type == SSL_FILETYPE_PEM)
  {
  j=ERR_R_PEM_LIB;
  x=PEM_read_bio_X509(in,NULL,ssl->ctx->default_passwd_callback,ssl->ctx->default_passwd_callback_userdata);
  }
 else
  {
  SSLerr(SSL_F_SSL_USE_CERTIFICATE_FILE,SSL_R_BAD_SSL_FILETYPE);
  goto end;
  }
 if (x == NULL)
  {
  SSLerr(SSL_F_SSL_USE_CERTIFICATE_FILE,j);
  goto end;
  }
// 加载解码后后的证书
 ret=SSL_use_certificate(ssl,x);
end:
 if (x != NULL) X509_free(x);
 if (in != NULL) BIO_free(in);
 return(ret);
 }

2.8 SSL_CTX_use_PrivateKey_file()

该函数加载私钥文件,和SSL_CTX_use_certificate_file()是类似的,因为RSA算法的公钥私钥是对称的,刚生成密钥时谁作私钥都行。
SSL_CTX_use_PrivateKey_file()只加载PEM格式私钥,DER格式的用函数SSL_use_PrivateKey_ASN1()加载。

/* ssl/ssl_rsa.c */
int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type)
 {
 int j,ret=0;
 BIO *in;
 EVP_PKEY *pkey=NULL;
 in=BIO_new(BIO_s_file_internal());
 if (in == NULL)
  {
  SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE,ERR_R_BUF_LIB);
  goto end;
  }
 if (BIO_read_filename(in,file) <= 0)
  {
  SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE,ERR_R_SYS_LIB);
  goto end;
  }
// 私钥只支持PEM格式
 if (type == SSL_FILETYPE_PEM)
  {
  j=ERR_R_PEM_LIB;
  pkey=PEM_read_bio_PrivateKey(in,NULL,
   ssl->ctx->default_passwd_callback,ssl->ctx->default_passwd_callback_userdata);
  }
 else
  {
  SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE,SSL_R_BAD_SSL_FILETYPE);
  goto end;
  }
 if (pkey == NULL)
  {
  SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE,j);
  goto end;
  }
// 加载私钥
 ret=SSL_use_PrivateKey(ssl,pkey);
 EVP_PKEY_free(pkey);
end:
 if (in != NULL) BIO_free(in);
 return(ret);
 }

2.9 SSL_CTX_check_private_key()

该函数检查所用的公钥私钥是否是匹配的
int SSL_CTX_check_private_key(SSL_CTX *ctx)
 {
 if ( (ctx == NULL) ||
  (ctx->cert == NULL) ||
  (ctx->cert->key->x509 == NULL))
  {
  SSLerr(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY,SSL_R_NO_CERTIFICATE_ASSIGNED);
  return(0);
  }
 if  (ctx->cert->key->privatekey == NULL)
  {
  SSLerr(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY,SSL_R_NO_PRIVATE_KEY_ASSIGNED);
  return(0);
  }
// 这才是真正比较函数,在crypto/x509/x509_cmp.c中定义
 return(X509_check_private_key(ctx->cert->key->x509, ctx->cert->key->privatekey));
 }
2.10 SSL_new
该函数根据SSL_CTX实现一个SSL结构实例,SSL结构是个很复杂的结构,定义如下:

/* ssl/ssl.h */
typedef struct ssl_st SSL;
struct ssl_st
 {
 /* protocol version
  * (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION)
  */
 int version;
 int type; /* SSL_ST_CONNECT or SSL_ST_ACCEPT */
 SSL_METHOD *method; /* SSLv3 */
 /* There are 2 BIO's even though they are normally both the
  * same.  This is so data can be read and written to different
  * handlers */
#ifndef OPENSSL_NO_BIO
 BIO *rbio; /* used by SSL_read */
 BIO *wbio; /* used by SSL_write */
 BIO *bbio; /* used during session-id reuse to concatenate
      * messages */
#else
 char *rbio; /* used by SSL_read */
 char *wbio; /* used by SSL_write */
 char *bbio;

没有评论: