下面實例中使用的證書請參考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