SSL 缩写 Secure Socket Layer,在TCP层之上提供安全的网络服务。并且对应用程序透明,应用最广的不过于SSL于HTTP协议结合实现的HTTPS协议。
SSL主要工作流程包括:1. 网络连接建立;2. 与该连接相关的加密方式和压缩方式选择;3. 双方的身份识别;4. 本次传输密钥的确定;5. 加密的数据传输;网络连接的关闭。
SSL协议建立在传输层和应用层之间,包括四个子协议:SSL记录协议和SSL握手协议,SSL告警协议,ChangeCipherSpec( 更改密钥规格 ),其中记录协议在其他协议下端。
SSL 协议结构如下:
我们先简单看看ChangeCipherSpec,Alert这两个个协议, 本文将重点介绍握手协议的过程,和记录协议,最后结合最近的经验,给一些SSL编程相关的指导。
SSL 的告警协议是用来为通信对方发送一条告警消息,告警分为两个级别: fatal 和 warning, 对方收到fatal级别的消息之后会立刻断掉网络链接,需要重连和认证。而收到warming级别的消息就只会输出一条日志。
SSL 更换密钥规格 (change cipher spec) 协议由单个消息组成 , 该消息只包含一个值为 1 的单个字节。对方收到这个消息之后就表明需要始使用之前协商好的密钥套件发送消息了。
本文的重点终于来了, SSL握手协议, SSL要提供安全的网络服务,那么双方就必须要协商一套安全的加解密方案,众所周知,SSL只是提供一套安全方案,本身不提供加解密算法,而对于具体加解密算法,认证等,就是握手协议需要干的事情了。
SSL握手协议主要有目的有三:
1.客户端和服务端协商一致的用于保护数据的加解密套件;
2.握手需要对客户端或者服务端身份进行认证,但是此操作是可选操作。
3.还需要协商一组加解密算法所使用的密钥;
我们先从下图来解析SSL握手协议全过程:
步骤1:目的:协商双方的安全能力。为SSL建立TCP连接之后的say hello过程,客户端先发送一个ClientHello消息给服务端, 这个ClientHello消息包含:客户端SSL版本号(SSL2_VERSION),密钥套件(Cipher List),会话ID和随机码。服务端收到之后,会向客户端回一个SeverHello, 这个消息包含如下内容:客户建议的低版本以及服务器支持的最高版本,服务器产生的随机码,服务器会话ID、服务器从客户端ClientHello中建议的密码算法中挑出一套。
步骤2:目的:认证服务器和密钥交换:。服务器发送自己的证书给客户端,消息包含一个X.509证书,或者一条证书链(从权威机构购买的证书一般是一条证书链),服务端向客户端发送server_key_exchange消息(可选),一般在服务器没有证书和证书仅当作签名来使用时发送。服务器发送certificate_request消息(可选),请求客户端证书。最后服务器发送server_done, 然后等待客户端应答。
步骤3. 目的:认证客户端和密钥交换。客户端收到服务器的server _done报文之后,客户端首先检查服务器证书的合法性(如果服务器要求),如果服务器向客户端请求了证书,客户端必须发送客户端证书,然后发送client_key_exchange报文,报文的内容依赖于client_hello与server_hello定义的密钥交换的类型。最后,客户端可能发送client__verify 报文来校验客户发送的证书,这个报文只能在具有签名作用的客户端证书之后发送。
步骤4:目的:修改密文族并结束握手。客户端向服务端发送change_cipher_spec报文并将挂起的CipherSpec复制到当前的CipherSpec。这个报文使用的是改变密码格式协议。然后,客户端使用新的算法、对称密钥和MAC秘密立即发送finished报文。finished报文验证密钥交换和鉴别过程是成功的。服务器对这两个报文分别回答,发送自己的change_cipher_spec报文、finished报文。握手结束。此后便可进行应用层数据交换了。
到此, 握手协议解析完毕。加密通道已经建立好了,可以使用SSL记录协议来进行数据交换。
从上面的第一个图可知,SSL所有的数据交互(包括握手阶段的消息)都是封装在SSL记录协议支持的记录中进行传输。记录协议对上层提供数据的加密传输和保证数据的完整性传输服务。其主要操作见下图:
首先将应用层数据分组,每个小组不得多余2^14个字节,并且增加记录头部信息,使用压缩算法对每一个记录进行压缩(此操作可选),压缩后的长度不得大于2^10个字节,在压缩数据上增加消息认证的MAC,然后对压缩数据和MAC加密,使用TCP分组发送出去。
对于各消息是怎样定义的,请读者自行翻看OpenSSL源代码。接下来对于SSL编程说说最近的一些相关经验,只对相关接口说明,不提供源代码。
一般不涉及到BIO编程,包含后面两个头文件即可:
#include <openssl/err.h>
#include <openssl/ssl.h>
先看服务端:
SSL_library_init(); /* SSL 库初始化 */
OpenSSL_add_all_algorithms();/* 载入所有 SSL 算法 */
SSL_load_error_strings();/* 载入所有 SSL 错误消息,可对错我输出 */
ctx = SSL_CTX_new(SSLv23_server_method());/* 以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Content Text */
SSL_CTX_load_verify_locations(ctx, CertFile, KeyFile) /*加载整数认证路径*/
SSL_CTX_set_default_verify_paths(ctx)/*设置默认的认证路径*/
对于上面两个函数,在单个X.509整数认证时,没有任何问题, 但是到了证书链认证时, 如果没有上面两个函数,FireFox浏览器和Android默认的WebKit2内核浏览器会认证不通过,其他浏览器认证通过。错误原因是找不到证书链。从IOS浏览器的编程来看,有些浏览器确实可以支持省去这两步的服务器认证。
SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 */
SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) /* 载入用户私钥 */
SSL_CTX_check_private_key(ctx) /* 检查用户私钥是否正确 */
ssl = SSL_new(ctx);
SSL_set_fd(ssl, sockfd);
SSL_read, SSL_write
客户端的编程可以更加简单:
SSL_library_init(); /* SSL 库初始化 */
OpenSSL_add_all_algorithms();/* 载入所有 SSL 算法 */
SSL_load_error_strings();/* 载入所有 SSL 错误消息,可对错我输出 */
ctx = SSL_CTX_new(SSLv23_client_method());
ssl = SSL_new(ctx);
SSL_set_fd(ssl, sockfd);
SSL_read, SSL_write
其中省去了很多的socket操作。
原文:http://blog.chinaunix.net/uid-26904464-id-4759687.html