Openssl實現ssl通信實例

下面實例中使用的證書請參考openssl詳解自行生成

server.c 

#include "stdio.h"
#include <net/if.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>

const unsigned short u16Port = 10001;

const char* const certificate_path ="./CA/server/server.crt" ;
const char* const private_key_path = "./CA/server/server.key";
const char* const pCAPath = "./CA/demoCA/cacert.pem";

const char* const pRetStr ="HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n";
int main(int argc ,char*argv[])
{

	/*SSL庫初始化(一個進程只初始化一次)*/
	SSL_library_init();
	/*載入所有ssl錯誤消息*/
	SSL_load_error_strings();
	/*載入所有ssl算法*/
	OpenSSL_add_all_algorithms();
	
	const SSL_METHOD  *pMethod = TLSv1_2_method();
    SSL_CTX * pCtx = NULL; 
	SSL *pSSl = NULL;

	int iRet = -1;
	int listen_socket = -1;
	int client_socket = -1;
	struct sockaddr_in serverAddr;
	struct sockaddr_in clientAddr;
	char szBuf[1024]={0};
	int iClientLen = 0;
	do 
	{
		/*初始化SSL上下文環境變量函數*/
		pCtx = SSL_CTX_new(pMethod); 

		if(NULL == pCtx)
		{
			printf("%s %d iRet=%d %s\n",__func__,__LINE__,iRet,ERR_error_string(ERR_get_error(), NULL));
			break;
		}
		
		/* 載入用戶的數字證書, 此證書用來發送給客戶端。 證書裏包含有公鑰 */
		if(SSL_CTX_use_certificate_file(pCtx, certificate_path, SSL_FILETYPE_PEM) <= 0)
		{
			printf("%s %d iRet=%d %s\n",__func__,__LINE__,iRet,ERR_error_string(ERR_get_error(), NULL));
			break;
		}
#if 1		
		/*設置私鑰的解鎖密碼*/
		SSL_CTX_set_default_passwd_cb_userdata(pCtx, "123456");
#endif
		/* 載入用戶私鑰 */
		if(SSL_CTX_use_PrivateKey_file(pCtx, private_key_path, SSL_FILETYPE_PEM) <= 0)
		{
			printf("%s %d iRet=%d %s\n",__func__,__LINE__,iRet,ERR_error_string(ERR_get_error(), NULL));
			break;
		}

		/* 檢查用戶私鑰是否正確 */
		if(SSL_CTX_check_private_key(pCtx) <= 0)
		{
			printf("%s %d iRet=%d %s\n",__func__,__LINE__,iRet,ERR_error_string(ERR_get_error(), NULL));
			break;
		}
		
		/*證書驗證*/
		SSL_CTX_set_verify(pCtx,SSL_VERIFY_NONE,NULL);
		
		SSL_CTX_set_options (pCtx, SSL_OP_ALL | SSL_OP_NO_SSLv2 |SSL_OP_NO_SSLv3);
		SSL_CTX_set_mode(pCtx, SSL_MODE_AUTO_RETRY);
		
		
	    listen_socket = socket(AF_INET,SOCK_STREAM,0); /* Open the socket */
		if(listen_socket < 0)
		{
			printf("%s %d errno=%d\n",__func__,__LINE__,errno);
			break;
		}
		
		memset(&serverAddr,0,sizeof(serverAddr));	   
		serverAddr.sin_addr.s_addr= INADDR_ANY;
		serverAddr.sin_family = AF_INET;
		serverAddr.sin_port = htons(u16Port);
		
		if(bind(listen_socket, (struct sockaddr *)&serverAddr, sizeof (serverAddr)) < 0)
		{
			printf("%s %d errno=%d\n",__func__,__LINE__,errno);
			break;
		}

		if(listen(listen_socket, 5) < 0)
		{
			printf("%s %d errno=%d\n",__func__,__LINE__,errno);
			break;

		}
		while(1)
		{
			iClientLen = sizeof (clientAddr);
			printf("start listen!!!\n");
			/*等待客戶端連接*/
			client_socket = accept(listen_socket,(struct sockaddr *)&clientAddr, &iClientLen);
			if(client_socket <  0)
			{
				printf("%s %d errno=%d\n",__func__,__LINE__,errno);
				break;
			}
			
			/*基於pCtx產生一個新的ssl*/
			pSSl = SSL_new(pCtx);
			if(NULL  == pSSl)
			{
				printf("%s %d iRet=%d %s\n",__func__,__LINE__,iRet,ERR_error_string(ERR_get_error(), NULL));
				break;
			}
			/*將連接的socket加入到ssl*/
		    SSL_set_fd(pSSl,client_socket);
			
			/*建立ssl連接(握手)*/
		    if(SSL_accept(pSSl) <=  0)
		    {
				printf("%s %d iRet=%d %s\n",__func__,__LINE__,iRet,ERR_error_string(ERR_get_error(), NULL));
				break;
			}
			
			/*接收客戶端的消息*/
			iRet = SSL_read(pSSl, szBuf, sizeof(szBuf));
			if(iRet > 0)
			{
				printf("server recv text :%s \n",szBuf);
			}
			
			/*發送消息給客戶端*/
			SSL_write(pSSl, pRetStr, strlen(pRetStr));
			printf("%s %d \n",__func__,__LINE__);
			
			/*關閉ssl連接*/
			SSL_shutdown(pSSl);
			close(client_socket);
		}
	}while(0);

	if (pSSl)
	{
		SSL_free(pSSl);
		pSSl = NULL;
	}
	if (pCtx)
	{
		/*釋放SSL上下文環境變量函數*/
		SSL_CTX_free(pCtx);
		pCtx = NULL;
	}

	if(client_socket > 0)
	{
		close(client_socket);
	}

	if(listen_socket > 0)
	{
		close(client_socket);

	}

	
}


 

client.c

#include "stdio.h"
#include <net/if.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

const char* pHostAddr = "127.0.0.1";
const unsigned short u16Port = 10001;
const char* const pCAPath = "./CA/demoCA/cacert.pem";;

#define  VIRIFY_SERVER_CA 1
int main(int argc ,char*argv[])
{
	/*SSL庫初始化(一個進程只初始化一次)*/
	SSL_library_init();
	/*載入所有ssl錯誤消息*/
	SSL_load_error_strings();
	/*載入所有ssl算法*/
	OpenSSL_add_all_algorithms();
	
	const SSL_METHOD  *pMethod = SSLv23_method();
    SSL_CTX * pCtx =NULL; 
	SSL *pSSl = NULL;

	int iRet = -1;
	int remote_socket = -1;
	struct sockaddr_in remoteDevAddr;
	X509* pX509Cert = NULL;
	X509_NAME *pX509Subject = NULL;
	char szBuf[256]={0};
	char szSubject[1024]={0};
	char szIssuer[256]={0};
	do 
	{
		/*初始化SSL上下文環境變量函數*/
		pCtx = SSL_CTX_new(pMethod); 
		if(NULL == pCtx)
		{
			printf("%s %d iRet=%d %s\n",__func__,__LINE__,iRet,ERR_error_string(ERR_get_error(), NULL));
			break;

		}
#if VIRIFY_SERVER_CA
		/*加載CA證書(對端證書需要用CA證書來驗證)*/
		if(SSL_CTX_load_verify_locations(pCtx,pCAPath, NULL) !=1)
		{
			printf("%s %d iRet=%d %s\n",__func__,__LINE__,iRet,ERR_error_string(SSL_get_error(pSSl, iRet), NULL));
			break;
		}
		/*設置對端證書驗證*/
		SSL_CTX_set_verify(pCtx,SSL_VERIFY_PEER,NULL);
#endif
#if 0
		if (!SSL_CTX_set_cipher_list (pCtx, "ALL"))
		{
			printf("%s %d iRet=%d %s\n",__func__,__LINE__,iRet,ERR_error_string(SSL_get_error(pSSl, iRet), NULL));
			break;

		}
#endif
		memset(&remoteDevAddr,0,sizeof(remoteDevAddr));	   
		remoteDevAddr.sin_addr.s_addr=inet_addr(pHostAddr);
		remoteDevAddr.sin_family = AF_INET;
		remoteDevAddr.sin_port = htons(u16Port);

	    remote_socket = socket(AF_INET,SOCK_STREAM,0); /* Open the socket */
		if(remote_socket < 0)
		{
			printf("%s %d errno=%d\n",__func__,__LINE__,errno);
			break;
		}
		if(connect(remote_socket, (struct sockaddr *)&remoteDevAddr, sizeof (remoteDevAddr)) < 0)
		{
			printf("%s %d errno=%d\n",__func__,__LINE__,errno);
			break;
		}
		
		/*基於pCtx產生一個新的ssl*/
	    pSSl = SSL_new(pCtx);
		if(NULL  == pSSl)
	    {
			printf("%s %d iRet=%d %s\n",__func__,__LINE__,iRet,ERR_error_string(ERR_get_error(), NULL));
			break;
		}
		/*將連接的socket加入到ssl*/
	    SSL_set_fd(pSSl,remote_socket);
		
		/*ssl握手*/
		iRet = SSL_connect(pSSl);
	    if(iRet <  0)
	    {
			printf("%s %d iRet=%d %s\n",__func__,__LINE__,iRet,ERR_error_string(SSL_get_error(pSSl, iRet), NULL));
			break;
		}
#if VIRIFY_SERVER_CA		
		/*獲取驗證對端證書的結果*/
		if(X509_V_OK  != SSL_get_verify_result(pSSl))
		{
			printf("%s %d iRet=%d %s\n",__func__,__LINE__,iRet,ERR_error_string(ERR_get_error(), NULL));
			break;
		}
		
		/*獲取對端證書*/
		pX509Cert = SSL_get_peer_certificate(pSSl);

		if( NULL == pX509Cert)
		{
			printf("%s %d iRet=%d %s\n",__func__,__LINE__,iRet,ERR_error_string(ERR_get_error(), NULL));
			break;
		}
		
		/*獲取證書使用者屬性*/
		pX509Subject = X509_get_subject_name(pX509Cert);
		if( NULL == pX509Subject)
		{
			printf("%s %d iRet=%d %s\n",__func__,__LINE__,iRet,ERR_error_string(SSL_get_error(pSSl, iRet), NULL));
			break;
		}

        X509_NAME_oneline(pX509Subject, szSubject, sizeof(szSubject) -1);
        X509_NAME_oneline(X509_get_issuer_name(pX509Cert), szIssuer, sizeof(szIssuer) -1);		
		X509_NAME_get_text_by_NID(pX509Subject, NID_commonName, szBuf, sizeof(szBuf)-1);
		printf("szSubject =%s \nszIssuer =%s\n  commonName =%s\n",szSubject,szIssuer,szBuf);
#endif		
		SSL_write(pSSl, "hello ssl", strlen("hello ssl"));
		printf("client send text:\"hello ssl\" to server\n");
		SSL_shutdown(pSSl);
	}while(0);
#if VIRIFY_SERVER_CA

	if(pX509Cert)
	{
    	X509_free (pX509Cert);
	}
#endif
	if (pSSl)
	{
		SSL_free(pSSl);
		pSSl = NULL;
	}
	if (pCtx)
	{
		SSL_CTX_free(pCtx);
		pCtx = NULL;
	}

	if(remote_socket > 0)
	{
		close(remote_socket);
	}

	
}

Makefile:

all:server client
.PHONY:all

server:server.c
	gcc $^ -o $@ -Wall -g -lssl
	
client:client.c
	gcc $^ -o $@ -Wall -g -lssl

.PHONY:clean
clean:
	rm -f server client

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章