/* * 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"); } }
/* * 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"); } }