2 * PDKIM - a RFC4871 (DKIM) implementation
4 * Copyright (C) 2009 - 2016 Tom Kistner <tom@duncanthrax.net>
5 * Copyright (C) 2016 Jeremy Harris <jgh@exim.org>
7 * http://duncanthrax.net/pdkim/
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #ifndef DISABLE_DKIM /* entire file */
30 # error Need SUPPORT_TLS for DKIM
33 #include "crypt_ver.h"
36 # include <openssl/rsa.h>
37 # include <openssl/ssl.h>
38 # include <openssl/err.h>
39 #elif defined(RSA_GNUTLS)
40 # include <gnutls/gnutls.h>
41 # include <gnutls/x509.h>
47 #define PDKIM_SIGNATURE_VERSION "1"
48 #define PDKIM_PUB_RECORD_VERSION US "DKIM1"
50 #define PDKIM_MAX_HEADER_LEN 65536
51 #define PDKIM_MAX_HEADERS 512
52 #define PDKIM_MAX_BODY_LINE_LEN 16384
53 #define PDKIM_DNS_TXT_MAX_NAMELEN 1024
54 #define PDKIM_DEFAULT_SIGN_HEADERS "From:Sender:Reply-To:Subject:Date:"\
55 "Message-ID:To:Cc:MIME-Version:Content-Type:"\
56 "Content-Transfer-Encoding:Content-ID:"\
57 "Content-Description:Resent-Date:Resent-From:"\
58 "Resent-Sender:Resent-To:Resent-Cc:"\
59 "Resent-Message-ID:In-Reply-To:References:"\
60 "List-Id:List-Help:List-Unsubscribe:"\
61 "List-Subscribe:List-Post:List-Owner:List-Archive"
63 /* -------------------------------------------------------------------------- */
64 struct pdkim_stringlist
{
70 /* -------------------------------------------------------------------------- */
71 /* A bunch of list constants */
72 const uschar
* pdkim_querymethods
[] = {
76 const uschar
* pdkim_algos
[] = {
81 const uschar
* pdkim_canons
[] = {
86 const uschar
* pdkim_hashes
[] = {
91 const uschar
* pdkim_keytypes
[] = {
96 typedef struct pdkim_combined_canon_entry
{
100 } pdkim_combined_canon_entry
;
102 pdkim_combined_canon_entry pdkim_combined_canons
[] = {
103 { US
"simple/simple", PDKIM_CANON_SIMPLE
, PDKIM_CANON_SIMPLE
},
104 { US
"simple/relaxed", PDKIM_CANON_SIMPLE
, PDKIM_CANON_RELAXED
},
105 { US
"relaxed/simple", PDKIM_CANON_RELAXED
, PDKIM_CANON_SIMPLE
},
106 { US
"relaxed/relaxed", PDKIM_CANON_RELAXED
, PDKIM_CANON_RELAXED
},
107 { US
"simple", PDKIM_CANON_SIMPLE
, PDKIM_CANON_SIMPLE
},
108 { US
"relaxed", PDKIM_CANON_RELAXED
, PDKIM_CANON_SIMPLE
},
113 /* -------------------------------------------------------------------------- */
116 pdkim_verify_status_str(int status
)
120 case PDKIM_VERIFY_NONE
: return "PDKIM_VERIFY_NONE";
121 case PDKIM_VERIFY_INVALID
: return "PDKIM_VERIFY_INVALID";
122 case PDKIM_VERIFY_FAIL
: return "PDKIM_VERIFY_FAIL";
123 case PDKIM_VERIFY_PASS
: return "PDKIM_VERIFY_PASS";
124 default: return "PDKIM_VERIFY_UNKNOWN";
129 pdkim_verify_ext_status_str(int ext_status
)
133 case PDKIM_VERIFY_FAIL_BODY
: return "PDKIM_VERIFY_FAIL_BODY";
134 case PDKIM_VERIFY_FAIL_MESSAGE
: return "PDKIM_VERIFY_FAIL_MESSAGE";
135 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE
: return "PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE";
136 case PDKIM_VERIFY_INVALID_BUFFER_SIZE
: return "PDKIM_VERIFY_INVALID_BUFFER_SIZE";
137 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD
: return "PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD";
138 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT
: return "PDKIM_VERIFY_INVALID_PUBKEY_IMPORT";
139 case PDKIM_VERIFY_INVALID_SIGNATURE_ERROR
: return "PDKIM_VERIFY_INVALID_SIGNATURE_ERROR";
140 case PDKIM_VERIFY_INVALID_DKIM_VERSION
: return "PDKIM_VERIFY_INVALID_DKIM_VERSION";
141 default: return "PDKIM_VERIFY_UNKNOWN";
146 pdkim_errstr(int status
)
150 case PDKIM_OK
: return "OK";
151 case PDKIM_FAIL
: return "FAIL";
152 case PDKIM_ERR_RSA_PRIVKEY
: return "RSA_PRIVKEY";
153 case PDKIM_ERR_RSA_SIGNING
: return "RSA SIGNING";
154 case PDKIM_ERR_LONG_LINE
: return "RSA_LONG_LINE";
155 case PDKIM_ERR_BUFFER_TOO_SMALL
: return "BUFFER_TOO_SMALL";
156 case PDKIM_SIGN_PRIVKEY_WRAP
: return "PRIVKEY_WRAP";
157 case PDKIM_SIGN_PRIVKEY_B64D
: return "PRIVKEY_B64D";
158 default: return "(unknown)";
163 /* -------------------------------------------------------------------------- */
164 /* Print debugging functions */
166 pdkim_quoteprint(const uschar
*data
, int len
)
169 for (i
= 0; i
< len
; i
++)
171 const int c
= data
[i
];
174 case ' ' : debug_printf("{SP}"); break;
175 case '\t': debug_printf("{TB}"); break;
176 case '\r': debug_printf("{CR}"); break;
177 case '\n': debug_printf("{LF}"); break;
178 case '{' : debug_printf("{BO}"); break;
179 case '}' : debug_printf("{BC}"); break;
181 if ( (c
< 32) || (c
> 127) )
182 debug_printf("{%02x}", c
);
184 debug_printf("%c", c
);
192 pdkim_hexprint(const uschar
*data
, int len
)
195 for (i
= 0 ; i
< len
; i
++) debug_printf("%02x", data
[i
]);
201 static pdkim_stringlist
*
202 pdkim_prepend_stringlist(pdkim_stringlist
* base
, const uschar
* str
)
204 pdkim_stringlist
* new_entry
= store_get(sizeof(pdkim_stringlist
));
206 memset(new_entry
, 0, sizeof(pdkim_stringlist
));
207 new_entry
->value
= string_copy(str
);
208 if (base
) new_entry
->next
= base
;
214 /* Trim whitespace fore & aft */
217 pdkim_strtrim(uschar
* str
)
221 while (*p
== '\t' || *p
== ' ') p
++; /* skip whitespace */
222 while (*p
) {*q
= *p
; q
++; p
++;} /* dump the leading whitespace */
224 while (q
!= str
&& ( (*q
== '\0') || (*q
== '\t') || (*q
== ' ') ) )
225 { /* dump trailing whitespace */
233 /* -------------------------------------------------------------------------- */
236 pdkim_free_ctx(pdkim_ctx
*ctx
)
241 /* -------------------------------------------------------------------------- */
242 /* Matches the name of the passed raw "header" against
243 the passed colon-separated "tick", and invalidates
244 the entry in tick. Returns OK or fail-code */
245 /*XXX might be safer done using a pdkim_stringlist for "tick" */
248 header_name_match(const uschar
* header
, uschar
* tick
)
254 uschar
* hcolon
= Ustrchr(header
, ':'); /* Get header name */
257 return PDKIM_FAIL
; /* This isn't a header */
259 /* if we had strncmpic() we wouldn't need this copy */
260 hname
= string_copyn(header
, hcolon
-header
);
262 /* Copy tick-off list locally, so we can punch zeroes into it */
263 p
= lcopy
= string_copy(tick
);
265 for (q
= Ustrchr(p
, ':'); q
; q
= Ustrchr(p
, ':'))
268 if (strcmpic(p
, hname
) == 0)
274 if (strcmpic(p
, hname
) == 0)
280 /* Invalidate header name instance in tick-off list */
286 /* -------------------------------------------------------------------------- */
287 /* Performs "relaxed" canonicalization of a header. */
290 pdkim_relax_header(const uschar
* header
, int crlf
)
292 BOOL past_field_name
= FALSE
;
293 BOOL seen_wsp
= FALSE
;
295 uschar
* relaxed
= store_get(Ustrlen(header
)+3);
296 uschar
* q
= relaxed
;
298 for (p
= header
; *p
; p
++)
302 if (c
== '\r' || c
== '\n')
304 if (c
== '\t' || c
== ' ')
308 c
= ' '; /* Turns WSP into SP */
312 if (!past_field_name
&& c
== ':')
314 if (seen_wsp
) q
--; /* This removes WSP before the colon */
315 seen_wsp
= TRUE
; /* This removes WSP after the colon */
316 past_field_name
= TRUE
;
321 /* Lowercase header name */
322 if (!past_field_name
) c
= tolower(c
);
326 if (q
> relaxed
&& q
[-1] == ' ') q
--; /* Squash eventual trailing SP */
328 if (crlf
) { *q
++ = '\r'; *q
++ = '\n'; }
334 /* -------------------------------------------------------------------------- */
335 #define PDKIM_QP_ERROR_DECODE -1
338 pdkim_decode_qp_char(uschar
*qp_p
, int *c
)
340 uschar
*initial_pos
= qp_p
;
342 /* Advance one char */
345 /* Check for two hex digits and decode them */
346 if (isxdigit(*qp_p
) && isxdigit(qp_p
[1]))
348 /* Do hex conversion */
349 *c
= (isdigit(*qp_p
) ? *qp_p
- '0' : toupper(*qp_p
) - 'A' + 10) << 4;
350 *c
|= isdigit(qp_p
[1]) ? qp_p
[1] - '0' : toupper(qp_p
[1]) - 'A' + 10;
354 /* Illegal char here */
355 *c
= PDKIM_QP_ERROR_DECODE
;
360 /* -------------------------------------------------------------------------- */
363 pdkim_decode_qp(uschar
* str
)
368 uschar
* n
= store_get(Ustrlen(str
)+1);
376 p
= pdkim_decode_qp_char(p
, &nchar
);
392 /* -------------------------------------------------------------------------- */
395 pdkim_decode_base64(uschar
*str
, blob
* b
)
398 dlen
= b64decode(str
, &b
->data
);
399 if (dlen
< 0) b
->data
= NULL
;
404 pdkim_encode_base64(blob
* b
)
406 return b64encode(b
->data
, b
->len
);
410 /* -------------------------------------------------------------------------- */
411 #define PDKIM_HDR_LIMBO 0
412 #define PDKIM_HDR_TAG 1
413 #define PDKIM_HDR_VALUE 2
415 static pdkim_signature
*
416 pdkim_parse_sig_header(pdkim_ctx
*ctx
, uschar
* raw_hdr
)
418 pdkim_signature
*sig
;
420 uschar
* cur_tag
= NULL
; int ts
= 0, tl
= 0;
421 uschar
* cur_val
= NULL
; int vs
= 0, vl
= 0;
422 BOOL past_hname
= FALSE
;
423 BOOL in_b_val
= FALSE
;
424 int where
= PDKIM_HDR_LIMBO
;
427 sig
= store_get(sizeof(pdkim_signature
));
428 memset(sig
, 0, sizeof(pdkim_signature
));
429 sig
->bodylength
= -1;
431 /* Set so invalid/missing data error display is accurate */
435 q
= sig
->rawsig_no_b_val
= store_get(Ustrlen(raw_hdr
)+1);
437 for (p
= raw_hdr
; ; p
++)
442 if (c
== '\r' || c
== '\n')
445 /* Fast-forward through header name */
448 if (c
== ':') past_hname
= TRUE
;
452 if (where
== PDKIM_HDR_LIMBO
)
454 /* In limbo, just wait for a tag-char to appear */
455 if (!(c
>= 'a' && c
<= 'z'))
458 where
= PDKIM_HDR_TAG
;
461 if (where
== PDKIM_HDR_TAG
)
463 if (c
>= 'a' && c
<= 'z')
464 cur_tag
= string_catn(cur_tag
, &ts
, &tl
, p
, 1);
469 if (Ustrcmp(cur_tag
, "b") == 0)
474 where
= PDKIM_HDR_VALUE
;
479 if (where
== PDKIM_HDR_VALUE
)
481 if (c
== '\r' || c
== '\n' || c
== ' ' || c
== '\t')
484 if (c
== ';' || c
== '\0')
489 pdkim_strtrim(cur_val
);
491 DEBUG(D_acl
) debug_printf(" %s=%s\n", cur_tag
, cur_val
);
496 if (cur_tag
[1] == 'h')
497 pdkim_decode_base64(cur_val
, &sig
->bodyhash
);
499 pdkim_decode_base64(cur_val
, &sig
->sigdata
);
502 /* We only support version 1, and that is currently the
503 only version there is. */
505 Ustrcmp(cur_val
, PDKIM_SIGNATURE_VERSION
) == 0 ? 1 : -1;
508 for (i
= 0; pdkim_algos
[i
]; i
++)
509 if (Ustrcmp(cur_val
, pdkim_algos
[i
]) == 0)
516 for (i
= 0; pdkim_combined_canons
[i
].str
; i
++)
517 if (Ustrcmp(cur_val
, pdkim_combined_canons
[i
].str
) == 0)
519 sig
->canon_headers
= pdkim_combined_canons
[i
].canon_headers
;
520 sig
->canon_body
= pdkim_combined_canons
[i
].canon_body
;
525 for (i
= 0; pdkim_querymethods
[i
]; i
++)
526 if (Ustrcmp(cur_val
, pdkim_querymethods
[i
]) == 0)
528 sig
->querymethod
= i
;
533 sig
->selector
= string_copy(cur_val
); break;
535 sig
->domain
= string_copy(cur_val
); break;
537 sig
->identity
= pdkim_decode_qp(cur_val
); break;
539 sig
->created
= strtoul(CS cur_val
, NULL
, 10); break;
541 sig
->expires
= strtoul(CS cur_val
, NULL
, 10); break;
543 sig
->bodylength
= strtol(CS cur_val
, NULL
, 10); break;
545 sig
->headernames
= string_copy(cur_val
); break;
547 sig
->copiedheaders
= pdkim_decode_qp(cur_val
); break;
549 DEBUG(D_acl
) debug_printf(" Unknown tag encountered\n");
556 where
= PDKIM_HDR_LIMBO
;
559 cur_val
= string_catn(cur_val
, &vs
, &vl
, p
, 1);
571 /* Chomp raw header. The final newline must not be added to the signature. */
572 while (--q
> sig
->rawsig_no_b_val
&& (*q
== '\r' || *q
== '\n'))
578 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
579 pdkim_quoteprint(US sig
->rawsig_no_b_val
, Ustrlen(sig
->rawsig_no_b_val
));
581 "PDKIM >> Sig size: %4u bits\n", (unsigned) sig
->sigdata
.len
*8);
583 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
586 exim_sha_init(&sig
->body_hash
, sig
->algo
== PDKIM_ALGO_RSA_SHA1
? HASH_SHA1
: HASH_SHA256
);
591 /* -------------------------------------------------------------------------- */
593 static pdkim_pubkey
*
594 pdkim_parse_pubkey_record(pdkim_ctx
*ctx
, const uschar
*raw_record
)
598 uschar
* cur_tag
= NULL
; int ts
= 0, tl
= 0;
599 uschar
* cur_val
= NULL
; int vs
= 0, vl
= 0;
600 int where
= PDKIM_HDR_LIMBO
;
602 pub
= store_get(sizeof(pdkim_pubkey
));
603 memset(pub
, 0, sizeof(pdkim_pubkey
));
605 for (p
= raw_record
; ; p
++)
610 if (c
!= '\r' && c
!= '\n') switch (where
)
612 case PDKIM_HDR_LIMBO
: /* In limbo, just wait for a tag-char to appear */
613 if (!(c
>= 'a' && c
<= 'z'))
615 where
= PDKIM_HDR_TAG
;
619 if (c
>= 'a' && c
<= 'z')
620 cur_tag
= string_catn(cur_tag
, &ts
, &tl
, p
, 1);
625 where
= PDKIM_HDR_VALUE
;
629 case PDKIM_HDR_VALUE
:
630 if (c
== ';' || c
== '\0')
635 pdkim_strtrim(cur_val
);
636 DEBUG(D_acl
) debug_printf(" %s=%s\n", cur_tag
, cur_val
);
641 pub
->version
= string_copy(cur_val
); break;
644 /* This field appears to never be used. Also, unclear why
645 a 'k' (key-type_ would go in this field name. There is a field
646 "keytype", also never used.
647 pub->hashes = string_copy(cur_val);
651 pub
->granularity
= string_copy(cur_val
); break;
653 pub
->notes
= pdkim_decode_qp(cur_val
); break;
655 pdkim_decode_base64(US cur_val
, &pub
->key
); break;
657 pub
->srvtype
= string_copy(cur_val
); break;
659 if (Ustrchr(cur_val
, 'y') != NULL
) pub
->testing
= 1;
660 if (Ustrchr(cur_val
, 's') != NULL
) pub
->no_subdomaining
= 1;
663 DEBUG(D_acl
) debug_printf(" Unknown tag encountered\n");
669 where
= PDKIM_HDR_LIMBO
;
672 cur_val
= string_catn(cur_val
, &vs
, &vl
, p
, 1);
676 if (c
== '\0') break;
679 /* Set fallback defaults */
680 if (!pub
->version
) pub
->version
= string_copy(PDKIM_PUB_RECORD_VERSION
);
681 else if (Ustrcmp(pub
->version
, PDKIM_PUB_RECORD_VERSION
) != 0) return NULL
;
683 if (!pub
->granularity
) pub
->granularity
= string_copy(US
"*");
685 if (!pub->keytype ) pub->keytype = string_copy(US"rsa");
687 if (!pub
->srvtype
) pub
->srvtype
= string_copy(US
"*");
697 /* -------------------------------------------------------------------------- */
700 pdkim_update_bodyhash(pdkim_ctx
*ctx
, const char *data
, int len
)
702 pdkim_signature
*sig
= ctx
->sig
;
703 /* Cache relaxed version of data */
704 uschar
*relaxed_data
= NULL
;
707 /* Traverse all signatures, updating their hashes. */
710 /* Defaults to simple canon (no further treatment necessary) */
711 const uschar
*canon_data
= CUS data
;
714 if (sig
->canon_body
== PDKIM_CANON_RELAXED
)
716 /* Relax the line if not done already */
719 BOOL seen_wsp
= FALSE
;
723 /* We want to be able to free this else we allocate
724 for the entire message which could be many MB. Since
725 we don't know what allocations the SHA routines might
726 do, not safe to use store_get()/store_reset(). */
728 relaxed_data
= store_malloc(len
+1);
730 for (p
= data
; *p
; p
++)
735 if (q
> 0 && relaxed_data
[q
-1] == ' ')
738 else if (c
== '\t' || c
== ' ')
740 c
= ' '; /* Turns WSP into SP */
747 relaxed_data
[q
++] = c
;
749 relaxed_data
[q
] = '\0';
752 canon_data
= relaxed_data
;
753 canon_len
= relaxed_len
;
756 /* Make sure we don't exceed the to-be-signed body length */
757 if ( sig
->bodylength
>= 0
758 && sig
->signed_body_bytes
+ (unsigned long)canon_len
> sig
->bodylength
760 canon_len
= sig
->bodylength
- sig
->signed_body_bytes
;
764 exim_sha_update(&sig
->body_hash
, CUS canon_data
, canon_len
);
765 sig
->signed_body_bytes
+= canon_len
;
766 DEBUG(D_acl
) pdkim_quoteprint(canon_data
, canon_len
);
772 if (relaxed_data
) store_free(relaxed_data
);
777 /* -------------------------------------------------------------------------- */
780 pdkim_finish_bodyhash(pdkim_ctx
*ctx
)
782 pdkim_signature
*sig
;
784 /* Traverse all signatures */
785 for (sig
= ctx
->sig
; sig
; sig
= sig
->next
)
786 { /* Finish hashes */
789 exim_sha_finish(&sig
->body_hash
, &bh
);
793 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
794 "PDKIM [%s] Body hash computed: ",
795 sig
->domain
, sig
->signed_body_bytes
, sig
->domain
);
796 pdkim_hexprint(CUS bh
.data
, bh
.len
);
799 /* SIGNING -------------------------------------------------------------- */
800 if (ctx
->flags
& PDKIM_MODE_SIGN
)
804 /* If bodylength limit is set, and we have received less bytes
805 than the requested amount, effectively remove the limit tag. */
806 if (sig
->signed_body_bytes
< sig
->bodylength
)
807 sig
->bodylength
= -1;
810 /* VERIFICATION --------------------------------------------------------- */
813 /* Compare bodyhash */
814 if (memcmp(bh
.data
, sig
->bodyhash
.data
, bh
.len
) == 0)
816 DEBUG(D_acl
) debug_printf("PDKIM [%s] Body hash verified OK\n", sig
->domain
);
822 debug_printf("PDKIM [%s] Body hash signature from headers: ", sig
->domain
);
823 pdkim_hexprint(sig
->bodyhash
.data
,
824 exim_sha_hashlen(&sig
->body_hash
));
825 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig
->domain
);
827 sig
->verify_status
= PDKIM_VERIFY_FAIL
;
828 sig
->verify_ext_status
= PDKIM_VERIFY_FAIL_BODY
;
837 pdkim_body_complete(pdkim_ctx
* ctx
)
839 pdkim_signature
* sig
= ctx
->sig
; /*XXX assumes only one sig */
841 /* In simple body mode, if any empty lines were buffered,
842 replace with one. rfc 4871 3.4.3 */
843 /*XXX checking the signed-body-bytes is a gross hack; I think
844 it indicates that all linebreaks should be buffered, including
845 the one terminating a text line */
847 if ( sig
&& sig
->canon_body
== PDKIM_CANON_SIMPLE
848 && sig
->signed_body_bytes
== 0
849 && ctx
->num_buffered_crlf
> 0
851 pdkim_update_bodyhash(ctx
, "\r\n", 2);
853 ctx
->flags
|= PDKIM_SEEN_EOD
;
854 ctx
->linebuf_offset
= 0;
860 /* -------------------------------------------------------------------------- */
861 /* Call from pdkim_feed below for processing complete body lines */
864 pdkim_bodyline_complete(pdkim_ctx
*ctx
)
866 char *p
= ctx
->linebuf
;
867 int n
= ctx
->linebuf_offset
;
868 pdkim_signature
*sig
= ctx
->sig
; /*XXX assumes only one sig */
870 /* Ignore extra data if we've seen the end-of-data marker */
871 if (ctx
->flags
& PDKIM_SEEN_EOD
) goto BAIL
;
873 /* We've always got one extra byte to stuff a zero ... */
874 ctx
->linebuf
[ctx
->linebuf_offset
] = '\0';
876 /* Terminate on EOD marker */
877 if (ctx
->flags
& PDKIM_DOT_TERM
)
879 if (memcmp(p
, ".\r\n", 3) == 0)
880 return pdkim_body_complete(ctx
);
883 if (memcmp(p
, "..", 2) == 0)
890 /* Empty lines need to be buffered until we find a non-empty line */
891 if (memcmp(p
, "\r\n", 2) == 0)
893 ctx
->num_buffered_crlf
++;
897 if (sig
&& sig
->canon_body
== PDKIM_CANON_RELAXED
)
899 /* Lines with just spaces need to be buffered too */
901 while (memcmp(check
, "\r\n", 2) != 0)
905 if (c
!= '\t' && c
!= ' ')
910 ctx
->num_buffered_crlf
++;
915 /* At this point, we have a non-empty line, so release the buffered ones. */
916 while (ctx
->num_buffered_crlf
)
918 pdkim_update_bodyhash(ctx
, "\r\n", 2);
919 ctx
->num_buffered_crlf
--;
922 pdkim_update_bodyhash(ctx
, p
, n
);
925 ctx
->linebuf_offset
= 0;
930 /* -------------------------------------------------------------------------- */
931 /* Callback from pdkim_feed below for processing complete headers */
932 #define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
935 pdkim_header_complete(pdkim_ctx
*ctx
)
937 /* Special case: The last header can have an extra \r appended */
938 if ( (ctx
->cur_header_len
> 1) &&
939 (ctx
->cur_header
[(ctx
->cur_header_len
)-1] == '\r') )
940 --ctx
->cur_header_len
;
941 ctx
->cur_header
[ctx
->cur_header_len
] = '\0';
944 if (ctx
->num_headers
> PDKIM_MAX_HEADERS
) goto BAIL
;
946 /* SIGNING -------------------------------------------------------------- */
947 if (ctx
->flags
& PDKIM_MODE_SIGN
)
949 pdkim_signature
*sig
;
951 for (sig
= ctx
->sig
; sig
; sig
= sig
->next
) /* Traverse all signatures */
953 /* Add header to the signed headers list (in reverse order) */
954 sig
->headers
= pdkim_prepend_stringlist(sig
->headers
,
958 /* VERIFICATION ----------------------------------------------------------- */
959 /* DKIM-Signature: headers are added to the verification list */
962 if (strncasecmp(CCS ctx
->cur_header
,
963 DKIM_SIGNATURE_HEADERNAME
,
964 Ustrlen(DKIM_SIGNATURE_HEADERNAME
)) == 0)
966 pdkim_signature
*new_sig
;
968 /* Create and chain new signature block */
969 DEBUG(D_acl
) debug_printf(
970 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
972 if ((new_sig
= pdkim_parse_sig_header(ctx
, ctx
->cur_header
)))
974 pdkim_signature
*last_sig
= ctx
->sig
;
979 while (last_sig
->next
) last_sig
= last_sig
->next
;
980 last_sig
->next
= new_sig
;
984 DEBUG(D_acl
) debug_printf(
985 "Error while parsing signature header\n"
986 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
989 /* every other header is stored for signature verification */
991 ctx
->headers
= pdkim_prepend_stringlist(ctx
->headers
, ctx
->cur_header
);
995 *ctx
->cur_header
= '\0';
996 ctx
->cur_header_len
= 0; /* leave buffer for reuse */
1002 /* -------------------------------------------------------------------------- */
1003 #define HEADER_BUFFER_FRAG_SIZE 256
1006 pdkim_feed(pdkim_ctx
*ctx
, char *data
, int len
)
1010 /* Alternate EOD signal, used in non-dotstuffing mode */
1012 pdkim_body_complete(ctx
);
1014 else for (p
= 0; p
<len
; p
++)
1018 if (ctx
->flags
& PDKIM_PAST_HDRS
)
1020 if (c
== '\n' && !(ctx
->flags
& PDKIM_SEEN_CR
)) /* emulate the CR */
1022 ctx
->linebuf
[ctx
->linebuf_offset
++] = '\r';
1023 if (ctx
->linebuf_offset
== PDKIM_MAX_BODY_LINE_LEN
-1)
1024 return PDKIM_ERR_LONG_LINE
;
1027 /* Processing body byte */
1028 ctx
->linebuf
[ctx
->linebuf_offset
++] = c
;
1030 ctx
->flags
|= PDKIM_SEEN_CR
;
1034 ctx
->flags
&= ~PDKIM_SEEN_CR
;
1035 if ((rc
= pdkim_bodyline_complete(ctx
)) != PDKIM_OK
)
1039 if (ctx
->linebuf_offset
== PDKIM_MAX_BODY_LINE_LEN
-1)
1040 return PDKIM_ERR_LONG_LINE
;
1044 /* Processing header byte */
1046 ctx
->flags
|= PDKIM_SEEN_CR
;
1049 if (!(ctx
->flags
& PDKIM_SEEN_CR
)) /* emulate the CR */
1050 ctx
->cur_header
= string_catn(ctx
->cur_header
, &ctx
->cur_header_size
,
1051 &ctx
->cur_header_len
, CUS
"\r", 1);
1053 if (ctx
->flags
& PDKIM_SEEN_LF
)
1055 int rc
= pdkim_header_complete(ctx
); /* Seen last header line */
1056 if (rc
!= PDKIM_OK
) return rc
;
1058 ctx
->flags
= ctx
->flags
& ~(PDKIM_SEEN_LF
|PDKIM_SEEN_CR
) | PDKIM_PAST_HDRS
;
1059 DEBUG(D_acl
) debug_printf(
1060 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>\n");
1064 ctx
->flags
= ctx
->flags
& ~PDKIM_SEEN_CR
| PDKIM_SEEN_LF
;
1066 else if (ctx
->flags
& PDKIM_SEEN_LF
)
1068 if (!(c
== '\t' || c
== ' '))
1070 int rc
= pdkim_header_complete(ctx
); /* End of header */
1071 if (rc
!= PDKIM_OK
) return rc
;
1073 ctx
->flags
&= ~PDKIM_SEEN_LF
;
1076 if (ctx
->cur_header_len
< PDKIM_MAX_HEADER_LEN
)
1077 ctx
->cur_header
= string_catn(ctx
->cur_header
, &ctx
->cur_header_size
,
1078 &ctx
->cur_header_len
, CUS
&data
[p
], 1);
1086 /* Extend a grwong header with a continuation-linebreak */
1088 pdkim_hdr_cont(uschar
* str
, int * size
, int * ptr
, int * col
)
1091 return string_catn(str
, size
, ptr
, US
"\r\n\t", 3);
1097 * RFC 5322 specifies that header line length SHOULD be no more than 78
1101 * returns uschar * (not nul-terminated)
1103 * col: this int holds and receives column number (octets since last '\n')
1104 * str: partial string to append to
1105 * size: current buffer size for str
1106 * ptr: current tail-pointer for str
1107 * pad: padding, split line or space after before or after eg: ";"
1108 * intro: - must join to payload eg "h=", usually the tag name
1109 * payload: eg base64 data - long data can be split arbitrarily.
1111 * this code doesn't fold the header in some of the places that RFC4871
1112 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1113 * pairs and inside long values. it also always spaces or breaks after the
1116 * no guarantees are made for output given out-of range input. like tag
1117 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
1121 pdkim_headcat(int * col
, uschar
* str
, int * size
, int * ptr
,
1122 const uschar
* pad
, const uschar
* intro
, const uschar
* payload
)
1130 str
= pdkim_hdr_cont(str
, size
, ptr
, col
);
1131 str
= string_catn(str
, size
, ptr
, pad
, l
);
1135 l
= (pad
?1:0) + (intro
?Ustrlen(intro
):0);
1138 { /*can't fit intro - start a new line to make room.*/
1139 str
= pdkim_hdr_cont(str
, size
, ptr
, col
);
1140 l
= intro
?Ustrlen(intro
):0;
1143 l
+= payload
? Ustrlen(payload
):0 ;
1146 { /* this fragment will not fit on a single line */
1149 str
= string_catn(str
, size
, ptr
, US
" ", 1);
1151 pad
= NULL
; /* only want this once */
1157 size_t sl
= Ustrlen(intro
);
1159 str
= string_catn(str
, size
, ptr
, intro
, sl
);
1162 intro
= NULL
; /* only want this once */
1167 size_t sl
= Ustrlen(payload
);
1168 size_t chomp
= *col
+sl
< 77 ? sl
: 78-*col
;
1170 str
= string_catn(str
, size
, ptr
, payload
, chomp
);
1176 /* the while precondition tells us it didn't fit. */
1177 str
= pdkim_hdr_cont(str
, size
, ptr
, col
);
1182 str
= pdkim_hdr_cont(str
, size
, ptr
, col
);
1188 str
= string_catn(str
, size
, ptr
, US
" ", 1);
1195 size_t sl
= Ustrlen(intro
);
1197 str
= string_catn(str
, size
, ptr
, intro
, sl
);
1205 size_t sl
= Ustrlen(payload
);
1207 str
= string_catn(str
, size
, ptr
, payload
, sl
);
1215 /* -------------------------------------------------------------------------- */
1218 pdkim_create_header(pdkim_signature
*sig
, BOOL final
)
1223 uschar
* hdr
; int hdr_size
= 0, hdr_len
= 0;
1224 uschar
* canon_all
; int can_size
= 0, can_len
= 0;
1226 canon_all
= string_cat (NULL
, &can_size
, &can_len
,
1227 pdkim_canons
[sig
->canon_headers
]);
1228 canon_all
= string_catn(canon_all
, &can_size
, &can_len
, US
"/", 1);
1229 canon_all
= string_cat (canon_all
, &can_size
, &can_len
,
1230 pdkim_canons
[sig
->canon_body
]);
1231 canon_all
[can_len
] = '\0';
1233 hdr
= string_cat(NULL
, &hdr_size
, &hdr_len
,
1234 US
"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION
);
1237 /* Required and static bits */
1238 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"a=",
1239 pdkim_algos
[sig
->algo
]);
1240 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"q=",
1241 pdkim_querymethods
[sig
->querymethod
]);
1242 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"c=",
1244 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"d=",
1246 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"s=",
1249 /* list of header names can be split between items. */
1251 uschar
* n
= string_copy(sig
->headernames
);
1252 uschar
* i
= US
"h=";
1257 uschar
* c
= Ustrchr(n
, ':');
1262 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, NULL
, NULL
, US
":");
1264 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, s
, i
, n
);
1275 base64_bh
= pdkim_encode_base64(&sig
->bodyhash
);
1276 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"bh=", base64_bh
);
1280 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"i=", sig
->identity
);
1282 if (sig
->created
> 0)
1286 snprintf(CS minibuf
, sizeof(minibuf
), "%lu", sig
->created
);
1287 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"t=", minibuf
);
1290 if (sig
->expires
> 0)
1294 snprintf(CS minibuf
, sizeof(minibuf
), "%lu", sig
->expires
);
1295 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"x=", minibuf
);
1298 if (sig
->bodylength
>= 0)
1302 snprintf(CS minibuf
, sizeof(minibuf
), "%lu", sig
->bodylength
);
1303 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"l=", minibuf
);
1306 /* Preliminary or final version? */
1307 base64_b
= final
? pdkim_encode_base64(&sig
->sigdata
) : US
"";
1308 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"b=", base64_b
);
1310 /* add trailing semicolon: I'm not sure if this is actually needed */
1311 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, NULL
, US
";", US
"");
1313 hdr
[hdr_len
] = '\0';
1318 /* -------------------------------------------------------------------------- */
1320 static pdkim_pubkey
*
1321 pdkim_key_from_dns(pdkim_ctx
* ctx
, pdkim_signature
* sig
, ev_ctx
* vctx
)
1323 uschar
* dns_txt_name
, * dns_txt_reply
;
1325 const uschar
* errstr
;
1327 /* Fetch public key for signing domain, from DNS */
1329 dns_txt_name
= string_sprintf("%s._domainkey.%s.", sig
->selector
, sig
->domain
);
1331 dns_txt_reply
= store_get(PDKIM_DNS_TXT_MAX_RECLEN
);
1332 memset(dns_txt_reply
, 0, PDKIM_DNS_TXT_MAX_RECLEN
);
1334 if ( ctx
->dns_txt_callback(CS dns_txt_name
, CS dns_txt_reply
) != PDKIM_OK
1335 || dns_txt_reply
[0] == '\0'
1338 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1339 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE
;
1346 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1348 pdkim_quoteprint(CUS dns_txt_reply
, Ustrlen(dns_txt_reply
));
1351 if ( !(p
= pdkim_parse_pubkey_record(ctx
, CUS dns_txt_reply
))
1352 || (Ustrcmp(p
->srvtype
, "*") != 0 && Ustrcmp(p
->srvtype
, "email") != 0)
1355 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1356 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD
;
1361 debug_printf(" Invalid public key service type '%s'\n", p
->srvtype
);
1363 debug_printf(" Error while parsing public key record\n");
1365 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1370 DEBUG(D_acl
) debug_printf(
1371 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1373 /* Import public key */
1374 if ((errstr
= exim_rsa_verify_init(&p
->key
, vctx
)))
1376 DEBUG(D_acl
) debug_printf("verify_init: %s\n", errstr
);
1377 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1378 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_PUBKEY_IMPORT
;
1386 /* -------------------------------------------------------------------------- */
1389 pdkim_feed_finish(pdkim_ctx
*ctx
, pdkim_signature
**return_signatures
)
1391 pdkim_signature
*sig
= ctx
->sig
;
1393 /* Check if we must still flush a (partial) header. If that is the
1394 case, the message has no body, and we must compute a body hash
1395 out of '<CR><LF>' */
1396 if (ctx
->cur_header
&& ctx
->cur_header_len
)
1398 int rc
= pdkim_header_complete(ctx
);
1399 if (rc
!= PDKIM_OK
) return rc
;
1400 pdkim_update_bodyhash(ctx
, "\r\n", 2);
1403 DEBUG(D_acl
) debug_printf(
1404 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1406 /* Build (and/or evaluate) body hash */
1407 pdkim_finish_bodyhash(ctx
);
1411 BOOL is_sha1
= sig
->algo
== PDKIM_ALGO_RSA_SHA1
;
1413 uschar
* sig_hdr
= US
"";
1416 int hdata_alloc
= 0;
1421 exim_sha_init(&hhash_ctx
, is_sha1
? HASH_SHA1
: HASH_SHA256
);
1423 DEBUG(D_acl
) debug_printf(
1424 "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>>>\n");
1426 /* SIGNING ---------------------------------------------------------------- */
1427 /* When signing, walk through our header list and add them to the hash. As we
1428 go, construct a list of the header's names to use for the h= parameter.
1429 Then append to that list any remaining header names for which there was no
1432 if (ctx
->flags
& PDKIM_MODE_SIGN
)
1434 uschar
* headernames
= NULL
; /* Collected signed header names */
1436 pdkim_stringlist
*p
;
1441 for (p
= sig
->headers
; p
; p
= p
->next
)
1442 if (header_name_match(p
->value
, sig
->sign_headers
) == PDKIM_OK
)
1445 /* Collect header names (Note: colon presence is guaranteed here) */
1446 uschar
* q
= Ustrchr(p
->value
, ':');
1448 headernames
= string_catn(headernames
, &hs
, &hl
,
1449 p
->value
, (q
- US p
->value
) + (p
->next
? 1 : 0));
1451 rh
= sig
->canon_headers
== PDKIM_CANON_RELAXED
1452 ? pdkim_relax_header(p
->value
, 1) /* cook header for relaxed canon */
1453 : string_copy(CUS p
->value
); /* just copy it for simple canon */
1455 /* Feed header to the hash algorithm */
1456 exim_sha_update(&hhash_ctx
, CUS rh
, Ustrlen(rh
));
1458 /* Remember headers block for signing (when the library cannot do incremental) */
1459 (void) exim_rsa_data_append(&hdata
, &hdata_alloc
, rh
);
1461 DEBUG(D_acl
) pdkim_quoteprint(rh
, Ustrlen(rh
));
1464 l
= sig
->sign_headers
;
1465 while((s
= string_nextinlist(&l
, &sep
, NULL
, 0)))
1467 { /*SSS string_append_listele() */
1468 if (hl
> 0 && headernames
[hl
-1] != ':')
1469 headernames
= string_catn(headernames
, &hs
, &hl
, US
":", 1);
1471 headernames
= string_cat(headernames
, &hs
, &hl
, s
);
1473 headernames
[hl
] = '\0';
1475 /* Copy headernames to signature struct */
1476 sig
->headernames
= headernames
;
1478 /* Create signature header with b= omitted */
1479 sig_hdr
= pdkim_create_header(sig
, FALSE
);
1482 /* VERIFICATION ----------------------------------------------------------- */
1483 /* When verifying, walk through the header name list in the h= parameter and
1484 add the headers to the hash in that order. */
1487 uschar
* p
= sig
->headernames
;
1489 pdkim_stringlist
* hdrs
;
1494 for (hdrs
= ctx
->headers
; hdrs
; hdrs
= hdrs
->next
)
1500 if ((q
= Ustrchr(p
, ':')))
1503 /*XXX walk the list of headers in same order as received. */
1504 for (hdrs
= ctx
->headers
; hdrs
; hdrs
= hdrs
->next
)
1506 && strncasecmp(CCS hdrs
->value
, CCS p
, Ustrlen(p
)) == 0
1507 && (hdrs
->value
)[Ustrlen(p
)] == ':'
1510 /* cook header for relaxed canon, or just copy it for simple */
1512 uschar
* rh
= sig
->canon_headers
== PDKIM_CANON_RELAXED
1513 ? pdkim_relax_header(hdrs
->value
, 1)
1514 : string_copy(CUS hdrs
->value
);
1516 /* Feed header to the hash algorithm */
1517 exim_sha_update(&hhash_ctx
, CUS rh
, Ustrlen(rh
));
1519 DEBUG(D_acl
) pdkim_quoteprint(rh
, Ustrlen(rh
));
1528 sig_hdr
= string_copy(sig
->rawsig_no_b_val
);
1532 DEBUG(D_acl
) debug_printf(
1533 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1535 /* Relax header if necessary */
1536 if (sig
->canon_headers
== PDKIM_CANON_RELAXED
)
1537 sig_hdr
= pdkim_relax_header(sig_hdr
, 0);
1542 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
1543 pdkim_quoteprint(CUS sig_hdr
, Ustrlen(sig_hdr
));
1545 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1548 /* Finalize header hash */
1549 exim_sha_update(&hhash_ctx
, CUS sig_hdr
, Ustrlen(sig_hdr
));
1550 exim_sha_finish(&hhash_ctx
, &hhash
);
1554 debug_printf("PDKIM [%s] Header hash computed: ", sig
->domain
);
1555 pdkim_hexprint(hhash
.data
, hhash
.len
);
1558 /* Remember headers block for signing (when the library cannot do incremental) */
1559 if (ctx
->flags
& PDKIM_MODE_SIGN
)
1560 (void) exim_rsa_data_append(&hdata
, &hdata_alloc
, US sig_hdr
);
1562 /* SIGNING ---------------------------------------------------------------- */
1563 if (ctx
->flags
& PDKIM_MODE_SIGN
)
1566 const uschar
* errstr
;
1568 /* Import private key */
1569 if ((errstr
= exim_rsa_signing_init(US sig
->rsa_privkey
, &sctx
)))
1571 DEBUG(D_acl
) debug_printf("signing_init: %s\n", errstr
);
1572 return PDKIM_ERR_RSA_PRIVKEY
;
1575 /* Do signing. With OpenSSL we are signing the hash of headers just
1576 calculated, with GnuTLS we have to sign an entire block of headers
1577 (due to available interfaces) and it recalculates the hash internally. */
1579 #if defined(RSA_OPENSSL) || defined(RSA_GCRYPT)
1583 if ((errstr
= exim_rsa_sign(&sctx
, is_sha1
, &hdata
, &sig
->sigdata
)))
1585 DEBUG(D_acl
) debug_printf("signing: %s\n", errstr
);
1586 return PDKIM_ERR_RSA_SIGNING
;
1591 debug_printf( "PDKIM [%s] b computed: ", sig
->domain
);
1592 pdkim_hexprint(sig
->sigdata
.data
, sig
->sigdata
.len
);
1595 sig
->signature_header
= pdkim_create_header(sig
, TRUE
);
1598 /* VERIFICATION ----------------------------------------------------------- */
1602 const uschar
* errstr
;
1605 /* Make sure we have all required signature tags */
1606 if (!( sig
->domain
&& *sig
->domain
1607 && sig
->selector
&& *sig
->selector
1608 && sig
->headernames
&& *sig
->headernames
1609 && sig
->bodyhash
.data
1610 && sig
->sigdata
.data
1615 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1616 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_SIGNATURE_ERROR
;
1618 DEBUG(D_acl
) debug_printf(
1619 " Error in DKIM-Signature header: tags missing or invalid\n"
1620 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1624 /* Make sure sig uses supported DKIM version (only v1) */
1625 if (sig
->version
!= 1)
1627 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1628 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_DKIM_VERSION
;
1630 DEBUG(D_acl
) debug_printf(
1631 " Error in DKIM-Signature header: unsupported DKIM version\n"
1632 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1636 if (!(sig
->pubkey
= pdkim_key_from_dns(ctx
, sig
, &vctx
)))
1639 /* Check the signature */
1640 if ((errstr
= exim_rsa_verify(&vctx
, is_sha1
, &hhash
, &sig
->sigdata
)))
1642 DEBUG(D_acl
) debug_printf("headers verify: %s\n", errstr
);
1643 sig
->verify_status
= PDKIM_VERIFY_FAIL
;
1644 sig
->verify_ext_status
= PDKIM_VERIFY_FAIL_MESSAGE
;
1649 /* We have a winner! (if bodyhash was correct earlier) */
1650 if (sig
->verify_status
== PDKIM_VERIFY_NONE
)
1651 sig
->verify_status
= PDKIM_VERIFY_PASS
;
1657 debug_printf("PDKIM [%s] signature status: %s",
1658 sig
->domain
, pdkim_verify_status_str(sig
->verify_status
));
1659 if (sig
->verify_ext_status
> 0)
1660 debug_printf(" (%s)\n",
1661 pdkim_verify_ext_status_str(sig
->verify_ext_status
));
1670 /* If requested, set return pointer to signature(s) */
1671 if (return_signatures
)
1672 *return_signatures
= ctx
->sig
;
1678 /* -------------------------------------------------------------------------- */
1680 DLLEXPORT pdkim_ctx
*
1681 pdkim_init_verify(int(*dns_txt_callback
)(char *, char *), BOOL dot_stuffing
)
1685 ctx
= store_get(sizeof(pdkim_ctx
));
1686 memset(ctx
, 0, sizeof(pdkim_ctx
));
1688 if (dot_stuffing
) ctx
->flags
= PDKIM_DOT_TERM
;
1689 ctx
->linebuf
= store_get(PDKIM_MAX_BODY_LINE_LEN
);
1690 ctx
->dns_txt_callback
= dns_txt_callback
;
1696 /* -------------------------------------------------------------------------- */
1698 DLLEXPORT pdkim_ctx
*
1699 pdkim_init_sign(char * domain
, char * selector
, char * rsa_privkey
, int algo
,
1700 BOOL dot_stuffed
, int(*dns_txt_callback
)(char *, char *))
1703 pdkim_signature
* sig
;
1705 if (!domain
|| !selector
|| !rsa_privkey
)
1708 ctx
= store_get(sizeof(pdkim_ctx
) + PDKIM_MAX_BODY_LINE_LEN
+ sizeof(pdkim_signature
));
1709 memset(ctx
, 0, sizeof(pdkim_ctx
));
1711 ctx
->flags
= dot_stuffed
? PDKIM_MODE_SIGN
| PDKIM_DOT_TERM
: PDKIM_MODE_SIGN
;
1712 ctx
->linebuf
= CS (ctx
+1);
1714 DEBUG(D_acl
) ctx
->dns_txt_callback
= dns_txt_callback
;
1716 sig
= (pdkim_signature
*)(ctx
->linebuf
+ PDKIM_MAX_BODY_LINE_LEN
);
1717 memset(sig
, 0, sizeof(pdkim_signature
));
1719 sig
->bodylength
= -1;
1722 sig
->domain
= string_copy(US domain
);
1723 sig
->selector
= string_copy(US selector
);
1724 sig
->rsa_privkey
= string_copy(US rsa_privkey
);
1727 exim_sha_init(&sig
->body_hash
, algo
== PDKIM_ALGO_RSA_SHA1
? HASH_SHA1
: HASH_SHA256
);
1731 pdkim_signature s
= *sig
;
1734 debug_printf("PDKIM (checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1735 if (!pdkim_key_from_dns(ctx
, &s
, &vctx
))
1736 debug_printf("WARNING: bad dkim key in dns\n");
1737 debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1744 /* -------------------------------------------------------------------------- */
1747 pdkim_set_optional(pdkim_ctx
*ctx
,
1753 unsigned long created
,
1754 unsigned long expires
)
1756 pdkim_signature
* sig
= ctx
->sig
;
1759 sig
->identity
= string_copy(US identity
);
1761 sig
->sign_headers
= string_copy(sign_headers
1762 ? US sign_headers
: US PDKIM_DEFAULT_SIGN_HEADERS
);
1764 sig
->canon_headers
= canon_headers
;
1765 sig
->canon_body
= canon_body
;
1766 sig
->bodylength
= bodylength
;
1767 sig
->created
= created
;
1768 sig
->expires
= expires
;
1782 #endif /*DISABLE_DKIM*/