下面是server 和client 的代碼。用沒跑過,但是用類似的代碼跑了。流程是這樣的。要注意的是openssl中ssl連接建立前用阻塞的socket,建立後可以設置非阻塞。openssl每個操作後最好檢查下是否成功。
/************server*************************/
#include <string.h>
#include <iostream>
#include <winsock2.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <openssl/rand.h>
#include <openssl/err.h>
#pragma comment (lib,"WS2_32.lib")
#pragma comment( lib, "libeay32.lib" )
#pragma comment( lib, "ssleay32.lib" )
char buffer[10001] = {0};
int main()
{
SSL_library_init(); //初始化SSL庫
OpenSSL_add_all_algorithms(); //支持所有算法
SSL_load_error_strings(); //提供將錯誤號解析爲字符串的功能
SSL *ssl = NULL;
SSL_CTX *ssl_ctx = NULL;
SSL_METHOD *ssl_method = NULL;
X509 *client_cert = NULL;
//設置客戶端使用的SSL版本
//ssl_method = SSLv3_server_method();
ssl_method = SSLv23_server_method();
//創建SSL上下文環境 每個進程只需維護一個SSL_CTX結構體
ssl_ctx = SSL_CTX_new(ssl_method);
//驗證對方
SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_PEER,NULL);
//若驗證,則放置CA證書
SSL_CTX_load_verify_locations(ssl_ctx, "cacert.pem", NULL);
//設置pass phrase
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, "pass phrase");
//讀取證書文件
SSL_CTX_use_certificate_file(ssl_ctx,"*****Cert.pem",SSL_FILETYPE_PEM);
//讀取密鑰文件
SSL_CTX_use_PrivateKey_file(ssl_ctx,"*****Key.pem",SSL_FILETYPE_PEM);
//驗證密鑰是否與證書一致
SSL_CTX_check_private_key(ssl_ctx);
/*構建隨機數生成機制,WIN32平臺必需*/
srand( (unsigned)time( NULL ) );
for( int i = 0; i < 100;i++ )
seed_int[i] = rand();
RAND_seed(seed_int, sizeof(seed_int));
//設置加密方式
//SSL_CTX_set_cipher_list(ssl_ctx,"RC4-MD5");
//建立TCP服務器端、開始監聽並接受客戶端連接請求
// 初始化 Winsock.
WSADATA wsaData;
int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
if ( iResult != NO_ERROR )
{
//失敗
return -1;
}
// 建立socket
server = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if ( server == INVALID_SOCKET )
{
//失敗
WSACleanup();
return -2;
}
// 綁定socket
sockaddr_in service;
service.sin_family = AF_INET;
//service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_addr.s_addr = INADDR_ANY;
service.sin_port = htons( 8899 );
if ( bind( server, (SOCKADDR*) &service, sizeof(service) ) == SOCKET_ERROR )
{
//失敗
closesocket(server);
return -3;
}
// 監聽 socket
if ( listen( server, 10 ) == SOCKET_ERROR )
{
//失敗
return -4;
}
do
{
sClient = accept(server,NULL,NULL);
Sleep(100);
}while(sClient == INVALID_SOCKET);
//創建當前連接的SSL結構體
ssl = SSL_new(ssl_ctx);
//將SSL綁定到套接字上
SSL_set_fd(ssl, sClient);
//接受SSL鏈接
SSL_accept(ssl);
//獲取和釋放客戶端證書
client_cert = SSL_get_peer_certificate(ssl);
//打印所有加密算法的信息(可選)
std::cout<<"SSL connection using"<<SSL_get_cipher(ssl)<<std::endl;
X509_free(client_cert);
//unsigned long cmd;
//if (SOCKET_ERROR == ioctlsocket(sClient, FIONBIO, &cmd))
//{
//創建套接字時發生錯誤,非阻塞設置失敗
//ErrorProcess();
//closesocket(sClient);
//}
while(true)
{
SSL_read(ssl, buffer, 10000);
memset(buffer,0,10000);
SSL_write(ssl, "hello, world!", sizeof("hello, world!"));
Sleep(1000);
}
//斷開SSL鏈接
SSL_shutdown(ssl);
//釋放當前SSL鏈接結構體
SSL_free(ssl);
//斷開TCP鏈接
closesocket(sClient);
//釋放SSL上下文
SSL_CTX_free(ssl_ctx);
return 0;
}
- /**************client*********************/
- #include <iostream>
- #include <string.h>
- #include <winsock2.h>
- #include <openssl/ssl.h>
- #include <openssl/x509.h>
- #include <openssl/rand.h>
- #include <openssl/err.h>
- #pragma comment (lib,"WS2_32.lib")
- #pragma comment( lib, "libeay32.lib" )
- #pragma comment( lib, "ssleay32.lib" )
- int main(int argc, _TCHAR* argv[])
- {
- SOCKET client;
- char buffer[256] = {0};
- int seed_int[100]; /*存放隨機序列*/
- SSL *ssl = NULL;
- SSL_CTX *ssl_ctx = NULL;
- SSL_METHOD *ssl_method = NULL;
- X509 *server_cert = NULL;
- SSL_library_init(); //init libraries
- OpenSSL_add_all_algorithms(); //支持所有算法
- SSL_load_error_strings(); //提供將錯誤號解析爲字符串的功能
- //設置客戶端使用的SSL版本
- ssl_method = SSLv3_client_method();
- //創建SSL上下文環境 每個進程只需維護一個SSL_CTX結構體
- ssl_ctx = SSL_CTX_new(ssl_method);
- /*構建隨機數生成機制,WIN32平臺必需*/
- srand( (unsigned)time( NULL ) );
- for( int i = 0; i < 100;i++ )
- seed_int[i] = rand();
- RAND_seed(seed_int, sizeof(seed_int));
- /* Load the RSA CA certificate into the SSL_CTX structure */
- /* This will allow this client to verify the server's */
- /* certificate. */
- SSL_CTX_load_verify_locations(ssl_ctx, "cacert.pem", NULL);
- /* Set flag in context to require peer (server) certificate verification */
- SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_PEER,NULL);
- SSL_CTX_set_verify_depth(ssl_ctx,1);
- SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, "pass phrase");
- //讀取證書文件
- SSL_CTX_use_certificate_file(ssl_ctx,"******Cert.pem",SSL_FILETYPE_PEM);
- //讀取密鑰文件
- SSL_CTX_use_PrivateKey_file(ssl_ctx,"******Key.pem",SSL_FILETYPE_PEM);
- //驗證密鑰是否與證書一致
- SSL_CTX_check_private_key(ssl_ctx);
- //建立TCP鏈接
- // 初始化 Winsock.
- WSADATA wsaData;
- int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
- if ( iResult != NO_ERROR )
- {
- //AfxMessageBox("Error at WSAStartup()!");
- return;
- }
- // 建立socket socket.
- client = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
- if ( client == INVALID_SOCKET )
- {
- //AfxMessageBox("Error at socket!");
- WSACleanup();
- return;
- }
- // 連接到服務器.
- sockaddr_in clientService;
- clientService.sin_family = AF_INET;
- clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );
- clientService.sin_port = htons( 8899 );
- if ( connect( client, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR)
- {
- //AfxMessageBox( "Failed to connect!" );
- WSACleanup();
- return;
- }
- //unsigned long cmd;
- //if (SOCKET_ERROR == ioctlsocket(client, FIONBIO, &cmd))
- //{
- // //AfxMessageBox( "創建套接字時發生錯誤,非阻塞設置失敗:");
- // closesocket(client);
- //}
- //創建維護當前連接信息的SSL結構體
- ssl = SSL_new(ssl_ctx);
- //將SSL綁定到套接字上
- SSL_set_fd(ssl, client);
- //建立SSL鏈接
- SSL_connect(ssl);
- //獲取服務器端證書
- server_cert = SSL_get_peer_certificate(ssl);
- //釋放服務器端證書
- X509_free(server_cert);
- unsigned long cmd;
- if (SOCKET_ERROR == ioctlsocket(client, FIONBIO, &cmd))
- {
- //AfxMessageBox( "創建套接字時發生錯誤,非阻塞設置失敗:");
- closesocket(client);
- }
- while(true)
- {
- SSL_write(ssl, "hello, world!", sizeof("hello, world!");
- SSL_read(ssl, buffer, 255);
- printf("received: %s\n",buffer);
- memset(buffer,0,255);
- Sleep(1000);
- }
- //斷開SSL鏈接
- SSL_shutdown(ssl);
- //釋放當前SSL鏈接結構體
- SSL_free(ssl);
- closesocket(client);
- //釋放上下文
- SSL_CTX_free(ssl_ctx);
- return 0;
- }