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

📄 securesocketimpl.cpp.svn-base

📁 很好用的网络封装库,不熟悉网络编程的人也可以使用。使用风格良好的标准c++编写。
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:
			std::string errMsg = Utility::convertSSLError(_pSSL, rc);
		}
	}
	while (rc < 0 && _socket.lastError() == POCO_EINTR);
	if (rc < 0) SocketImpl::error();
	return rc;
}


int SecureSocketImpl::receiveBytes(void* buffer, int length, int flags)
{
	poco_assert (sockfd() != POCO_INVALID_SOCKET);
	poco_check_ptr (_pSSL);	

	int rc;
	bool renegotiating = false;
	do
	{
		rc = SSL_read(_pSSL, buffer, length);
		if (rc <= 0)
		{
			switch (SSL_get_error(_pSSL, rc))
			{
			case SSL_ERROR_ZERO_RETURN:
				// connection closed
				close();
				break;
			case SSL_ERROR_NONE:
			case SSL_ERROR_WANT_WRITE: //renegotiation
			case SSL_ERROR_WANT_READ: //renegotiation
				renegotiating = true;
				break;
			default:
				;
			}
		}
	}
	while (rc < 0 && _socket.lastError() == POCO_EINTR);
	if (rc < 0) 
	{
		if (renegotiating || _socket.lastError() == POCO_EAGAIN || _socket.lastError() == POCO_ETIMEDOUT)
			throw TimeoutException();
		else
			SocketImpl::error("failed to read bytes");
	}
	return rc;
}


int SecureSocketImpl::sendTo(const void* buffer, int length, const SocketAddress& address, int flags)
{
	throw NetException("sendTo not possible with SSL");
}


int SecureSocketImpl::receiveFrom(void* buffer, int length, SocketAddress& address, int flags)
{
	throw NetException("receiveFrom not possible with SSL");
}


void SecureSocketImpl::sendUrgent(unsigned char data)
{
	// SSL doesn't support out-of-band data
	sendBytes(reinterpret_cast<const void*>(&data), sizeof(data));
}


long SecureSocketImpl::postConnectionCheck(bool server, SSL* pSSL, const std::string& hostName)
{
	static std::string locHost("127.0.0.1");

	SSLManager& mgr = SSLManager::instance();
	Context::VerificationMode mode = server? mgr.defaultServerContext()->verificationMode() : mgr.defaultClientContext()->verificationMode();
	if (hostName == locHost && mode != Context::VERIFY_STRICT)
		return X509_V_OK;

	X509* cert = 0;
	X509_NAME* subj = 0;
	char* host = const_cast<char*>(hostName.c_str());
	
	int extcount=0;

	if (mode == Context::VERIFY_NONE) // should we allow none on the client side?
	{
		return X509_V_OK;
	}

	cert = SSL_get_peer_certificate(pSSL);
	
	// note: the check is used by the client, so as long we don't set None at the client we reject
	// cases where no certificate/incomplete info is presented by the server
	if ((!cert || !host) && mode != Context::VERIFY_NONE)
	{
		if (cert)
			X509_free(cert);
		return X509_V_ERR_APPLICATION_VERIFICATION;
	}

	bool ok = false;

	if ((extcount = X509_get_ext_count(cert)) > 0)
	{
		for (int i = 0; i < extcount && !ok; ++i)
		{
			const char* extstr = 0;
			X509_EXTENSION* ext;
			ext = X509_get_ext(cert, i);
			extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));

			if (!strcmp(extstr, "subjectAltName"))
			{
				X509V3_EXT_METHOD* meth = X509V3_EXT_get(ext);
				if (!meth)
					break;

#if OPENSSL_VERSION_NUMBER >= 0x00908000
				const unsigned char* pData = ext->value->data;
				const unsigned char** ppData = &pData;
#else
				unsigned char* pData = ext->value->data;
				unsigned char** ppData = &pData;
#endif
				STACK_OF(CONF_VALUE)* val = meth->i2v(meth, meth->d2i(0, ppData, ext->value->length), 0);

				for (int j = 0; j < sk_CONF_VALUE_num(val) && !ok; ++j)
				{
					CONF_VALUE* nval = sk_CONF_VALUE_value(val, j);
					if (!strcmp(nval->name, "DNS") && !strcmp(nval->value, host))
					{
						ok = true;
					}
				}
			}
		}
	}

	char data[256];
	if (!ok && (subj = X509_get_subject_name(cert)) && X509_NAME_get_text_by_NID(subj, NID_commonName, data, 256) > 0)
	{
		data[255] = 0;
		
		std::string strData(data); // commonName can contain wildcards like *.appinf.com
		try
		{
			// two cases: strData contains wildcards or not
			if (SecureSocketImpl::containsWildcards(strData))
			{
				// a compare by IPAddress is not possible with wildcards
				// only allow compare by name
				const HostEntry& heData = DNS::resolve(hostName);
				ok = SecureSocketImpl::matchByAlias(strData, heData);
			}
			else
			{
				// it depends on hostname if we compare by IP or by alias
				IPAddress ip;
				if (IPAddress::tryParse(hostName, ip))
				{
					// compare by IP
					const HostEntry& heData = DNS::resolve(strData);
					const HostEntry::AddressList& addr = heData.addresses();
					HostEntry::AddressList::const_iterator it = addr.begin();
					HostEntry::AddressList::const_iterator itEnd = addr.end();
					for (; it != itEnd && !ok; ++it)
					{
						ok = (*it == ip);
					}
				}
				else
				{
					// compare by name
					const HostEntry& heData = DNS::resolve(hostName);
					ok = SecureSocketImpl::matchByAlias(strData, heData);
				}
			}
		}
		catch(HostNotFoundException&)
		{
			if (cert)
				X509_free(cert);
			return X509_V_ERR_APPLICATION_VERIFICATION;
		}
	}

	if (cert)
		X509_free(cert);

	// we already have a verify callback registered so no need to ask twice SSL_get_verify_result(pSSL);
	if (ok)
		return X509_V_OK;

	return X509_V_ERR_APPLICATION_VERIFICATION;
}


void SecureSocketImpl::connectSSL(const SocketAddress& address)
{
	if (!_pSSL)
	{
		_pSSL = SSL_new(SSLManager::instance().defaultClientContext()->sslContext());
		SSL_set_bio(_pSSL, _pBIO, _pBIO);
	}
	std::string errMsg;

	int ret = SSL_connect(_pSSL);
	
	if (ret <= 0)
	{
		errMsg = Utility::convertSSLError(_pSSL, ret);
		throw SSLException(errMsg);
	}
	
	std::string serverName = address.host().toString();
	long errCode = 0;
	if (_endHost.empty())
		postConnectionCheck(false, _pSSL, serverName);
	else
		postConnectionCheck(false, _pSSL, _endHost);
	bool err = false;

	if (errCode != X509_V_OK)
	{
		err = true;
		errMsg = Utility::convertCertificateError(errCode);
	}
	else
	{
		int tmpSocket=0;
		BIO_get_fd(_pBIO,&tmpSocket);
		poco_assert (-1 != tmpSocket);
		setSockfd(tmpSocket);
	}

	if (err)
	{
		SSL_free(_pSSL); // dels _pBIO too
		_pSSL = 0;
		_pBIO = 0;
		invalidate();
		throw InvalidCertificateException(errMsg);
	}
}


void SecureSocketImpl::establishTunnel()
{
	if (!_endHost.empty())
	{
		poco_check_ptr (_pBIO);
		// send CONNECT proxyHost:proxyPort HTTP/1.0\r\n\r\n
		std::string connect("CONNECT ");
		connect.append(_endHost);
		connect.append(":");
		connect.append(Poco::NumberFormatter::format(_endPort));
		connect.append(" HTTP/1.0\r\n\r\n");
		int rc = BIO_write(_pBIO, (const void*) connect.c_str(), (int)(connect.length()*sizeof(char)));
		if (rc != connect.length())
			throw SSLException("Failed to establish connection to proxy");
		// get the response
		char resp[512];
		rc = BIO_read(_pBIO, resp, 512*sizeof(char));
		std::string response(resp);
		if (response.find("200") == std::string::npos)
			throw SSLException("Failed to establish connection to proxy");
	}
}


bool SecureSocketImpl::containsWildcards(const std::string& commonName)
{
	return (commonName.find('*') != std::string::npos || commonName.find('?') != std::string::npos);
}


bool SecureSocketImpl::matchByAlias(const std::string& alias, const HostEntry& heData)
{
	// fix wildcards
	std::string aliasRep = Poco::replace(alias, "*", ".*");
	Poco::replaceInPlace(aliasRep, "..*", ".*");
	Poco::replaceInPlace(aliasRep, "?", ".?");
	Poco::replaceInPlace(aliasRep, "..?", ".?");
	// compare by name
	Poco::RegularExpression expr(aliasRep);
	bool found = false;
	const HostEntry::AliasList& aliases = heData.aliases();
	HostEntry::AliasList::const_iterator it = aliases.begin();
	HostEntry::AliasList::const_iterator itEnd = aliases.end();
	for (; it != itEnd && !found; ++it)
	{
		found = expr.match(*it);
	}

	return found;
}


} } // namespace Poco::Net

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -