赞
踩
深入探索 OpenSSL:概念、原理、开发步骤、使用方法、使用场景及代码示例
c++使用OpenSSL基于socket实现tcp双向认证ssl(使用TSL协议)代码实现
SSL握手通信详解及linux下c/c++ SSL Socket代码举例(另附SSL双向认证客户端代码)
SSL/CA 证书及其相关证书文件(pem、crt、cer、key、csr)
TCP3次握手
+OPENSLL四次握手
)SSL全称安全套接字协议层,为了通信安全,使用RSA非对称加密交换密钥,密钥交换完成后使用对称密钥进行通信。(为什么将非对称加密切换称对称加密是为了提供通信效率。非对称加密效率低)
TCP openssl双向认证:即在TCP三次握手的基础上增加一次openssl的4次握手。
SSL_accept
SSL_connect
SSL_accept
进行四次握手SSL_read
、SSL_write
收发数据SSL_shutdown
、SSL_free
#include <iostream> #include <tchar.h> #include <winsock.h> #include "openssl/ssl.h" #pragma comment(lib,"ws2_32.lib") #pragma comment(lib,"libcrypto_static.lib") #pragma comment(lib,"libssl_static.lib") using namespace std; int main() { WSADATA wsdata; int errcode = WSAStartup(MAKEWORD(2, 2), &wsdata); if (errcode != 0) { std::cout << "WSAStartup failed,errcode:%d" << errcode<<std::endl; return 0; } //初始化ssl SSL_library_init(); //加载ssl算法库 OpenSSL_add_all_algorithms(); //加载ssl 错误信息 SSL_load_error_strings(); //以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Context SSL_CTX* ssl_ctx = SSL_CTX_new(SSLv23_server_method()); if (ssl_ctx == nullptr) { std::cout << "SSL_CTX_new failed"<<std::endl; return 0; } //加载数字证书 if (SSL_CTX_use_certificate_chain_file(ssl_ctx, "ca.crt") <= 0) { printf("SSL_CTX_use_certificate_chain_file failed\r\n"); return 0; } //加载私钥 if (SSL_CTX_use_PrivateKey_file(ssl_ctx, "ca.key", SSL_FILETYPE_PEM) <= 0) { printf("SSL_CTX_use_PrivateKey_file failed\r\n"); return 0; } // 检查用户私钥是否正确 if (!SSL_CTX_check_private_key(ssl_ctx)) { printf("SSL_CTX_check_private_key failed\r\n"); return 0; } SSL_CTX_set_timeout(ssl_ctx, 100); //创建socket->bind->list->accept SOCKET listen_sock = socket(AF_INET, SOCK_STREAM, 0); if (listen_sock == INVALID_SOCKET) { printf("socket create failed\r\n"); return 0; } //setsocketopt resuse port unsigned short port = 32100; sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(port); sin.sin_addr.S_un.S_addr = INADDR_ANY; if (SOCKET_ERROR == bind(listen_sock, (sockaddr*)&sin, sizeof(sin))) { printf("socket bind failed\r\n"); return 0; } if (SOCKET_ERROR == listen(listen_sock, 5)) { printf("socket listen failed\r\n"); return 0; } printf("tcp ssl server:%d\r\n", port); while (true) { char szbuf[1024] = ""; sockaddr_in peer_addr; int naddr_len = sizeof(peer_addr); printf("wait client...\r\n"); SOCKET soct_peer = accept(listen_sock, (sockaddr*)&peer_addr, &naddr_len); printf("accept client ,socket:%d\r\n", soct_peer); //将socket和ssl绑定(ssl握手) SSL* ssl_peer = SSL_new(ssl_ctx); if (ssl_peer == nullptr) { printf("socket:%d,SSL_new failed\r\n", soct_peer); goto freessl; } SSL_set_fd(ssl_peer, soct_peer); //这里会无限阻塞,为了安全应该异步增加一个超时值,如果超时仍然未连接上则应该close if (SSL_accept(ssl_peer) < 0) { printf("socket:%d,SSL_accept failed\r\n", soct_peer); goto freessl; } //开始ssl读写 SSL_read(ssl_peer, szbuf, 1024); printf("socket[%d] read:%s\r\n", soct_peer, szbuf); SSL_write(ssl_peer, szbuf, lstrlenA(szbuf)); freessl: shutdown(soct_peer, 0); closesocket(soct_peer); //释放ssl if(ssl_peer) SSL_free(ssl_peer); continue; } return 0; }
SSL_connect
进行四次握手SSL_read
、SSL_write
收发数据SSL_shutdown
、SSL_free
#include <iostream> #include <tchar.h> #include <winsock.h> #include "openssl/ssl.h" #pragma comment(lib,"ws2_32.lib") #pragma comment(lib,"libcrypto_static.lib") #pragma comment(lib,"libssl_static.lib") using namespace std; int main() { WSADATA wsdata; int errcode = WSAStartup(MAKEWORD(2, 2), &wsdata); if (errcode != 0) { std::cout << "WSAStartup failed,errcode:%d" << errcode << std::endl; return 0; } //初始化ssl SSL_library_init(); //加载ssl算法库 OpenSSL_add_all_algorithms(); //加载ssl 错误信息 SSL_load_error_strings(); //以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Context SSL_CTX* ssl_ctx = SSL_CTX_new(SSLv23_client_method()); if (ssl_ctx == nullptr) { std::cout << "SSL_CTX_new failed" << std::endl; return 0; } //SSL_CTX_set_timeout(ssl_ctx, 100); //创建socket->connect SOCKET cli_sock = socket(AF_INET, SOCK_STREAM, 0); if (cli_sock == INVALID_SOCKET) { printf("socket create failed\r\n"); return 0; } //setsocketopt resuse port sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(32100); sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); if (SOCKET_ERROR == connect(cli_sock, (sockaddr*)&sin, sizeof(sin))) { printf("socket connect failed\r\n"); return 0; } printf("connect client ,socket:%d\r\n", cli_sock); //将socket和ssl绑定(ssl握手) char szbuf[1024] = "Hellow word!!!"; SSL* ssl_peer = SSL_new(ssl_ctx); if (ssl_peer == nullptr) { printf("socket:%d,SSL_new failed\r\n", cli_sock); goto freessl; } SSL_set_fd(ssl_peer, cli_sock); //这里会无限阻塞,为了安全应该异步增加一个超时值,如果超时仍然未连接上则应该close if (SSL_connect(ssl_peer) < 0) { printf("socket:%d,SSL_accept failed\r\n", cli_sock); goto freessl; } printf("ssl connectd ok\r\n"); SSL_write(ssl_peer, szbuf, lstrlenA(szbuf)); //开始ssl读写 memset(szbuf, 0, 1024); SSL_read(ssl_peer, szbuf, 1024); printf("socket[%d] read:%s\r\n", cli_sock, szbuf); freessl: shutdown(cli_sock, 0); closesocket(cli_sock); //释放ssl if (ssl_peer) SSL_free(ssl_peer); return 0; }
1. 服务端和客户端初始化SSL_CTX参数不同
//以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Context
//客户端调用openssl客户端的方法
SSL_CTX* ssl_ctx = SSL_CTX_new(SSLv23_client_method());
//服务端调用openssl服务端的方法
SSL_CTX* ssl_ctx = SSL_CTX_new(SSLv23_server_method());
2. SSL_accept
、SSL_connect
阻塞函数
在同步调用 SSL_accept
、SSL_connect
的时候会进行阻塞,需要定时检测是否超时,如果超时则关闭当前socket,防止恶意链接。例如拿非openssl的客户端连接openssl的服务端,此时不会存在四次握手,在未发送数据前会一直阻塞下去,等待握手的完成。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。