52#define _strnicmp strncasecmp
53#define _stricmp strcasecmp
54#define MAX_SIGNATURES 10
62int dig_ascii(
char *digascii,
unsigned const char *digest,
const int len)
64 static const char hextab[] =
"0123456789abcdef";
67 for (
j = 0;
j < len;
j++) {
68 digascii[2 *
j] = hextab[(
unsigned char)digest[
j] >> 4];
69 digascii[2 *
j + 1] = hextab[(
unsigned char)digest[
j] & 0x0f];
71 digascii[2 * len] =
'\0';
77int _DNSGetTXT(
const char *szFQDN,
char *Buffer,
int nBufLen)
87 switch (dns_txt(&
out,&
sa)) {
92 if (nBufLen <
out.len)
95 if (!stralloc_0(&
out))
return -1;
96 memcpy(Buffer,
out.s,
out.len);
105 FILE*
out = fopen(ResFile,
"wb+");
106 if (
out == NULL)
return -1;
109 len = strlen(result);
110 fwrite(result,1,len,
out);
111 fwrite(
"\r",1,1,
out);
115 fwrite(reason,1,strlen(reason),
out);
116 fwrite(
"\r",1,1,
out);
125 const char* errormsg =
"";
129 errormsg =
" (verify error: message is suspicious)";
132 errormsg =
" (signature error: could not parse or has bad tags/values)";
135 errormsg =
" (signature error: RSA/ED25519 verify failed)";
138 errormsg =
" (signature error: RSA/ED25519 verify failed but testing)";
141 errormsg =
" (signature error: signature x= value expired)";
144 errormsg =
" (signature error: selector doesn't parse or contains invalid values)";
147 errormsg =
" (signature error: selector g= doesn't match i=)";
150 errormsg =
" (signature error: revoked p= empty)";
153 errormsg =
" (dns error: selector domain name too long to request)";
156 errormsg =
" (dns error: temporary dns failure requesting selector)";
159 errormsg =
" (dns error: permanent dns failure requesting selector)";
162 errormsg =
" (signature error: selector p= value invalid or wrong format)";
165 errormsg =
" (process error: no signatures)";
168 errormsg =
" (process error: no valid signatures)";
171 errormsg =
" (signature verify error: message body does not hash to bh= value)";
174 errormsg =
" (signature error: selector h= doesn't match signature a=)";
177 errormsg =
" (signature error: incompatible v= value)";
180 errormsg =
" (signature error: not all message's From headers in signature)";
183 errormsg =
" (internal error: memory allocation failed)";
186 errormsg =
" (internal error: DKIMContext structure invalid for this operation)";
189 errormsg =
" (signing error: Could not find From: or Sender: header in message)";
192 errormsg =
" (signing error: Could not parse private key)";
195 errormsg =
" (signing error: Buffer passed in is not large enough)";
207#if ((OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L))
214#if (OPENSSL_VERSION_NUMBER > 0x10101000L)
215 m_Msg_ctx = EVP_MD_CTX_new();
226#if ((OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L))
234#if (OPENSSL_VERSION_NUMBER > 0x10101000L)
235 EVP_MD_CTX_reset(m_Msg_ctx);
241 return (ch ==
' ' || ch ==
'\t' || ch ==
'\r' || ch ==
'\n');
251 char *s = tagvaluelist;
269 }
while (isalnum(*s) || *s ==
'-');
292 while (*s !=
';' && ((*s ==
'\t' || *s ==
'\r' || *s ==
'\n') || (*s >=
' ' && *s <=
'~')))
308 while (e > value &&
isswsp(e[-1]))
315 for (
unsigned i = 0; wanted[i] != NULL; i++) {
316 if (strcmp(wanted[i],tag) == 0) {
318 if (values[i] != NULL)
336 if (ch >=
'0' && ch <=
'9')
338 else if (ch >=
'A' && ch <=
'F')
339 return (ch -
'A' + 10);
340 else if (ch >=
'a' && ch <=
'f')
341 return (ch -
'a' + 10);
355 while (*s !=
'\0' && *s !=
'=')
363 if (*s ==
'=' && isxdigit(s[1]) && isxdigit(s[2])) {
369 }
while (*s !=
'\0');
379 static const char base64_table[256] = {
380 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
381 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,
382 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
383 -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
384 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
385 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
386 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
387 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
389 unsigned char* s = (
unsigned char* )ptr;
390 unsigned char*
d = (
unsigned char* )ptr;
391 unsigned b64accum = 0;
392 unsigned char b64shift = 0;
395 unsigned char value = base64_table[*s++];
396 if ((
signed char) value >= 0) {
397 b64accum = (b64accum << 6) | value;
401 *
d++ = (b64accum >> b64shift);
406 return (
char* )
d-ptr;
421 const char* wildcard = strchr(
p,
'*');
422 if (wildcard == NULL) {
423 return strcmp(s,
p) == 0;
425 unsigned beforewildcardlen = wildcard -
p;
426 unsigned afterwildcardlen = strlen(wildcard + 1);
427 unsigned slen = strlen(s);
428 return (slen >= beforewildcardlen + afterwildcardlen) &&
429 (strncmp(s,
p,beforewildcardlen) == 0) && strcmp(s + slen - afterwildcardlen,wildcard + 1) == 0;
440 char* s = (
char* )str.c_str();
448 while (*from !=
'\0') {
452 for (
int depth = 1; depth != 0; from++) {
455 else if (*from ==
'(')
457 else if (*from ==
')')
459 else if (*from ==
'\\' && from[1] !=
'\0')
463 else if (*from ==
')') {
466 }
else if (*from ==
',' || *from ==
';') {
471 else if (*from ==
' ' || *from ==
'\t' || *from ==
'\r' || *from ==
'\n') {
474 }
else if (*from ==
'"') {
477 while (*from !=
'\0') {
481 }
else if (*from ==
'\\' && from[1] !=
'\0')
485 }
else if (*from ==
'\\' && from[1] !=
'\0') {
504 char *gt = strchr(start,
'>');
509 char *colon = strchr(start,
':');
511 char *at = strchr(start,
'@');
512 if (at == NULL || colon < at)
517 if (*start !=
'\0' && strchr(start,
'@') != NULL) {
518 Addresses.push_back(start);
524 return !Addresses.empty();
579 unsigned char *SignMsg;
580 unsigned SuccessCount = 0;
581 int TestingFailures = 0;
582 int RealFailures = 0;
585 list<string> SuccessfulDomains;
589 if (!i->BodyHashData.empty()) {
590 unsigned char md[EVP_MAX_MD_SIZE];
593#if ((OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L))
594 res = EVP_DigestFinal(&i->m_Bdy_ctx,md,&len);
596 res = EVP_DigestFinal_ex(i->m_Bdy_ctx,md,&len);
597 EVP_MD_CTX_reset(i->m_Bdy_ctx);
602 if (!res || len != i->BodyHashData.length() || memcmp(i->BodyHashData.data(),md,len) != 0) {
606 if (i->m_pSelector->Testing) {
622 string sSignedSig = i->Header;
623 string sSigValue = sSignedSig.substr(sSignedSig.find(
':') + 1);
625 static const char* tags[] = {
"b",NULL};
626 char* values[
sizeof(tags)/
sizeof(tags[0])] = {NULL};
628 char* pSigValue = (
char* ) sSigValue.c_str();
630 sSignedSig.erase(15 + values[0] - pSigValue,strlen(values[0]));
639 sSignedSig.replace(0,14,
"dkim-signature",14);
642 i->Hash(sSignedSig.c_str(),sSignedSig.length());
643 assert(i->m_pSelector != NULL);
645 if (EVP_PKEY_base_id(i->m_pSelector->PublicKey) != EVP_PKEY_ED25519)
646#if ((OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L))
647 res = EVP_VerifyFinal(&i->m_Hdr_ctx,(
unsigned char *)i->SignatureData.data(),i->SignatureData.length(),i->m_pSelector->PublicKey);
649 res = EVP_VerifyFinal(i->m_Hdr_ctx,(
unsigned char *)i->SignatureData.data(),i->SignatureData.length(),i->m_pSelector->PublicKey);
651#if (OPENSSL_VERSION_NUMBER > 0x10101000L)
652 else if (EVP_PKEY_base_id(i->m_pSelector->PublicKey) == EVP_PKEY_ED25519) {
653 EVP_DigestVerifyInit(i->m_Msg_ctx,NULL,NULL,NULL,i->m_pSelector->PublicKey);
655 SignMsg = (
unsigned char *)
SigHdr.data();
656 res = EVP_DigestVerify(i->m_Msg_ctx,(
unsigned char *)i->SignatureData.data(),(
size_t)i->SignatureData.length(),
662 if (i->UnverifiedBodyCount == 0)
667 SuccessfulDomains.push_back(i->Domain);
670 if (i->m_pSelector->Testing) {
692 if (
_strnicmp(i->c_str(),
"From",4) == 0) {
694 const char* s = i->c_str() + 4;
695 while (*s ==
' ' || *s ==
'\t')
698 vector<string> Addresses;
700 unsigned atpos = Addresses[0].find(
'@');
701 sFromDomain = Addresses[0].substr(atpos + 1);
711 if (SuccessCount > 0 && !sFromDomain.empty()) {
712 for (list<string>::iterator i = SuccessfulDomains.begin(); i != SuccessfulDomains.end(); ++i) {
714 if (i->length() > sFromDomain.length())
716 if (
_stricmp(i->c_str(),sFromDomain.c_str() + sFromDomain.length() - i->length()) != 0)
718 if (i->length() == sFromDomain.length() || sFromDomain.c_str()[sFromDomain.length() - i->length() - 1] ==
'.') {
739 if(nBufLength == 2 && szBuffer[0] ==
'\r' && szBuffer[1] ==
'\n')
743 char* szDbg =
new char[nBufLength+1];
744 strncpy(szDbg, szBuffer, nBufLength);
745 szDbg[nBufLength] =
'\0';
746 printf(
"[%s]\n", szDbg);
757 if (nBufLength == 0)
return;
762#if ((OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L))
763 EVP_DigestUpdate(&
m_Bdy_ctx,szBuffer,nBufLength);
765 EVP_VerifyUpdate(&
m_Hdr_ctx,szBuffer,nBufLength);
767 EVP_DigestUpdate(
m_Bdy_ctx,szBuffer,nBufLength);
769 EVP_VerifyUpdate(
m_Hdr_ctx,szBuffer,nBufLength);
771#if (OPENSSL_VERSION_NUMBER > 0x10101000L)
772 SigHdr.append(szBuffer,nBufLength);
792 if (strlen(i->c_str()) < 14)
continue;
793 if (
_strnicmp(i->c_str(),
"DKIM-Signature",14) == 0) {
795 const char *s = i->c_str() + 14;
796 while (*s ==
' ' || *s ==
'\t')
813 bool ValidSigFound =
false;
842#if ((OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L))
843 EVP_VerifyInit(&sig.
m_Hdr_ctx,EVP_sha1());
844 EVP_DigestInit(&sig.
m_Bdy_ctx,EVP_sha1());
846 EVP_VerifyInit_ex(sig.
m_Hdr_ctx,EVP_sha1(),NULL);
847 EVP_DigestInit_ex(sig.
m_Bdy_ctx,EVP_sha1(),NULL);
851#if ((OPENSSL_VERSION_NUMBER < 0x10100000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L))
852 EVP_VerifyInit(&sig.
m_Hdr_ctx,EVP_sha256());
853 EVP_DigestInit(&sig.
m_Bdy_ctx,EVP_sha256());
855 EVP_VerifyInit_ex(sig.
m_Hdr_ctx,EVP_sha256(),NULL);
856 EVP_DigestInit_ex(sig.
m_Bdy_ctx,EVP_sha256(),NULL);
858#if (OPENSSL_VERSION_NUMBER > 0x10101000L)
865 vector<list<string>::reverse_iterator> used;
868 list<string>::reverse_iterator i;
870 if (
_strnicmp(i->c_str(),x->c_str(),x->length()) == 0) {
872 const char* s = i->c_str()+x->length();
873 while (*s ==
' ' || *s ==
'\t')
875 if (*s ==
':' && find(used.begin(),used.end(),i) == used.end())
885 sig.
Hash(i->c_str(),i->length());
888 sig.
Hash(sTemp.c_str(),sTemp.length());
894 for (
char* s = (
char*)sTemp.c_str(); *s !=
'\0' && *s !=
':'; s++) {
895 if (*s >=
'A' && *s <=
'Z')
898 sig.
Hash(sTemp.c_str(),sTemp.length());
911 list<string>::reverse_iterator i;
913 if (
_strnicmp(i->c_str(),
"From",4) == 0) {
915 const char *s = i->c_str() + 4;
916 while (*s ==
' ' || *s ==
'\t')
919 if (find(used.begin(),used.end(),i) == used.end()) {
933 ValidSigFound =
true;
949bool ParseUnsigned(
const char *s,
unsigned *result)
952 bool overflowed =
false;
955 if (*s <
'0' || *s >
'9')
964 }
while (*s !=
'\0');
966 *result = overflowed ? -1 :
temp;
984 string sValue = sHeader.substr(sHeader.find(
':') + 1);
986 static const char *tags[] = {
"v",
"a",
"b",
"d",
"h",
"s",
"c",
"i",
"l",
"q",
"t",
"x",
"bh",NULL};
987 char *values[
sizeof(tags)/
sizeof(tags[0])] = {NULL};
996 if (values[1] == NULL || values[2] == NULL || values[3] == NULL || values[4] == NULL || values[5] == NULL)
1000 if (strcmp(values[1],
"rsa-sha1") == 0) {
1002 }
else if (strcmp(values[1],
"rsa-sha256") == 0) {
1004#if (OPENSSL_VERSION_NUMBER > 0x10101000L)
1005 }
else if (strcmp(values[1],
"ed25519-sha256") == 0) {
1015 if (SigDataLen == 0)
1026 if (*values[3] ==
'\0')
1031 if (*values[4] ==
'\0')
1035 if (*values[5] ==
'\0')
1040 if (values[6] == NULL) {
1043 char* slash = strchr(values[6],
'/');
1047 if (strcmp(values[6],
"simple") == 0)
1049 else if (strcmp(values[6],
"relaxed") == 0)
1054 if (slash == NULL || strcmp(slash + 1,
"simple") == 0)
1056 else if (strcmp(slash + 1,
"relaxed") == 0)
1063 if (values[7] == NULL) {
1071 char* at = strchr(values[7],
'@');
1076 char* ilocalpart = values[7];
1077 char* idomain = at + 1;
1080 int idomainlen = strlen(idomain);
1081 int ddomainlen = strlen(values[3]);
1084 if (idomainlen < ddomainlen)
1086 if (
_stricmp(idomain + idomainlen - ddomainlen,values[3]) != 0)
1088 if (idomainlen > ddomainlen && idomain[idomainlen - ddomainlen - 1] !=
'.')
1099 if (!ParseUnsigned(values[8],&sig.
BodyLength))
1104 if (values[9] != NULL) {
1106 bool HasDNS =
false;
1107 char* s = strtok_r(values[9],
":",&saveptr);
1109 if (strncmp(s,
"dns",3) == 0 && (s[3] ==
'\0' || s[3] ==
'/')) {
1113 s = strtok_r(NULL,
": \t",&saveptr);
1121 unsigned SignedTime = -1;
1122 if (values[10] != NULL) {
1123 if (!ParseUnsigned(values[10],&SignedTime))
1128 if (values[11] == NULL) {
1131 if (!ParseUnsigned(values[11],&sig.
ExpireTime))
1136 if (SignedTime != (
unsigned) -1 && sig.
ExpireTime <= SignedTime)
1140 unsigned curtime = time(NULL);
1147 bool HasFrom =
false, HasSubject =
false;
1149 char* s = strtok_r(values[4],
":",&saveptr);
1153 else if (
_stricmp(s,
"Subject") == 0)
1157 s = strtok_r(NULL,
":",&saveptr);
1175 bool MoreBodyNeeded =
false;
1180 if (nBufLength > 0) {
1181 while (i->EmptyLineCount > 0) {
1182 i->Hash(
"\r\n",2,
true);
1183 i->EmptyLineCount--;
1185 i->Hash(szBuffer,nBufLength,
true);
1186 i->Hash(
"\r\n",2,
true);
1188 i->EmptyLineCount++;
1190 i->Hash(
"\r\n",2,
true);
1194 if (nBufLength > 0) {
1195 while (i->EmptyLineCount > 0) {
1196 i->Hash(
"\r\n",2,
true);
1197 i->EmptyLineCount--;
1199 i->Hash(szBuffer,nBufLength,
true);
1201 i->Hash(
"\r\n",2,
true);
1202 }
else i->EmptyLineCount++;
1205 i->Hash(szBuffer,nBufLength,
true);
1208 if (i->UnverifiedBodyCount == 0)
1209 MoreBodyNeeded =
true;
1213 if (!MoreBodyNeeded)
1246 char ed25519PubKey[61];
1248 static const char *tags[] = {
"v",
"g",
"h",
"k",
"p",
"s",
"t",
"n",NULL};
1249 char *values[
sizeof(tags)/
sizeof(tags[0])] = {NULL};
1254 if (values[0] != NULL) {
1256 if (strcmp(values[0],
"DKIM1") != 0)
1260 for (
unsigned j = 1;
j <
sizeof(values)/
sizeof(values[0]);
j++) {
1261 if (values[
j] != NULL && values[
j] < values[0]) {
1268 if (values[4] == NULL)
1271 PubKeyBase64 = values[4];
1274 if (values[1] == NULL)
1280 if (values[2] == NULL) {
1285 char* s = strtok_r(values[2],
":",&saveptr);
1287 if (strcmp(s,
"sha1") == 0)
1289 else if (strcmp(s,
"sha256") == 0)
1291 s = strtok_r(NULL,
":",&saveptr);
1298 if (values[3] != NULL) {
1300 if (strcmp(values[3],
"rsa") != 0 && strcmp(values[3],
"ed25519") != 0)
1302 if (strcmp(values[3],
"ed25519") == 0) {
1305 strcpy(ed25519PubKey,
"MCowBQYDK2VwAyEA");
1311 if (strlen(values[4]) > 44)
1313 strcat(ed25519PubKey,values[4]);
1314 PubKeyBase64 = ed25519PubKey;
1319 if (values[5] != NULL) {
1321 bool ServiceTypeMatch =
false;
1322 char* s = strtok_r(values[5],
":",&saveptr);
1324 if (strcmp(s,
"*") == 0 || strcmp(s,
"email") == 0) {
1325 ServiceTypeMatch =
true;
1328 s = strtok_r(NULL,
":",&saveptr);
1330 if (!ServiceTypeMatch)
1335 if (values[6] != NULL) {
1336 char *s = strtok_r(values[6],
":",&saveptr);
1338 if (strcmp(s,
"y") == 0) {
1340 }
else if (strcmp(s,
"s") == 0) {
1343 s = strtok_r(NULL,
":",&saveptr);
1350 if (PublicKeyLen == 0) {
1353 const unsigned char *PublicKeyData = (
unsigned char* )PubKeyBase64;
1355 EVP_PKEY *pkey = d2i_PUBKEY(NULL,&PublicKeyData,PublicKeyLen);
1361#if ((OPENSSL_VERSION_NUMBER < 0x10101000L) || (LIBRESSL_VERSION_NUMBER > 0 && LIBRESSL_VERSION_NUMBER < 0x20700000L))
1362 if (pkey->type == EVP_PKEY_RSA || pkey->type == EVP_PKEY_RSA2) {
1364 if ((EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA) ||
1365 (EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA2) ||
1366 (EVP_PKEY_base_id(pkey) == EVP_PKEY_ED25519)) {
1370 EVP_PKEY_free(pkey);
1386 for (list<SelectorInfo>::iterator i = Selectors.begin(); i != Selectors.end(); ++i) {
1387 if (
_stricmp(i->Selector.c_str(),sSelector.c_str()) == 0 &&
_stricmp(i->Domain.c_str(),sDomain.c_str()) == 0) {
1395 string sFQDN = sSelector;
1396 sFQDN +=
"._domainkey.";
1400 char Buffer[BufLen];
1404 if (m_pfnSelectorCallback) {
1405 DNSResult = m_pfnSelectorCallback(sFQDN.c_str(),Buffer,BufLen);
1407 DNSResult =
_DNSGetTXT(sFQDN.c_str(),Buffer,BufLen);
1411 switch (DNSResult) {
1429 for (list < SignatureInfo>::iterator i = Signatures.begin(); i != Signatures.end(); ++i) {
1431 d.szSignature = (
char* )i->Header.c_str();
1432 d.szSignatureDomain = (
char* )i->Domain.c_str();
1433 d.szIdentityDomain = (
char* )i->IdentityDomain.c_str();
1434 d.szCanonicalizedData = (
char* )i->CanonicalizedData.c_str();
1435 d.nResult = i->Status;
1436 Details.push_back(
d);
1439 *nSigCount = Details.size();
1440 *pDetails = (*nSigCount != 0) ? &Details[0] : NULL;
static string RelaxHeader(const string &sHeader)
static void CompressSWSP(char *pBuffer, int &nBufLength)
static void RemoveSWSP(char *szBuffer)
list< string > HeaderList
DKIMDNSCALLBACK m_pfnSelectorCallback
SelectorInfo & GetSelector(const string &sSelector, const string &sDomain)
bool m_AllowUnsignedFromHeaders
bool m_SaveCanonicalizedData
int GetDetails(int *nSigCount, DKIMVerifyDetails **pDetails)
int ParseDKIMSignature(const string &sHeader, SignatureInfo &sig)
virtual int ProcessBody(char *szBuffer, int nBufLength, bool bEOF)
virtual int ProcessHeaders(void)
bool m_HonorBodyLengthTag
list< SignatureInfo > Signatures
SelectorInfo(const string &sSelector, const string &sDomain)
vector< string > SignedHeaders
unsigned HeaderCanonicalization
bool m_SaveCanonicalizedData
unsigned UnverifiedBodyCount
unsigned BodyCanonicalization
SignatureInfo(bool SaveCanonicalizedData)
void Hash(const char *szBuffer, unsigned nBufLength, bool IsBody=false)
unsigned VerifiedBodyCount
SelectorInfo * m_pSelector
#define DKIM_SUCCESS_BUT_EXTRA
#define DKIM_BUFFER_TOO_SMALL
#define DKIM_PARTIAL_SUCCESS
#define DKIM_SELECTOR_PUBLIC_KEY_INVALID
#define DKIM_BODY_HASH_MISMATCH
#define DKIM_SELECTOR_KEY_REVOKED
#define DKIM_CANON_SIMPLE
#define DKIM_SIGNATURE_BAD_BUT_TESTING
#define DKIM_STAT_INCOMPAT
#define DKIM_NO_VALID_SIGNATURES
#define DKIM_SELECTOR_ALGORITHM_MISMATCH
#define DKIM_INVALID_CONTEXT
#define DKIM_SELECTOR_DNS_TEMP_FAILURE
#define DKIM_OUT_OF_MEMORY
#define DKIM_SELECTOR_GRANULARITY_MISMATCH
#define DKIM_SIGNATURE_BAD
#define DKIM_CANON_RELAXED
#define DKIM_SIGNATURE_EXPIRED
#define DKIM_BAD_PRIVATE_KEY
#define DKIM_UNSIGNED_FROM
#define DKIM_FINISHED_BODY
#define DKIM_NO_SIGNATURES
#define DKIM_SELECTOR_INVALID
#define DKIM_SELECTOR_DNS_PERM_FAILURE
#define DKIM_SELECTOR_DOMAIN_NAME_TOO_LONG
int stralloc_copys(stralloc *, char const *)
int _DNSGetTXT(const char *szFQDN, char *Buffer, int nBufLen)
int _DKIM_ReportResult(const char *ResFile, const char *result, const char *reason)
bool WildcardMatch(const char *p, const char *s)
unsigned DecodeBase64(char *ptr)
bool ParseAddresses(string str, vector< string > &Addresses)
bool ParseTagValueList(char *tagvaluelist, const char *wanted[], char *values[])
const char * DKIM_ErrorResult(const int res)
void DecodeQuotedPrintable(char *ptr)
int dig_ascii(char *digascii, unsigned const char *digest, const int len)
void p(char *, char *, int, int, int)
DKIMDNSCALLBACK pfnSelectorCallback
int nAllowUnsignedFromHeaders
int nSaveCanonicalizedData