OpenSSL在蘋果手機推送中的使用

opensslshiy流程:
1.初始化; SSLv23_client_method();建立SSL上下文環境 SSL_CTX_new ()
2.建立socket,connect;校驗證書;
3.socket綁定SSL:SSL_new,SSL_connect;
4.校驗服務器證書;
5.SSL_write,SSL_read;
6.釋放資源 SSL_shutdown等;
////openssl
//author:jordan.sg  QQ:87895224  
//2012.7 
//初始化部分 
SSL_library_init(); 
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();

//校驗服務器
bool CWorker::verifyServer(APP_SERVER *ptserver)
{
	/* Following two steps are optional and not required for
     data exchange to be successful. */

	/* Set for server verification*/
	SSL_CTX_set_verify(ptserver->psslctx,SSL_VERIFY_PEER,NULL);

	/* Get the cipher - opt */
#ifdef _DEBUG
	LogExt(LOG_LOG_LEVEL,"SSL connection using %s\n", SSL_get_cipher(ptserver->ssl));
#endif
	/* Get server's certificate (note: beware of dynamic allocation) - opt */

	ptserver->server_cert = SSL_get_peer_certificate (ptserver->ssl);       
	if (!ptserver->server_cert) 
	{
		writelogimmediatly("[exception]SSL_get_peer_certificate \n");
		setallthreadexitflag();
		return false;
	}
#ifdef _DEBUG
	LogExt(LOG_LOG_LEVEL,"Server certificate:\n");
#endif
	char*  str = X509_NAME_oneline (X509_get_subject_name (ptserver->server_cert),0,0);
	if (!str) 
	{
		writelogimmediatly("[exception]X509_NAME_oneline\n");
		setallthreadexitflag();
		return false;
	}

#ifdef _DEBUG
	LogExt(LOG_LOG_LEVEL,"\t subject: %s\n", str);
//subject: /C=US/ST=California/L=Cupertino/O=Apple Inc./OU=iTMS Engineering/CN=gateway.sandbox.push.apple.com
//issuer: /C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C
#endif

	OPENSSL_free (str);

	str = X509_NAME_oneline (X509_get_issuer_name(ptserver->server_cert),0,0);
	if (!str) 
	{
		writelogimmediatly("[exception]X509_NAME_oneline.\n");
		setallthreadexitflag();
		return false;
	}

#ifdef _DEBUG
	LogExt(LOG_LOG_LEVEL,"\t issuer: %s\n", str);
#endif

	OPENSSL_free (str);

	/* We could do all sorts of certificate verification stuff here before
	 deallocating the certificate. */

	X509_free (ptserver->server_cert);

	return true;
}
//本機校驗
bool CWorker::caVerify(APP_SERVER *ptserver)
{
	/* define HOME to be dir for key and certificate files... */
	//#define HOME "/certs/"
	/* Make these what you want for certificate & key files */
	#define CERT_FILE  ptserver->pemfile   ///// HOME "1024ccert.pem"
	#define KEY_FILE   ptserver->pemfile
		
		/*Cipher list to be used*/
	#define CIPHER_LIST "AES128-SHA"
		
		/*Trusted CAs location*/
	#define CA_FILE  ptserver->pemfile   ////"/certs/1024ccert.pem"
	#define CA_DIR  NULL
	
	/*Set cipher list*/
	if (SSL_CTX_set_cipher_list(ptserver->psslctx,CIPHER_LIST) <= 0) 
	{
		writelogimmediatly("[exception][CWorker][SSL]Error setting the cipher list.\n");
	    setallthreadexitflag();
		return false ;
	}

	/*Indicate the certificate file to be used*/

string pathfile=getExePath();
    pathfile+="\\";
	pathfile+=ptserver->pemfile;
	if (SSL_CTX_use_certificate_file(ptserver->psslctx, pathfile.c_str(), SSL_FILETYPE_PEM) <= 0) 
	{

		string errstr("[err][SSL]Error setting the certificate file");
		const char * pc=ERR_reason_error_string(ERR_get_error());
		errstr.append(pc?pc:"!\n");
		errstr.append("\n");
		writelogimmediatly(errstr.c_str() );

		setallthreadexitflag();
		return false;
	}


	/*Load the password for the Private Key*/
	SSL_CTX_set_default_passwd_cb_userdata(ptserver->psslctx, (void*)g_cfg.pem_psw.c_str());

	pathfile=getExePath();
	pathfile+= "\\";
	pathfile+=KEY_FILE;
	/*Indicate the key file to be used*/
	if (SSL_CTX_use_PrivateKey_file(ptserver->psslctx, pathfile.c_str(), SSL_FILETYPE_PEM) <= 0) 
	{
		writelogimmediatly("[exception][CWorker][SSL]Error setting the key file.\n");
		setallthreadexitflag();
		return false;
	}

	/*Make sure the key and certificate file match*/
	if (SSL_CTX_check_private_key(ptserver->psslctx) == 0) {
		writelogimmediatly("[log][CWorker][SSL]Private key does not match the certificate public key\n");
		setallthreadexitflag();
		return false;
	}

	/* Set the list of trusted CAs based on the file and/or directory provided*/
	pathfile=getExePath();
	pathfile+= "\\";
	pathfile+=CA_FILE;
	if(SSL_CTX_load_verify_locations(ptserver->psslctx, pathfile.c_str(), CA_DIR)<1) {
		writelogimmediatly("[log][CWorker][SSL]Error setting verify location\n");
		setallthreadexitflag();
		return false;
	}

	return true;

}
//鏈接到蘋果的服務器
bool CWorker::connectToServer(const char *hostname,int port,APP_SERVER *ptserver)
{
#ifdef _DEBUG
	writelogimmediatly("connectToServer start\n");
#endif

	//set client using SSL version
	ptserver->meth = (SSL_METHOD *)SSLv23_client_method();
	

	//建立SSL上下文環境 
	ptserver->psslctx = SSL_CTX_new (ptserver->meth);
	if(!ptserver->psslctx)
	{
	   writelogimmediatly("[err]SSL_CTX_new: NULL\n");
	   //LogExt(LOG_LOG_LEVEL,"Error: %s\n", ERR_reason_error_string(ERR_get_error()));
	   return false;
	}

	caVerify(ptserver);	
	/* ----------------------------------------------- */
	/* Create a socket and connect to server using normal socket calls. */
	
	ptserver->sd = socket (AF_INET, SOCK_STREAM, 0);       
	if(SOCKET_ERROR == ptserver->sd)
	{
		writelogimmediatly("[err][connectToServer]socket\n");
		return false;
	}

    if(!nonblock_connect(ptserver->sd,ptserver->sa,hostname,port))
	{
		return false;
	}
	
	/* ----------------------------------------------- */
	/* Now we have TCP conncetion. Start SSL negotiation. */
	ptserver->ssl = SSL_new (ptserver->psslctx);  
	if(!ptserver->ssl)
	{	
		string errstr("[err][SSL_new]");
		const char * pc=ERR_reason_error_string(ERR_get_error());
		errstr.append(pc?pc:"fail!\n");		
		writelogimmediatly(errstr.c_str() );
		return false;
	}
	SSL_set_fd (ptserver->ssl, ptserver->sd);
	SSL_set_mode(ptserver->ssl, SSL_MODE_AUTO_RETRY);

#ifdef NONEBLOCK_SOCKET

CONN_RE:

	ptserver->err = SSL_connect (ptserver->ssl); 
	if(1 == ptserver->err)
	{
#ifdef _DEBUG
		LogExt(LOG_LOG_LEVEL,"The TLS/SSL handshake was successfully completed, a TLS/SSL connection has been established.\n");
#endif
	}
	else if(-1 == ptserver->err)
	{		
		ptserver->err = SSL_get_error(ptserver->ssl,ptserver->err);
		if (SSL_ERROR_WANT_READ==ptserver->err || SSL_ERROR_WANT_WRITE==ptserver->err)
		{
			goto CONN_RE;
		}
		string errstr("[err][SSL_connect]fail!\n");
		writelogimmediatly(errstr.c_str() );
		return false;
	}

#else

	ptserver->err = SSL_connect (ptserver->ssl); 
	if(1 == ptserver->err)
	{
		LogExt(LOG_LOG_LEVEL,"The TLS/SSL handshake was successfully completed, a TLS/SSL connection has been established.\n");
	}
	else if(-1 == ptserver->err)
	{		
		string errstr("[err][SSL_connect]");
		const char * pc=ERR_reason_error_string(ERR_get_error());
		errstr.append(pc?pc:"fail!\n");
		writelogimmediatly(errstr.c_str() );
		return false;
	}
#endif
	// 檢查證書是否有效 
	//20 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: unable to get local issuer certificate
	//	the issuer certificate could not be found: this occurs if the issuer certificate of an untrusted certificate cannot be found.

	int ret_ssl=0;
	if(X509_V_OK !=  ( ret_ssl=SSL_get_verify_result(ptserver->ssl)))
	{
		LogExt(LOG_LOG_LEVEL,"SSL_get_verify_result =>%d\n",ret_ssl);
	}
	
	return true;
}

//鏈接到Feedback沙盒測試服務器
bool CWorker::connectToFeedbackSandBoxServer()
{	
	bool ret = connectToServer(g_cfg.feedback_sandbox_www.c_str(),g_cfg.feedback_sandbox_port,&this->feed);
	if (ret)
	{
		verifyServer(&this->feed);
	}

	return ret;
}

//讀取Feedback
void CWorker::getFeedback()
{
	bool ret = false;
	if ( IsSandBox())
	{
		ret = connectToFeedbackSandBoxServer();	
	}
	else
	{
		ret = connectToFeedbackServer();
	}
	
	//讀feedback
	if (ret)
	{
		readFeedbackSub();
	}
		 
	stopSSLFeed();
}
//發送推送信息
void CWorker::sendtoAPNs()
{
	bool ret = false;
	if ( IsSandBox())
	{
		ret = connectToAPNsSandBox();	
	}
	else
	{
		ret = connectToAPNs();
	}
	
	if (ret)
	{
		//找到開始的一條信息,開始的一個設備
		string current_info_id("");//send_id char12
		UINT   current_device_id=0;
		string current_device_token("");
		
		StartSend(current_info_id,current_device_token,&current_device_id);
		if (!current_info_id.empty() && !current_device_token.empty() )
		{
			batchSendtoApns(current_info_id,current_device_token,current_device_id);
		}
		
		//
		
	}
	stopSSLApns(); 
	
}

void CWorker::stopSSLFeed()
{

	if (feed.ssl)
	{
		SSL_shutdown (feed.ssl);  /* send SSL/TLS close_notify */
		
		close (feed.sd);
		SSL_free (feed.ssl);
		SSL_CTX_free (feed.psslctx);
	}
	feed.ssl=NULL;


}
相關文章
相關標籤/搜索