关闭

嵌入式 建立ssl连接过程分析二

643人阅读 评论(0) 收藏 举报
分类:

2.6 SSL_CTX_set_default_passwd_cb[_userdata]()


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

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


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");
    returnstrlen(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()

该函数读取证书文件,证书文件通常都进行了加密保护。普及一下,证书文件里肯定是有公钥的,一般没私钥,某些情况会把私钥也包含进去,但那样作太不安全了,原则上私钥是永远不会给别人看到的,就算是进行了加密保护。

int SSL_use_certificate_file(SSL *ssl, const char *file, inttype)
 {
 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()加载。


int SSL_use_PrivateKey_file(SSL *ssl, const char *file, inttype)
 {
 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结构是个很复杂的结构,定义如下:

typedef struct ssl_st SSL;
struct ssl_st
 {
 
 int version;
 int type;
 SSL_METHOD *method;
 
#ifndef OPENSSL_NO_BIO
 BIO *rbio;
 BIO *wbio;
 BIO *bbio;
#else
 char *rbio;
 char *wbio;
 char *bbio;
#endif
 
 int rwstate;
 
 int in_handshake;
 int (*handshake_func)();
 
 int server; 
 int new_session;
 int quiet_shutdown;
 int shutdown; 
 int state; 
 int rstate; 
 BUF_MEM *init_buf; 
 void*init_msg;   
 intinit_num;  
 intinit_off;  
 
 unsigned char *packet;
 unsigned int packet_length;
 struct ssl2_state_st *s2;
 struct ssl3_state_st *s3;
 intread_ahead;  
 
 void (*msg_callback)(int write_p, int version,int content_type, const void *buf, size_t len, SSL *ssl, void*arg);
 void *msg_callback_arg;
 inthit;  
 intpurpose;  
 inttrust;  
 
 STACK_OF(SSL_CIPHER) *cipher_list;
 STACK_OF(SSL_CIPHER) *cipher_list_by_id;
 
 EVP_CIPHER_CTX*enc_read_ctx;  
 const EVP_MD*read_hash;  
#ifndef OPENSSL_NO_COMP
 COMP_CTX*expand;   
#else
 char *expand;
#endif
 EVP_CIPHER_CTX*enc_write_ctx;  
 const EVP_MD*write_hash;  
#ifndef OPENSSL_NO_COMP
 COMP_CTX*compress;   
#else
 char *compress; 
#endif
 
 
 
 struct cert_st *cert;
 
 unsigned int sid_ctx_length;
 unsigned charsid_ctx[SSL_MAX_SID_CTX_LENGTH];
 
 SSL_SESSION *session;
 
 GEN_SESSION_CB generate_session_id;
 
 int verify_mode; 
 int verify_depth;
 int (*verify_callback)(int ok,X509_STORE_CTX*ctx);
 void (*info_callback)(const SSL *ssl,int type,intval);
 interror;  
 interror_code;  
#ifndef OPENSSL_NO_KRB5
 KSSL_CTX*kssl_ctx;    
#endif 
 SSL_CTX *ctx;
 
 int debug; 
 
 long verify_result;
 CRYPTO_EX_DATA ex_data;
 
 STACK_OF(X509_NAME) *client_CA;
 int references;
 unsigned long options;
 unsigned long mode;
 long max_cert_list;
 int first_packet;
 int client_version; 
 };

SSL *SSL_new(SSL_CTX *ctx)
 {
 SSL *s;
// 一些必要检查
 if (ctx == NULL)
  {
  SSLerr(SSL_F_SSL_NEW,SSL_R_NULL_SSL_CTX);
  return(NULL);
  }
 if (ctx->method == NULL)
  {
  SSLerr(SSL_F_SSL_NEW,SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION);
  return(NULL);
  }
// 分配SSL实例的空间
 s=(SSL *)OPENSSL_malloc(sizeof(SSL));
 if (s == NULL) goto err;
 memset(s,0,sizeof(SSL));
// 初始化SSL结构参数
#ifndef OPENSSL_NO_KRB5
 s->kssl_ctx =kssl_ctx_new();
#endif 
 s->options=ctx->options;
 s->mode=ctx->mode;
 s->max_cert_list=ctx->max_cert_list;
 if (ctx->cert != NULL)
  {
  
  s->cert =ssl_cert_dup(ctx->cert);
  if (s->cert ==NULL)
   gotoerr;
  }
 else
  s->cert=NULL;
 s->read_ahead=ctx->read_ahead;
 s->msg_callback=ctx->msg_callback;
 s->msg_callback_arg=ctx->msg_callback_arg;
 s->verify_mode=ctx->verify_mode;
 s->verify_depth=ctx->verify_depth;
 s->sid_ctx_length=ctx->sid_ctx_length;
 OPENSSL_assert(s->sid_ctx_length<= sizeof s->sid_ctx);
 memcpy(&s->sid_ctx,&ctx->sid_ctx,sizeof(s->sid_ctx));
 s->verify_callback=ctx->default_verify_callback;
 s->generate_session_id=ctx->generate_session_id;
 s->purpose =ctx->purpose;
 s->trust =ctx->trust;
 s->quiet_shutdown=ctx->quiet_shutdown;
 CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX);
 s->ctx=ctx;
 s->verify_result=X509_V_OK;
 s->method=ctx->method;
 if(!s->method->ssl_new(s))
  goto err;
 s->references=1;
 s->server=(ctx->method->ssl_accept== ssl_undefined_function)?0:1;
 SSL_clear(s);
 CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL, s,&s->ex_data);
 return(s);
err:
 if (s != NULL)
  {
  if (s->cert !=NULL)
   ssl_cert_free(s->cert);
  if (s->ctx !=NULL)
   SSL_CTX_free(s->ctx);
  OPENSSL_free(s);
  }
 SSLerr(SSL_F_SSL_NEW,ERR_R_MALLOC_FAILURE);
 return(NULL);
 }
 

2.11 SSL_set_fd

SSL_set_fd()函数将建立的SSL结构与TCP套接字联系,使SSL结构对套接字中的TCP数据进行SSL封装。
int SSL_set_fd(SSL *s,int fd)
 {
 int ret=0;
 BIO *bio=NULL;
// 建立一个BIO,BIO是OpenSSL提供的用来进行算法封装的处理结构,还可以将多个算法
// 串联起来,这样可以很方便地实现数据的封装
 bio=BIO_new(BIO_s_socket());
 if (bio == NULL)
  {
  SSLerr(SSL_F_SSL_SET_FD,ERR_R_BUF_LIB);
  goto err;
  }
// 把套接字和BIO联系
 BIO_set_fd(bio,fd,BIO_NOCLOSE);
// 把SSL和BIO联系起来,包括读写操作
 SSL_set_bio(s,bio,bio);
 ret=1;
err:
 return(ret);
 }

void SSL_set_bio(SSL *s,BIO *rbio,BIO *wbio)
 {
 
 if (s->bbio != NULL)
  {
  if (s->wbio ==s->bbio)
   {
   s->wbio=s->wbio->next_bio;
   s->bbio->next_bio=NULL;
   }
  }
 if ((s->rbio != NULL)&& (s->rbio !=rbio))
  BIO_free_all(s->rbio);
 if ((s->wbio != NULL)&& (s->wbio != wbio)&& (s->rbio !=s->wbio))
  BIO_free_all(s->wbio);
// 设置SSL读写BIO
 s->rbio=rbio;
 s->wbio=wbio;
 }

SSL_set_fd()还有两个类似函数:
SSL_set_wfd():对写的数据进行SSL封装
SSL_set_rfd():对都的数据进行SSL封装
不过一般情况下用得比较少。
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:983798次
    • 积分:17677
    • 等级:
    • 排名:第540名
    • 原创:741篇
    • 转载:522篇
    • 译文:0篇
    • 评论:105条
    最新评论