?? sslclientsocket.cpp
字號:
// SslClientSocket.cpp : implementation file
//
#include "stdafx.h"
#include "Raclient.h"
#include "SslClientSocket.h"
#include "MainFrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CSslClientSocket
CSslClientSocket::CSslClientSocket()
{
m_Ctx=NULL;
m_Ssl=NULL;
m_AuditList=NULL;
m_MadeList=NULL;
m_RevokeList=NULL;
m_ifCert=false;
m_ifCrl=false;
m_MaxCount=0;
}
CSslClientSocket::~CSslClientSocket()
{
}
// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CSslClientSocket, CAsyncSocket)
//{{AFX_MSG_MAP(CSslClientSocket)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif // 0
/////////////////////////////////////////////////////////////////////////////
// CSslClientSocket member functions
X509 * CSslClientSocket::load_cert(BIO *cert/*輸入BIO*/, int format/*格式*/,char * pwd,/*P12密碼*/char * outMsg)
{
ASN1_HEADER *ah=NULL;
BUF_MEM *buf=NULL;
X509 *x=NULL;
if (format == DER)
x=d2i_X509_bio(cert,NULL);
else if (format == PEM)
x=PEM_read_bio_X509(cert,NULL,NULL,NULL);//PEM_read_bio_X509_AUX
else if (format == P12)
{
PKCS12 *p12 = d2i_PKCS12_bio(cert, NULL);
PKCS12_parse(p12, pwd, NULL, &x, NULL);
PKCS12_free(p12);
p12 = NULL;
}
else
{
sprintf(outMsg,"bad input format specified for input cert\n");
goto end;
}
end:
if (x == NULL)
{
sprintf(outMsg,"unable to load certificate\n");
}
if (ah != NULL) ASN1_HEADER_free(ah);
if (buf != NULL) BUF_MEM_free(buf);
return(x);
}
X509 * CSslClientSocket::LoadCert(char * cert,int certlen,char * outMsg)//枚舉DER/PEM格式
{
BIO * in=NULL;
X509 * x509=NULL;
if(certlen==0)//輸入為磁盤文件
{
if((in=BIO_new_file(cert, "r")) == NULL)
{
sprintf(outMsg,"open CA certificate file error");
return NULL;
}
}
else//輸入為內存中文件
{
if((in=BIO_new_mem_buf(cert,certlen))== NULL)//只讀類型
{
sprintf(outMsg,"Make Mem Bio Error");
return NULL;
}
}
if((x509=load_cert(in,DER,NULL,outMsg))==NULL)//嘗試DER
{
BIO_reset(in);//恢復bio
x509=load_cert(in,PEM,NULL,outMsg);//嘗試PEM
}
if (in != NULL) BIO_free(in);
return x509;
}
EVP_PKEY * CSslClientSocket::load_key(BIO *bio, int format, char *pass,char * outMsg)
{
EVP_PKEY *pkey=NULL;
if (format == DER)
{
pkey=d2i_PrivateKey_bio(bio, NULL);
}
else if (format == PEM)
{
pkey=PEM_read_bio_PrivateKey(bio,NULL,NULL,pass);
}
else if (format == P12)
{
PKCS12 *p12 = d2i_PKCS12_bio(bio, NULL);
PKCS12_parse(p12, pass, &pkey, NULL, NULL);
PKCS12_free(p12);
p12 = NULL;
}
else
{
sprintf(outMsg,"bad input format specified for key\n");
goto end;
}
end:
if (pkey == NULL)
sprintf(outMsg,"unable to load Private Key\n");
return(pkey);
}
EVP_PKEY * CSslClientSocket::LoadKey(char * key,int keylen,char * pass,char * outMsg)
{
EVP_PKEY *pkey=NULL;
BIO * in=NULL;
if(keylen==0)//輸入為磁盤文件
{
if((in=BIO_new_file(key, "r")) == NULL)
{
sprintf(outMsg,"open CA certificate file error");
return NULL;
}
}
else//輸入為內存中文件
{
if((in=BIO_new_mem_buf(key,keylen))== NULL)//只讀類型
{
sprintf(outMsg,"Make Mem Bio Error");
return NULL;
}
}
if((pkey=load_key(in,DER,pass,outMsg))==NULL)//嘗試DER
{
BIO_reset(in);//BIO是可讀寫的,那么該BIO所有數據都會被清空;
//如果該BIO是只讀的,那么該操作只會簡單將指
//針指向原始位置,里面的數據可以再讀.
pkey=load_key(in,PEM,pass,outMsg);//嘗試PEM
}
if (in != NULL) BIO_free(in);
return pkey;
}
BOOL CSslClientSocket::SockConnect(SSL_METHOD *meth,char *certfile,int certlen, char *keyfile,int keylen,
char * cafile, char * capath,LPCTSTR lpszHostAddress, UINT nHostPort,char * out)
{
EVP_PKEY *pkey=NULL;
X509 *x509=NULL;
CString str;
unsigned long l=1;
BIO * sbio=NULL;
struct hostent *hp;
struct sockaddr_in addr;
int sock,i=0;
// m_pList=plist;/////////////////////
OpenSSL_add_ssl_algorithms();
m_Ctx=SSL_CTX_new(meth);
if (m_Ctx == NULL)
{
strcpy(out,"Create ctx error");
return FALSE;
}
SSL_CTX_set_options(m_Ctx,SSL_OP_ALL);
pkey=LoadKey(keyfile,keylen,NULL,out);
if (pkey == NULL)
{
sprintf(out,"unable to load CA private key\n");
m_Ctx=NULL;
goto err;
}
if(!(SSL_CTX_use_PrivateKey(m_Ctx,pkey)))
{
strcpy(out,"adds private key to ctx error");
SSL_CTX_free(m_Ctx);
m_Ctx=NULL;
goto err;
}
x509=LoadCert(certfile,certlen,out);
if (x509 == NULL)
{
sprintf(out,"unable to load CA certificate\n");
SSL_CTX_free(m_Ctx);
m_Ctx=NULL;
goto err;
}
if(!(SSL_CTX_use_certificate(m_Ctx,x509)))
{
strcpy(out,"loads certificate into ctx error");
SSL_CTX_free(m_Ctx);
m_Ctx=NULL;
goto err;
}
if (!SSL_CTX_check_private_key(m_Ctx))
{
strcpy(out,"Private key does not match the certificate public key");
SSL_CTX_free(m_Ctx);
m_Ctx=NULL;
goto err;
}
/* Load the CAs we trust*/
if(!(SSL_CTX_load_verify_locations(m_Ctx,cafile,/*capath*/NULL)))
{
strcpy(out,"Couldn't read CA list");
SSL_CTX_free(m_Ctx);
m_Ctx=NULL;
goto err;
}
SSL_CTX_set_verify_depth(m_Ctx,1);
SSL_CTX_set_client_CA_list(m_Ctx,SSL_load_client_CA_file(cafile));
m_Ssl=SSL_new(m_Ctx);
if(m_Ssl==NULL)
{
strcpy(out,"Make SSL Error");
goto err;
}
/* Load randomness */
// Rand(NULL,1,out);
/*連接服務器*/
if(!(hp=gethostbyname(lpszHostAddress)))
{
strcpy(out,"Couldn't resolve host");
return FALSE;
}
memset(&addr,0,sizeof(addr));
addr.sin_addr=*(struct in_addr*)hp->h_addr_list[0];
addr.sin_family=AF_INET;
addr.sin_port=htons(nHostPort);
sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (sock == INVALID_SOCKET)
{
strcpy(out,"create socket error");
return FALSE;
}
i=setsockopt(sock,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
if (i < 0)
{
strcpy(out,"setsockopt error");
return FALSE;
}
if (connect(sock,(struct sockaddr *)&addr,sizeof(addr)) == -1)
{
shutdown(sock,2);
closesocket(sock);
strcpy(out,"connect error");
return FALSE;
}
/* Connect the SSL socket */
if (BIO_socket_ioctl(sock,FIONBIO,&l) < 0)
{
strcpy(out,"io set error");
shutdown(sock,2);
closesocket(sock);
SSlShouDown();
return FALSE;
}
sbio=BIO_new_socket(sock,BIO_NOCLOSE);
SSL_set_bio(m_Ssl,sbio,sbio);
SSL_set_connect_state(m_Ssl);
Attach(sock, FD_CLOSE);
str.Format("%d接入服務器%s,等待握手....",m_hSocket,inet_ntoa(addr.sin_addr));
// m_pList->AddMsg(str,M_WARING);
return TRUE;
err:
EVP_PKEY_free(pkey);
X509_free(x509);
SSlShouDown();
return FALSE;
}
int CSslClientSocket::SSlConnect(char * out)
{
if(m_Ssl==NULL)
{
strcpy("SSL沒有正確初始化",out);
return -1;
}
int err=0;
if ((err = SSL_connect(m_Ssl)) <= 0)
{
if (BIO_sock_should_retry(err))
{
return 0;//重試
}
else
{
strcpy(out,"SSL連接失敗");//ERR_clear_error
return -1;
}
}
return 1;
}
void CSslClientSocket::SSlShouDown()
{
if(m_Ctx!=NULL)
{
SSL_CTX_free(m_Ctx);
m_Ctx=NULL;
}
if(m_Ssl!=NULL)
{
SSL_shutdown(m_Ssl);
SSL_free(m_Ssl);
m_Ssl=NULL;
}
stuLIST * LIST=NULL;
for(;!m_ComList.IsEmpty();)
{
LIST=(stuLIST *)m_ComList.RemoveHead();
delete LIST;
}
ShutDown(2);
Close();
}
int CSslClientSocket::SSlSend(char *buf, int len)
{
if(m_Ssl==NULL)
return -1;
int k=0;//接收數量
int offect=0;//偏移
for(;0!=len;)//maximum record size of 16kB for SSLv3/TLSv1
{
k = SSL_write(m_Ssl,buf+offect,len);
if (k <= 0)
{
if (BIO_sock_should_retry(k))
{
((CMainFrame *)AfxGetMainWnd())->AddDialogBarInfo(0,"SSlSend",M_WARING);
Sleep(100);
continue;
}
}
offect+=k;//接收到數據
len-=k;
}
AsyncSelect(FD_READ|FD_CLOSE);//選擇讀(發送一條處理一條)
return offect;
}
int CSslClientSocket::SSlReceive(char * buf, int len)
{
int k=0;
do
{
for(;;)
{
k = SSL_read(m_Ssl,buf,len);
if (k <=0)
{
if (BIO_sock_should_retry(k))
{
((CMainFrame *)AfxGetMainWnd())->AddDialogBarInfo(0,"SSlReceive",M_WARING);
Sleep(100);
continue;//重試
}
return k;//錯誤退出
}
break;//成功
}
}while (SSL_pending(m_Ssl));
return k;
/*如果對方一次性發送〉16k(16384),最大只能收到16k,SSL_pending返回0,
如果接收len<16k,則SSL_pending返回(16k-len)*/
}
void CSslClientSocket::InsertList(CListCtrl * pList,stuRA * pRa)
{
if(pList==NULL)
{
AfxMessageBox("InsertList Error");
return;
}
CString item;
char buf[48]={0};//最大長度48
item.Format("%d",pRa->ID);
LVFINDINFO Info;
Info.flags=LVFI_STRING;
Info.psz=item;
if(pList->FindItem(&Info,-1)!=-1)//存在
return;
pList->InsertItem(0,item);//ID
strncpy(buf,(char *)pRa->SUBJECT.CN,sizeof(pRa->SUBJECT.CN));
pList->SetItemText(0,1,buf);
ZeroMemory(buf,48);
strncpy(buf,(char *)pRa->SUBJECT.C,sizeof(pRa->SUBJECT.C));
pList->SetItemText(0,2,buf);
ZeroMemory(buf,48);
strncpy(buf,(char *)pRa->SUBJECT.ST,sizeof(pRa->SUBJECT.ST));
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -