⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sslclientsocket.cpp

📁 基本实现了数字证书的制作、SSL安全通讯、加解密操作等功能
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// 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 + -