SSL连接,搭建网络安全道路
什么是SSL连接
SSL连接,当前版本为3.1(SSL3.1就是TLS1.0)。它已被广泛地用于Web浏览器与服务器之间的身份认证和加密数据传输.它位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。 SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。
SSL连接建立过程
(以OpenSSL API为例)
OpenSSL是一套开放源代码的SSL套件,其函数库是以C语言所写成,实现了基本的传输层数据加密功能。此软件是以两个加拿大人Eric A. Young 和Tim J. Hudson所写的SSLeay为基础所发展的,SSLeay随着两人前往RSA公司任职而停止开发。1998年,OpenSSL项目组接管了OpenSSL的开发工作,并推出了OpenSSL的0.9.1版,到目前为止,OpenSSL的算法已经非常完善,对SSL2.0、SSL3.0以及TLS1.0都支持。
OpenSSL同时实现了客户端与服务器的开发接口,使用OpenSSL进行安全通信的大致流程如下图所示。
一、OpenSSL API
SSL通信模型采用标准的C/S结构,因此基于OpenSSL的程序可以被分为两个部分:Client和Server。上图是建立SSL通信的流程简图,说明了基于OpenSSL的程序所要遵循的以下几个重要步骤:
(1)OpenSSL初始化
OpenSSL在使用之前,必须进行相应的初始化工作。完成初始化功能的函数原型为:
void SSL_load_error_strings(void); // 错误信息的初始化
int SSL_library_int(void); // 初始化SSL算法库函数( 加载要用到的算法 ),调用SSL函数之前必须调用此函数
在建立SSL连接之前,要为Client和Server分别指定本次连接采用的协议及其版本,目前能够使用的协议版本包括SSLv2、SSLv3、SSLv2/v3和TLSv1.0。SSL连接若要正常建立,则要求Client和Server必须使用相互兼容的协议。
(2)创建CTX
在OpenSSL中,CTX是指SSL会话环境。建立连接时使用不同的协议,其CTX也不一样。创建CTX的过程中会依次用到以下OpenSSL函数:
//客户端、服务端都需要调用的
SSL_CTX_new() //申请SSL会话环境
//若有验证对方证书的需求,则需调用
SSL_CTX_set_verify() //指定证书验证方式
SSL_CTX_load_verify_location() //为SSL会话环境加载本应用所信任的CA证书列表
//若有加载证书的需求,则需调用
SSL_CTX_use_certificate_file() //为SSL会话加载本应用的证书
SSL_CTX_use_certificate_chain_file() //为SSL会话加载本应用的证书所属的证书链
SSL_CTX_use_PrivateKey_file() //为SSL会话加载本应用的私钥
SSL_CTX_check_private_key() //验证所加载的私钥和证书是否相匹配
(3)创建SSL套接字
在此之前要先创建普通的流套接字,完成TCP三次握手,建立普通的TCP连接。然后创建SSL套接字,并将之与流套接字绑定。这一过程中会使用以下几个函数:
SSL *SSl_new(SSL_CTX *ctx); //创建一个SSL套接字
int SSL_set_fd(SSL *ssl,int fd); //以读写模式绑定流套接字
int SSL_set_rfd(SSL *ssl,int fd); //以只读模式绑定流套接字
int SSL_set_wfd(SSL *ssl,int fd); //以只写模式绑定流套接字
(4)完成SSL握手
在这一步,我们需要在普通TCP连接的基础上,建立SSL连接。与普通流套接字建立连接的过程类似:Client使用函数SSL_connect()【类似于流套接字中用的connect()】发起握手,而Server使用函数SSL_ accept()【类似于流套接字中用的accept()】对握手进行响应,从而完成握手过程。两函数原型如下:
int SSL_connect(SSL *ssl);
int SSL_accept(SSL *ssl);
握手过程完成之后,Client通常会要求Server发送证书信息,以便对Server进行鉴别。其实现会用到以下两个函数:
X509 *SSL_get_peer_certificate(SSL *ssl); //从SSL套接字中获取对方的证书信息
X509_NAME *X509_get_subject_name(X509 *a); //得到证书所用者的名字
(5)进行数据传输
经过前面的一系列过程后,就可以进行安全的数据传输了。在数据传输阶段,需要使用SSL_read( )和SSL_write( )来代替普通流套接字所使用的read( )和write( )函数,以此完成对SSL套接字的读写操作,两个新函数的原型分别如下:
int SSL_read(SSL *ssl,void *buf,int num); //从SSL套接字读取数据
int SSL_write(SSL *ssl,const void *buf,int num); //向SSL套接字写入数据
(6)会话结束
当Client和Server之间的通信过程完成后,就使用以下函数来释放前面过程中申请的SSL资源:
int SSL_shutdown(SSL *ssl); //关闭SSL套接字
void SSl_free(SSL *ssl); //释放SSL套接字
void SSL_CTX_free(SSL_CTX *ctx); //释放SSL会话环境
全球可信CA机构