这里以生成客户端证书和密钥文件为例,目的是建立一个加密的安全的tcp连接
1 生成密钥文件
命令:openssl genrsa -des3 -out PK.pem 2048
会提示输入密钥短语,输入后还会让输入确认
2 生成证书文件
openssl req -new -x509 -key PK.pem -out CA.pem -days 365
验证代码片段:
// logout
#include <WinSock2.h>
#include "openssl/ossl_typ.h"
#include "openssl/bio.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "KKSock.h"
#pragma comment (lib,"WS2_32.lib")
#pragma comment( lib, "openssl/lib/libeay32.lib" )
#pragma comment( lib, "openssl/lib/ssleay32.lib" )
class CSSLClient
{
public:
CSSLClient();
~CSSLClient();
bool DoConnect();
void Reset();
int Hex2Chr(char *DstStr,char *HexStr,int HexLen);
int Chr2Hex(char c);
int CreateMessage(char *binaryMessageBuff,char *deviceTokenBinary, char *payloadBuff, size_t payloadLength);
void InitSSL();
private:
SSL_CTX *m_pctx;
SSL *m_pssl;
const SSL_METHOD *m_pmeth;
CKKSock m_tcpSocket;
};
// 代码里的CKKSock为一个封装的select模型的类,也可以使用原生的socket,执行阻塞或非阻塞操作
</pre><pre name="code" class="cpp">#include "SSLClient.h"
#include <Windows.h>
#include <string>
using namespace std;
CSSLClient::CSSLClient()
{
m_pssl = NULL;
m_pctx = NULL;
m_pmeth = NULL;
m_tcpSocket.InitSock();
}
CSSLClient::~CSSLClient()
{
}
void CSSLClient::Reset()
{
if(m_pssl)
{
SSL_shutdown(m_pssl);
SSL_free(m_pssl);
m_pssl = NULL;
}
if(m_pctx)
{
SSL_CTX_free(m_pctx);
m_pctx = NULL;
}
m_tcpSocket.Close();
}
void CSSLClient::InitSSL()
{
SSL_library_init();
SSL_load_error_strings();
}
bool CSSLClient::DoConnect()
{
//Reset();
int nErr;
bool bRet = false;
do
{
m_pmeth = SSLv23_client_method();// create ssl method
m_pctx = SSL_CTX_new(m_pmeth);
if (!m_pctx)
break;
SSL_CTX_set_options(m_pctx, SSL_OP_ALL);
char szPath[MAX_PATH + 1] = {0};
if (GetModuleFileName(NULL, szPath, MAX_PATH) == 0)
{
break;
}
for (int i = strlen(szPath); i > 0; i--)
{
if (szPath[i - 1] == '\\')
{
szPath[i - 1] = '\0';
break;
}
}
char szCAPath[MAX_PATH + 1] = {0};
char szPKPath[MAX_PATH + 1] = {0};
strcpy(szCAPath, szPath);
strcpy(szPKPath, szPath);
strcat(szCAPath, "\\CA.pem");
strcat(szPKPath, "\\PK.pem");
if (!SSL_CTX_use_certificate_file(m_pctx, szCAPath, SSL_FILETYPE_PEM))
break;
// 验证密码文件
BIO* pKeyBuff = BIO_new_file(szPKPath, "r");
if(NULL == pKeyBuff)
{
break;
}
//SSL_CTX_set_default_passwd_cb_userdata
char szPwd[16] = "111111";
EVP_PKEY *pkey = PEM_read_bio_PrivateKey(pKeyBuff, NULL, NULL, szPwd);
if(pkey==NULL)
{
break;
}
int nRetTmp = SSL_CTX_use_PrivateKey(m_pctx, pkey);
if (nRetTmp <= 0)
{
break;
}
bool bConnect = m_tcpSocket.ConnectEx("10.1.8.26", 10156, 3000);
if (!bConnect)
break;
/* An SSL structure is created */
m_pssl = SSL_new(m_pctx);
if(!m_pssl)
{
break;
}
if(SSL_get_verify_result(m_pssl) != X509_V_OK)
{
//X509证书无效
break;
}
/* Assign the socket into the SSL structure (SSL and socket without BIO) */
SSL_set_fd(m_pssl, m_tcpSocket.m_sock);
SSL_set_mode(m_pssl, SSL_MODE_AUTO_RETRY);
/* Perform SSL Handshake on the SSL client */
DWORD dwNow = GetTickCount();
while ((nRetTmp = SSL_connect(m_pssl)) <= 0)
{
int nLastErr = SSL_get_error(m_pssl, nRetTmp);
if (nLastErr != SSL_ERROR_WANT_READ && nLastErr != SSL_ERROR_WANT_WRITE)
{
char szErrMsg[1024] = {0};
ERR_error_string(ERR_get_error(), szErrMsg);
printf("err msg: %s\n", szErrMsg);
printf("lastErr: %d \n", nLastErr);
break;
}
Sleep(10);
}
printf("nRetTmp = %d\n", nRetTmp); //if nRetTmp > 0 means connect success
bRet = true;
char szReadBuffer[2048] = {0};
while (true)
{
//
memset(szReadBuffer, 0, sizeof(szReadBuffer));
nRetTmp = SSL_read(m_pssl, szReadBuffer, 2048); // read test
if (nRetTmp <= 0)
{
char szErrMsg[1024] = {0};
ERR_error_string(ERR_get_error(), szErrMsg);
printf("err msg: %s\n", szErrMsg);
int nLastErr = SSL_get_error(m_pssl, nRetTmp);
if (nLastErr != SSL_ERROR_WANT_READ && nLastErr != SSL_ERROR_WANT_WRITE)
{
//close connection
getchar();
break;
}
}
else
{
}
Sleep(100);
}
} while (false);
return bRet;
}