Exemplo n.º 1
0
/*
 * CheckBodyHash()
 *
 * Validate the message according to rfc6376
 */
void Validatory::CheckBodyHash(const DKIM::Signature& sig)
	throw (DKIM::PermanentError)
{
	std::unique_ptr<EVP_MD_CTX, std::function<void(EVP_MD_CTX*)>> evpmdbody(EVP_MD_CTX_create(), [] (EVP_MD_CTX* p) { EVP_MD_CTX_destroy(p); });

	// create signature for our body (message data)
	switch (sig.GetDigestAlgorithm())
	{
		case DKIM::DKIM_A_SHA1:
			EVP_DigestInit_ex(evpmdbody.get(), EVP_sha1(), nullptr);
			break;
		case DKIM::DKIM_A_SHA256:
			EVP_DigestInit_ex(evpmdbody.get(), EVP_sha256(), nullptr);
			break;
	}

	DKIM::Conversion::EVPDigest evpupd;
	evpupd.ctx = evpmdbody.get();

	CanonicalizationBody(m_file,
			sig.GetCanonModeBody(),
			m_msg.GetBodyOffset(),
			sig.GetBodySizeLimit(),
			sig.GetBodySize(),
			std::bind(&DKIM::Conversion::EVPDigest::update, &evpupd, std::placeholders::_1, std::placeholders::_2));

	unsigned char md_value[EVP_MAX_MD_SIZE];
	unsigned int md_len;
	EVP_DigestFinal_ex(evpmdbody.get(), md_value, &md_len);

	if (sig.GetBodyHash().size() != md_len ||
			memcmp(sig.GetBodyHash().c_str(), md_value, md_len) != 0)
	{
		throw DKIM::PermanentError("Body hash did not verify");
	}
}
Exemplo n.º 2
0
/*
 * GetSignature()
 *
 * Get the signature from supported header iterator
 */
void Validatory::GetSignature(const Message::HeaderList::const_iterator& headerIter,
		DKIM::Signature& sig)	
	throw (DKIM::PermanentError)
{
	sig.Parse((*headerIter)->GetHeader().substr((*headerIter)->GetValueOffset()));

	// create signature for our body (message data)
	switch (sig.GetAlgorithm())
	{
		case DKIM::DKIM_A_SHA1:
			EVP_DigestInit(&m_ctx_body, EVP_sha1());
			break;
		case DKIM::DKIM_A_SHA256:
			EVP_DigestInit(&m_ctx_body, EVP_sha256());
			break;
	}

	CanonicalizationBody canonicalbody(sig.GetCanonModeBody());

	// if we should limit the size of the body we hash
	bool limitBody = sig.GetBodySizeLimit();
	size_t bodySize = sig.GetBodySize();

	// if we have a message: seek to GetBodyOffset()
	if (m_msg.GetBodyOffset() != -1)
	{
		m_file.clear();
		m_file.seekg(m_msg.GetBodyOffset(), std::istream::beg);

		std::string s;
		while (std::getline(m_file, s) || m_file.peek() != EOF)
		{
			// double dots (postfix file may have .., instead of .)
			if (m_doubleDots && s.substr(0, 2) == "..")
			{
				s.erase(0, 1);
			}

			// remove possible \r (if not removed by getline *probably not*)
			if (s.size() > 0 && s[s.size()-1] == '\r')
				s.erase(s.size()-1);

			// canonical body
			std::vector<std::string> output;
			if (canonicalbody.FilterLine(s, output))
			{
				for (std::vector<std::string>::const_iterator i = output.begin();
						i != output.end(); ++i)
				{
					if (limitBody && bodySize == 0) break;
#ifdef DEBUG
					if (*i == "\r\n") printf("[CRLF]\n");
					else printf("[%s]\n", i->c_str());
#endif
					EVP_DigestUpdate(&m_ctx_body, i->c_str(),
							limitBody?std::min(i->size(), bodySize):i->size());
					bodySize -= std::min(i->size(), bodySize);
				}
			}
		}
	}

	// else call (Done) -- which may insert a last CRLF if the body was empty
	if (m_msg.GetBodyOffset() != -1 || m_file.peek() == EOF)
	{
		std::vector<std::string> output;
		if (canonicalbody.Done(output))
		{
			for (std::vector<std::string>::const_iterator i = output.begin();
					i != output.end(); ++i)
			{
				if (limitBody && bodySize == 0) break;
#ifdef DEBUG
				if (*i == "\r\n") printf("[CRLF]\n");
				else printf("[%s]\n", i->c_str());
#endif
				EVP_DigestUpdate(&m_ctx_body, i->c_str(),
						limitBody?std::min(i->size(), bodySize):i->size());
				bodySize -= std::min(i->size(), bodySize);
			}
		}
	}

	unsigned char md_value[EVP_MAX_MD_SIZE];
	unsigned int md_len;
	EVP_DigestFinal_ex(&m_ctx_body, md_value, &md_len);
	EVP_MD_CTX_cleanup(&m_ctx_body);

	if (sig.GetBodyHash().size() != md_len ||
			memcmp(sig.GetBodyHash().c_str(), md_value, md_len) != 0)
	{
		throw DKIM::PermanentError("Body hash did not verify");
	}
}