Openssl 之 SSL 协议通信
0x00 前言
SSL协议最早由netscape公司提出,包含ssl v2 和 v3 两个版本。主要目的是保证通信双方的信道安全。它能够提供数据加密、身份认证以及消息完整性保护,另外SSL协议还支持数据压缩。SSL协议通过客户端和服务器端握手来协商各种算法和密钥。
Openssl是一个功能强大的开源的密码算法和协议的工具箱。主要提供的功能有: SSL协议实现(包括SSL V2, SSL V3 和 TLS V1),对称密码算法(AES,DES,Blowfish,Camellia等),哈希算法(MD5,SHA1等),公钥密码算法(RSA,DH,DSA,ECC,ECDH,ECDSA)以及证书相关操作等。
0x01 服务端
-
SSL初始化操作
SSL_library_init() OpenSSL_add_all_algorithms() /* 载入Openssl所支持的算法 */ SSL_load_error_strings() /* 载入Openssl的相关错误信息 */
-
申请SSL_CTX数据结构
SSL_CTX * ctx = SSL_CTX_new(SSLv23_server_method())
SSLv23_server_method()
表明是以SSL v2 和 v3 标准兼容方式产生SSL_CTX
, 即SSL Context Text
,也可以使用SSLv2_server_method()
或SSLv3_server_method()
单独表示v2 或 v3标准。 -
服务端载入自己的证书
#define CACERT ".\\cert\\server\\server-cert.crt" SSL_CTX_use_certificate_file(ctx, CACERT, SSL_FILETYPE_PEM)
server-cert.crt
是服务端的数字证书,由CA机构认证签发。此证书用来发送给客户端,证书内包含有服务端的公钥。
-
服务端载入自己的私钥并检查
#define PRIKEY ".\\cert\\server\\server-key.pem" SSL_CTX_use_PrivateKey_file(ctx, PRIKEY, SSL_FILETYPE_PEM) SSL_CTX_check_private_key(ctx) /*检查服务端的私钥是否正确*/
server-key.pem
是 服务端的私钥文件,里面包含密钥信息,是通过openssl的命令行工具生成,详细信息参见openssl相关文档。 -
建立socket通信
WSADATA wsaData; WSAStartup( MAKEWORD(2, 2), &wsaData ) sockfd = socket(PF_INET, SOCK_STREAM, 0)) /* 建立 socket 结构 */ bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) /* 绑定地址 */ listen(sockfd, 2) /* 监听 */ new_fd =accept(sockfd, (struct sockaddr *) &their_addr,&len)) /* 等待客户端连接 */
-
建立SSL连接
SSL *ssl = SSL_new(ctx) /* 基于上述SSL_CTX的句柄ctx产生一个新的 SSL 用于通信 */ SSL_set_fd(ssl, new_fd) /* 将刚刚接收到的客户端连接的socket加入到 SSL 结构中 */ SSL_accept(ssl) /* 建立 SSL 连接 */
-
基于SSL的数据通信
SSL_write(ssl, buf, strlen(buf)) /* 向客户端发送消息,消息的传输通过SSL加密 */ SSL_read(ssl, buf, MAXBUF) /* 接收客户端发送来的消息 */
-
关闭与释放
SSL_shutdown(ssl) /* 关闭 SSL 连接 */ SSL_free(ssl) /* 释放 SSL */ closesocket(new_fd) /* 关闭 客户端连接的 socket */ closesocket(sockfd) /* 关闭监听的 socket */ SSL_CTX_free(ctx) /* 释放 CTX */
0x02 客户端
-
SSL初始化操作
/* 参见 服务端代码 */ SSL_library_init() OpenSSL_add_all_algorithms() SSL_load_error_strings()
-
申请SSL_CTX数据结构
SSL_CTX * ctx = SSL_CTX_new(SSLv23_server_method())
-
建立socket通信
WSADATA wsaData; WSAStartup( MAKEWORD(2, 2), &wsaData ) sockfd = socket(AF_INET, SOCK_STREAM, 0) connect(sockfd, (struct sockaddr *) &dest, sizeof(dest))/* 连接到服务器 */ /* dest 是 服务器端的 地址信息 和 端口信息 */
-
建立SSL连接
SSL *ssl = SSL_new(ctx) SSL_set_fd(ssl, sockfd) /* 将连接到服务端的socket加入到SSL结构中*/ SSL_connect(ssl) /* 与服务端建立SSL连接 */
与服务端成功建立SSL连接后,客户端可以通过
SSL_get_peer_certificate(ssl)
获取到服务端的证书,从而进一步获取证书内的详细信息,如获取证书的颁发者X509_get_issuer_name(cert)
,更多信息参见openssl提供的x509证书机制。 -
基于SSL的数据通信
SSL_read(ssl, buffer, MAXBUF) /* 接收服务器发来的信息 */ SSL_write(ssl, buffer, strlen(buffer)) /* 向服务器发送信息 */
SSL_read
&SSL_write
建立在SSL基础上,所以客户端与服务端的通信数据是受加密保护的。 -
关闭连接
SSL_shutdown(ssl); SSL_free(ssl); closesocket(sockfd); SSL_CTX_free(ctx);
0x03 总结
SSL协议,将数据加密技术集成到了协议自身,数据在离开计算机前就已经被加密保护,只有到达通信对方后才能被解密。openssl提供的证书和密码学算法支撑起SSL协议的运转。
理论上,即使加密的数据在到达对方目标之前,存在中间人的窃听或截取,被加密的数据仍然不可能被破解。然而,随着计算机技术的变化和密码翻译技术的发展,SSL中的加密协议也面临着新的考验。