summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Harris <jgh146exb@wizmail.org>2017-06-28 15:25:12 +0100
committerJeremy Harris <jgh146exb@wizmail.org>2017-08-09 22:23:58 +0100
commit135e949699b889c8c9088bb05f810d44adc74246 (patch)
tree1e82b43c0b5857e76cd4041ee3865fe4a191481d
parent0f1a8658daf8689f0ef0afbb11d0cb589447a57d (diff)
DKIM: Enforce any "h" field present in the DNS publickey record. This can be set to require specific
hash types, eg sha256, in signatues. There is an IETF draft in discussion which deprecates sha1 so this feature may start to be used.
-rw-r--r--doc/doc-txt/ChangeLog3
-rw-r--r--src/src/pdkim/pdkim.c33
-rw-r--r--src/src/pdkim/pdkim.h15
-rw-r--r--test/dnszones-src/db.test.ex6
-rw-r--r--test/log/45003
-rw-r--r--test/log/45063
-rw-r--r--test/scripts/4500-DKIM/450034
-rw-r--r--test/scripts/4500-DKIM/450635
-rw-r--r--test/stderr/45201
9 files changed, 120 insertions, 13 deletions
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index 0b4076c20..ecb6b33a9 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -138,6 +138,9 @@ JH/21 Bug 2151: Avoid using SIZE on the MAIL for a callout verify, on any but
JH/22 Retire historical build files to an "unsupported" subdir. These are
defined as "ones for which we have no current evidence of testing".
+JH/23 DKIM: enforce the DNS pubkey record "h" permitted-hashes optional field,
+ if present. Previously it was ignored.
+
Exim version 4.89
-----------------
diff --git a/src/src/pdkim/pdkim.c b/src/src/pdkim/pdkim.c
index d41b60f13..d289ec7a3 100644
--- a/src/src/pdkim/pdkim.c
+++ b/src/src/pdkim/pdkim.c
@@ -132,6 +132,7 @@ switch(ext_status)
{
case PDKIM_VERIFY_FAIL_BODY: return "PDKIM_VERIFY_FAIL_BODY";
case PDKIM_VERIFY_FAIL_MESSAGE: return "PDKIM_VERIFY_FAIL_MESSAGE";
+ case PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH: return "PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH";
case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE: return "PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE";
case PDKIM_VERIFY_INVALID_BUFFER_SIZE: return "PDKIM_VERIFY_INVALID_BUFFER_SIZE";
case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD: return "PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD";
@@ -644,12 +645,8 @@ for (p = raw_record; ; p++)
case 'v':
pub->version = string_copy(cur_val); break;
case 'h':
+ pub->hashes = string_copy(cur_val); break;
case 'k':
-/* This field appears to never be used. Also, unclear why
-a 'k' (key-type_ would go in this field name. There is a field
-"keytype", also never used.
- pub->hashes = string_copy(cur_val);
-*/
break;
case 'g':
pub->granularity = string_copy(cur_val); break;
@@ -682,7 +679,11 @@ a 'k' (key-type_ would go in this field name. There is a field
/* Set fallback defaults */
if (!pub->version ) pub->version = string_copy(PDKIM_PUB_RECORD_VERSION);
-else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0) return NULL;
+else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0)
+ {
+ DEBUG(D_acl) debug_printf(" Bad v= field\n");
+ return NULL;
+ }
if (!pub->granularity) pub->granularity = string_copy(US"*");
/*
@@ -694,6 +695,7 @@ if (!pub->srvtype ) pub->srvtype = string_copy(US"*");
if (pub->key.data)
return pub;
+DEBUG(D_acl) debug_printf(" Missing p= field\n");
return NULL;
}
@@ -1631,6 +1633,25 @@ while (sig)
if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx, err)))
goto NEXT_VERIFY;
+ /* If the pubkey limits to a list of specific hashes, ignore sigs that
+ do not have the hash part of the sig algorithm matching */
+
+ if (sig->pubkey->hashes)
+ {
+ const uschar * list = sig->pubkey->hashes, * ele;
+ int sep = ':';
+ while ((ele = string_nextinlist(&list, &sep, NULL, 0)))
+ if (Ustrcmp(ele, pdkim_algos[sig->algo] + 4) == 0) break;
+ if (!ele)
+ {
+ DEBUG(D_acl) debug_printf("pubkey h=%s vs sig a=%s\n",
+ sig->pubkey->hashes, pdkim_algos[sig->algo]);
+ sig->verify_status = PDKIM_VERIFY_FAIL;
+ sig->verify_ext_status = PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH;
+ goto NEXT_VERIFY;
+ }
+ }
+
/* Check the signature */
if ((*err = exim_rsa_verify(&vctx, is_sha1, &hhash, &sig->sighash)))
{
diff --git a/src/src/pdkim/pdkim.h b/src/src/pdkim/pdkim.h
index 78e3c3c8b..9899356d5 100644
--- a/src/src/pdkim/pdkim.h
+++ b/src/src/pdkim/pdkim.h
@@ -51,12 +51,13 @@
#define PDKIM_VERIFY_FAIL_BODY 1
#define PDKIM_VERIFY_FAIL_MESSAGE 2
-#define PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE 3
-#define PDKIM_VERIFY_INVALID_BUFFER_SIZE 4
-#define PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD 5
-#define PDKIM_VERIFY_INVALID_PUBKEY_IMPORT 6
-#define PDKIM_VERIFY_INVALID_SIGNATURE_ERROR 7
-#define PDKIM_VERIFY_INVALID_DKIM_VERSION 8
+#define PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH 3
+#define PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE 4
+#define PDKIM_VERIFY_INVALID_BUFFER_SIZE 5
+#define PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD 6
+#define PDKIM_VERIFY_INVALID_PUBKEY_IMPORT 7
+#define PDKIM_VERIFY_INVALID_SIGNATURE_ERROR 8
+#define PDKIM_VERIFY_INVALID_DKIM_VERSION 9
/* -------------------------------------------------------------------------- */
/* Some parameter values */
@@ -100,8 +101,8 @@ typedef struct pdkim_pubkey {
uschar *version; /* v= */
uschar *granularity; /* g= */
-#ifdef notdef
uschar *hashes; /* h= */
+#ifdef notdef
uschar *keytype; /* k= */
#endif
uschar *srvtype; /* s= */
diff --git a/test/dnszones-src/db.test.ex b/test/dnszones-src/db.test.ex
index f7c9e313b..73db57f9c 100644
--- a/test/dnszones-src/db.test.ex
+++ b/test/dnszones-src/db.test.ex
@@ -491,13 +491,19 @@ DELAY=1500 delay1500 A HOSTIPV4
; openssl rsa -in aux-fixed/dkim/dkim.private -out /dev/stdout -pubout -outform PEM
;
; Deliberate bad version, having extra backslashes
+; sha256-hash-only version.... appears to be too long, gets truncated
;
; Another, 512-bit (with a Notes field)
+; 512 requiring sha1 hash
+; 512 requiring sha256 hash
;
sel._domainkey TXT "v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXRFf+VhT+lCgFhhSkinZKcFNeRzjYdW8vT29Rbb3NadvTFwAd+cVLPFwZL8H5tUD/7JbUPqNTCPxmpgIL+V5T4tEZMorHatvvUM2qfcpQ45IfsZ+YdhbIiAslHCpy4xNxIR3zylgqRUF4+Dtsaqy3a5LhwMiKCLrnzhXk1F1hxwIDAQAB"
sel_bad._domainkey TXT "v=DKIM1\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXRFf+VhT+lCgFhhSkinZKcFNeRzjYdW8vT29Rbb3NadvTFwAd+cVLPFwZL8H5tUD/7JbUPqNTCPxmpgIL+V5T4tEZMorHatvvUM2qfcpQ45IfsZ+YdhbIiAslHCpy4xNxIR3zylgqRUF4+Dtsaqy3a5LhwMiKCLrnzhXk1F1hxwIDAQAB"
+sel_sha256._domainkey TXT "v=DKIM1; h=sha256; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXRFf+VhT+lCgFhhSkinZKcFNeRzjYdW8vT29Rbb3NadvTFwAd+cVLPFwZL8H5tUD/7JbUPqNTCPxmpgIL+V5T4tEZMorHatvvUM2qfcpQ45IfsZ+YdhbIiAslHCpy4xNxIR3zylgqRUF4+Dtsaqy3a5LhwMiKCLrnzhXk1F1hxwIDAQAB"
ses._domainkey TXT "v=DKIM1; n=halfkilo; p=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL6eAQxd9didJ0/+05iDwJOqT6ly826Vi8aGPecsBiYK5/tAT97fxXk+dPWMZp9kQxtknEzYjYjAydzf+HQ2yJMCAwEAAQ=="
+ses_sha1._domainkey TXT "v=DKIM1; h=sha1; p=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL6eAQxd9didJ0/+05iDwJOqT6ly826Vi8aGPecsBiYK5/tAT97fxXk+dPWMZp9kQxtknEzYjYjAydzf+HQ2yJMCAwEAAQ=="
+ses_sha256._domainkey TXT "v=DKIM1; h=sha256; p=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL6eAQxd9didJ0/+05iDwJOqT6ly826Vi8aGPecsBiYK5/tAT97fxXk+dPWMZp9kQxtknEzYjYjAydzf+HQ2yJMCAwEAAQ=="
; End
diff --git a/test/log/4500 b/test/log/4500
index 0e0f8400d..ec8ef088e 100644
--- a/test/log/4500
+++ b/test/log/4500
@@ -10,3 +10,6 @@
1999-03-02 09:44:33 10HmaZ-0005vi-00 DKIM: d=test.ex s=sel c=simple/simple a=rsa-sha256 b=1024 [verification succeeded]
1999-03-02 09:44:33 10HmaZ-0005vi-00 signer: test.ex bits: 1024
1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@disco-zombie.net
+1999-03-02 09:44:33 10HmbA-0005vi-00 DKIM: d=test.ex s=ses_sha1 c=simple/simple a=rsa-sha1 b=512 [verification succeeded]
+1999-03-02 09:44:33 10HmbA-0005vi-00 signer: test.ex bits: 512
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@disco-zombie.net
diff --git a/test/log/4506 b/test/log/4506
index fb0f22567..027169df0 100644
--- a/test/log/4506
+++ b/test/log/4506
@@ -13,3 +13,6 @@
1999-03-02 09:44:33 10HmbA-0005vi-00 DKIM: validation error: RSA_LONG_LINE
1999-03-02 09:44:33 10HmbA-0005vi-00 DKIM: Error during validation, disabling signature verification: RSA_LONG_LINE
1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@disco-zombie.net
+1999-03-02 09:44:33 10HmbB-0005vi-00 DKIM: d=test.ex s=ses_sha256 c=simple/simple a=rsa-sha1 b=512 [verification failed - unspecified reason]
+1999-03-02 09:44:33 10HmbB-0005vi-00 signer: test.ex bits: 512
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@disco-zombie.net
diff --git a/test/scripts/4500-DKIM/4500 b/test/scripts/4500-DKIM/4500
index 6728b141d..6b3ff5fcf 100644
--- a/test/scripts/4500-DKIM/4500
+++ b/test/scripts/4500-DKIM/4500
@@ -101,6 +101,40 @@ QUIT
****
#
#
+# This should pass. The pubkey dns decord has a additional sha1-only h= field
+#
+# - sha1, 512b
+# Mail original in aux-fixed/4500.msg1.txt
+# Sig generated by: perl aux-fixed/dkim/sign.pl --keyfile=aux-fixed/dkim/dkim512.private \
+# --method=simple/simple --selector=ses_sha1 < aux-fixed/4500.msg1.txt
+client 127.0.0.1 PORT_D
+??? 220
+HELO xxx
+??? 250
+MAIL FROM:<CALLER@bloggs.com>
+??? 250
+RCPT TO:<a@test.ex>
+??? 250
+DATA
+??? 354
+DKIM-Signature: v=1; a=rsa-sha1; c=simple/simple; d=test.ex; h=from:to
+ :date:message-id:subject; s=ses_sha1; bh=OB9dZVu7+5/ufs3TH9leIcE
+ pXSo=; b=hG14R3Eb/f13Pw6J0LmovHAL01KHVmVrTZ7KJrqieYTQemUaseoU2pB
+ 7/g8NUwG/AsYoaw3gaAK8PqxSk2lcIQ==
+From: mrgus@text.ex
+To: bakawolf@yahoo.com
+Date: Thu, 19 Nov 2015 17:00:07 -0700
+Message-ID: <qwerty1234@disco-zombie.net>
+Subject: simple test
+
+This is a simple test.
+.
+??? 250
+QUIT
+??? 221
+****
+#
+#
killdaemon
no_stdout_check
no_msglog_check
diff --git a/test/scripts/4500-DKIM/4506 b/test/scripts/4500-DKIM/4506
index 6eb81cc16..e8d7c41f0 100644
--- a/test/scripts/4500-DKIM/4506
+++ b/test/scripts/4500-DKIM/4506
@@ -134,6 +134,41 @@ QUIT
****
#
#
+# This should fail as the sig on the mail uses sha1 but the dns record requires sha256
+#
+# - sha256, 512b
+# Mail original in aux-fixed/4500.msg1.txt
+# Sig generated by: perl aux-fixed/dkim/sign.pl --keyfile=aux-fixed/dkim/dkim512.private \
+# --method=simple/simple --selector=ses_sha1 < aux-fixed/4500.msg1.txt
+# and then modifying the s= manually
+client 127.0.0.1 PORT_D
+??? 220
+HELO xxx
+??? 250
+MAIL FROM:<CALLER@bloggs.com>
+??? 250
+RCPT TO:<a@test.ex>
+??? 250
+DATA
+??? 354
+DKIM-Signature: v=1; a=rsa-sha1; c=simple/simple; d=test.ex; h=from:to
+ :date:message-id:subject; s=ses_sha256; bh=OB9dZVu7+5/ufs3TH9leIcE
+ pXSo=; b=hG14R3Eb/f13Pw6J0LmovHAL01KHVmVrTZ7KJrqieYTQemUaseoU2pB
+ 7/g8NUwG/AsYoaw3gaAK8PqxSk2lcIQ==
+From: mrgus@text.ex
+To: bakawolf@yahoo.com
+Date: Thu, 19 Nov 2015 17:00:07 -0700
+Message-ID: <qwerty1234@disco-zombie.net>
+Subject: simple test
+
+This is a simple test.
+.
+??? 250
+QUIT
+??? 221
+****
+#
+#
killdaemon
no_stdout_check
no_msglog_check
diff --git a/test/stderr/4520 b/test/stderr/4520
index c1bafcdcc..fc64a9e93 100644
--- a/test/stderr/4520
+++ b/test/stderr/4520
@@ -28,6 +28,7 @@ PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Raw record: v=DKIM1\;{SP}p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXRFf+VhT+lCgFhhSkinZKcFNeRzjYdW8vT29Rbb3NadvTFwAd+cVLPFwZL8H5tUD/7JbUPqNTCPxmpgIL+V5T4tEZMorHatvvUM2qfcpQ45IfsZ+YdhbIiAslHCpy4xNxIR3zylgqRUF4+Dtsaqy3a5LhwMiKCLrnzhXk1F1hxwIDAQAB
v=DKIM1\
p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXRFf+VhT+lCgFhhSkinZKcFNeRzjYdW8vT29Rbb3NadvTFwAd+cVLPFwZL8H5tUD/7JbUPqNTCPxmpgIL+V5T4tEZMorHatvvUM2qfcpQ45IfsZ+YdhbIiAslHCpy4xNxIR3zylgqRUF4+Dtsaqy3a5LhwMiKCLrnzhXk1F1hxwIDAQAB
+ Bad v= field
Error while parsing public key record
WARNING: bad dkim key in dns
PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<