2 * PDKIM - a RFC4871 (DKIM) implementation
4 * Copyright (C) 2009 - 2016 Tom Kistner <tom@duncanthrax.net>
5 * Copyright (C) 2016 - 2017 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 if (data
) for (i
= 0 ; i
< len
; i
++) debug_printf("%02x", data
[i
]);
196 else debug_printf("<NULL>");
202 static pdkim_stringlist
*
203 pdkim_prepend_stringlist(pdkim_stringlist
* base
, const uschar
* str
)
205 pdkim_stringlist
* new_entry
= store_get(sizeof(pdkim_stringlist
));
207 memset(new_entry
, 0, sizeof(pdkim_stringlist
));
208 new_entry
->value
= string_copy(str
);
209 if (base
) new_entry
->next
= base
;
215 /* Trim whitespace fore & aft */
218 pdkim_strtrim(uschar
* str
)
222 while (*p
== '\t' || *p
== ' ') p
++; /* skip whitespace */
223 while (*p
) {*q
= *p
; q
++; p
++;} /* dump the leading whitespace */
225 while (q
!= str
&& ( (*q
== '\0') || (*q
== '\t') || (*q
== ' ') ) )
226 { /* dump trailing whitespace */
234 /* -------------------------------------------------------------------------- */
237 pdkim_free_ctx(pdkim_ctx
*ctx
)
242 /* -------------------------------------------------------------------------- */
243 /* Matches the name of the passed raw "header" against
244 the passed colon-separated "tick", and invalidates
245 the entry in tick. Returns OK or fail-code */
246 /*XXX might be safer done using a pdkim_stringlist for "tick" */
249 header_name_match(const uschar
* header
, uschar
* tick
)
255 uschar
* hcolon
= Ustrchr(header
, ':'); /* Get header name */
258 return PDKIM_FAIL
; /* This isn't a header */
260 /* if we had strncmpic() we wouldn't need this copy */
261 hname
= string_copyn(header
, hcolon
-header
);
263 /* Copy tick-off list locally, so we can punch zeroes into it */
264 p
= lcopy
= string_copy(tick
);
266 for (q
= Ustrchr(p
, ':'); q
; q
= Ustrchr(p
, ':'))
269 if (strcmpic(p
, hname
) == 0)
275 if (strcmpic(p
, hname
) == 0)
281 /* Invalidate header name instance in tick-off list */
287 /* -------------------------------------------------------------------------- */
288 /* Performs "relaxed" canonicalization of a header. */
291 pdkim_relax_header(const uschar
* header
, int crlf
)
293 BOOL past_field_name
= FALSE
;
294 BOOL seen_wsp
= FALSE
;
296 uschar
* relaxed
= store_get(Ustrlen(header
)+3);
297 uschar
* q
= relaxed
;
299 for (p
= header
; *p
; p
++)
303 if (c
== '\r' || c
== '\n')
305 if (c
== '\t' || c
== ' ')
309 c
= ' '; /* Turns WSP into SP */
313 if (!past_field_name
&& c
== ':')
315 if (seen_wsp
) q
--; /* This removes WSP before the colon */
316 seen_wsp
= TRUE
; /* This removes WSP after the colon */
317 past_field_name
= TRUE
;
322 /* Lowercase header name */
323 if (!past_field_name
) c
= tolower(c
);
327 if (q
> relaxed
&& q
[-1] == ' ') q
--; /* Squash eventual trailing SP */
329 if (crlf
) { *q
++ = '\r'; *q
++ = '\n'; }
335 /* -------------------------------------------------------------------------- */
336 #define PDKIM_QP_ERROR_DECODE -1
339 pdkim_decode_qp_char(uschar
*qp_p
, int *c
)
341 uschar
*initial_pos
= qp_p
;
343 /* Advance one char */
346 /* Check for two hex digits and decode them */
347 if (isxdigit(*qp_p
) && isxdigit(qp_p
[1]))
349 /* Do hex conversion */
350 *c
= (isdigit(*qp_p
) ? *qp_p
- '0' : toupper(*qp_p
) - 'A' + 10) << 4;
351 *c
|= isdigit(qp_p
[1]) ? qp_p
[1] - '0' : toupper(qp_p
[1]) - 'A' + 10;
355 /* Illegal char here */
356 *c
= PDKIM_QP_ERROR_DECODE
;
361 /* -------------------------------------------------------------------------- */
364 pdkim_decode_qp(uschar
* str
)
369 uschar
* n
= store_get(Ustrlen(str
)+1);
377 p
= pdkim_decode_qp_char(p
, &nchar
);
393 /* -------------------------------------------------------------------------- */
396 pdkim_decode_base64(uschar
*str
, blob
* b
)
399 dlen
= b64decode(str
, &b
->data
);
400 if (dlen
< 0) b
->data
= NULL
;
405 pdkim_encode_base64(blob
* b
)
407 return b64encode(b
->data
, b
->len
);
411 /* -------------------------------------------------------------------------- */
412 #define PDKIM_HDR_LIMBO 0
413 #define PDKIM_HDR_TAG 1
414 #define PDKIM_HDR_VALUE 2
416 static pdkim_signature
*
417 pdkim_parse_sig_header(pdkim_ctx
*ctx
, uschar
* raw_hdr
)
419 pdkim_signature
*sig
;
421 uschar
* cur_tag
= NULL
; int ts
= 0, tl
= 0;
422 uschar
* cur_val
= NULL
; int vs
= 0, vl
= 0;
423 BOOL past_hname
= FALSE
;
424 BOOL in_b_val
= FALSE
;
425 int where
= PDKIM_HDR_LIMBO
;
428 sig
= store_get(sizeof(pdkim_signature
));
429 memset(sig
, 0, sizeof(pdkim_signature
));
430 sig
->bodylength
= -1;
432 /* Set so invalid/missing data error display is accurate */
436 q
= sig
->rawsig_no_b_val
= store_get(Ustrlen(raw_hdr
)+1);
438 for (p
= raw_hdr
; ; p
++)
443 if (c
== '\r' || c
== '\n')
446 /* Fast-forward through header name */
449 if (c
== ':') past_hname
= TRUE
;
453 if (where
== PDKIM_HDR_LIMBO
)
455 /* In limbo, just wait for a tag-char to appear */
456 if (!(c
>= 'a' && c
<= 'z'))
459 where
= PDKIM_HDR_TAG
;
462 if (where
== PDKIM_HDR_TAG
)
464 if (c
>= 'a' && c
<= 'z')
465 cur_tag
= string_catn(cur_tag
, &ts
, &tl
, p
, 1);
470 if (Ustrcmp(cur_tag
, "b") == 0)
475 where
= PDKIM_HDR_VALUE
;
480 if (where
== PDKIM_HDR_VALUE
)
482 if (c
== '\r' || c
== '\n' || c
== ' ' || c
== '\t')
485 if (c
== ';' || c
== '\0')
490 pdkim_strtrim(cur_val
);
492 DEBUG(D_acl
) debug_printf(" %s=%s\n", cur_tag
, cur_val
);
497 pdkim_decode_base64(cur_val
,
498 cur_tag
[1] == 'h' ? &sig
->bodyhash
: &sig
->sighash
);
501 /* We only support version 1, and that is currently the
502 only version there is. */
504 Ustrcmp(cur_val
, PDKIM_SIGNATURE_VERSION
) == 0 ? 1 : -1;
507 for (i
= 0; pdkim_algos
[i
]; i
++)
508 if (Ustrcmp(cur_val
, pdkim_algos
[i
]) == 0)
515 for (i
= 0; pdkim_combined_canons
[i
].str
; i
++)
516 if (Ustrcmp(cur_val
, pdkim_combined_canons
[i
].str
) == 0)
518 sig
->canon_headers
= pdkim_combined_canons
[i
].canon_headers
;
519 sig
->canon_body
= pdkim_combined_canons
[i
].canon_body
;
524 for (i
= 0; pdkim_querymethods
[i
]; i
++)
525 if (Ustrcmp(cur_val
, pdkim_querymethods
[i
]) == 0)
527 sig
->querymethod
= i
;
532 sig
->selector
= string_copy(cur_val
); break;
534 sig
->domain
= string_copy(cur_val
); break;
536 sig
->identity
= pdkim_decode_qp(cur_val
); break;
538 sig
->created
= strtoul(CS cur_val
, NULL
, 10); break;
540 sig
->expires
= strtoul(CS cur_val
, NULL
, 10); break;
542 sig
->bodylength
= strtol(CS cur_val
, NULL
, 10); break;
544 sig
->headernames
= string_copy(cur_val
); break;
546 sig
->copiedheaders
= pdkim_decode_qp(cur_val
); break;
548 DEBUG(D_acl
) debug_printf(" Unknown tag encountered\n");
555 where
= PDKIM_HDR_LIMBO
;
558 cur_val
= string_catn(cur_val
, &vs
, &vl
, p
, 1);
570 /* Chomp raw header. The final newline must not be added to the signature. */
571 while (--q
> sig
->rawsig_no_b_val
&& (*q
== '\r' || *q
== '\n'))
577 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
578 pdkim_quoteprint(US sig
->rawsig_no_b_val
, Ustrlen(sig
->rawsig_no_b_val
));
580 "PDKIM >> Sig size: %4u bits\n", (unsigned) sig
->sighash
.len
*8);
582 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
585 if (!exim_sha_init(&sig
->body_hash_ctx
,
586 sig
->algo
== PDKIM_ALGO_RSA_SHA1
? HASH_SHA1
: HASH_SHA256
))
588 DEBUG(D_acl
) debug_printf("PDKIM: hash init internal error\n");
595 /* -------------------------------------------------------------------------- */
597 static pdkim_pubkey
*
598 pdkim_parse_pubkey_record(pdkim_ctx
*ctx
, const uschar
*raw_record
)
602 uschar
* cur_tag
= NULL
; int ts
= 0, tl
= 0;
603 uschar
* cur_val
= NULL
; int vs
= 0, vl
= 0;
604 int where
= PDKIM_HDR_LIMBO
;
606 pub
= store_get(sizeof(pdkim_pubkey
));
607 memset(pub
, 0, sizeof(pdkim_pubkey
));
609 for (p
= raw_record
; ; p
++)
614 if (c
!= '\r' && c
!= '\n') switch (where
)
616 case PDKIM_HDR_LIMBO
: /* In limbo, just wait for a tag-char to appear */
617 if (!(c
>= 'a' && c
<= 'z'))
619 where
= PDKIM_HDR_TAG
;
623 if (c
>= 'a' && c
<= 'z')
624 cur_tag
= string_catn(cur_tag
, &ts
, &tl
, p
, 1);
629 where
= PDKIM_HDR_VALUE
;
633 case PDKIM_HDR_VALUE
:
634 if (c
== ';' || c
== '\0')
639 pdkim_strtrim(cur_val
);
640 DEBUG(D_acl
) debug_printf(" %s=%s\n", cur_tag
, cur_val
);
645 pub
->version
= string_copy(cur_val
); break;
648 /* This field appears to never be used. Also, unclear why
649 a 'k' (key-type_ would go in this field name. There is a field
650 "keytype", also never used.
651 pub->hashes = string_copy(cur_val);
655 pub
->granularity
= string_copy(cur_val
); break;
657 pub
->notes
= pdkim_decode_qp(cur_val
); break;
659 pdkim_decode_base64(US cur_val
, &pub
->key
); break;
661 pub
->srvtype
= string_copy(cur_val
); break;
663 if (Ustrchr(cur_val
, 'y') != NULL
) pub
->testing
= 1;
664 if (Ustrchr(cur_val
, 's') != NULL
) pub
->no_subdomaining
= 1;
667 DEBUG(D_acl
) debug_printf(" Unknown tag encountered\n");
673 where
= PDKIM_HDR_LIMBO
;
676 cur_val
= string_catn(cur_val
, &vs
, &vl
, p
, 1);
680 if (c
== '\0') break;
683 /* Set fallback defaults */
684 if (!pub
->version
) pub
->version
= string_copy(PDKIM_PUB_RECORD_VERSION
);
685 else if (Ustrcmp(pub
->version
, PDKIM_PUB_RECORD_VERSION
) != 0) return NULL
;
687 if (!pub
->granularity
) pub
->granularity
= string_copy(US
"*");
689 if (!pub->keytype ) pub->keytype = string_copy(US"rsa");
691 if (!pub
->srvtype
) pub
->srvtype
= string_copy(US
"*");
701 /* -------------------------------------------------------------------------- */
704 pdkim_update_bodyhash(pdkim_ctx
* ctx
, const char * data
, int len
)
706 pdkim_signature
* sig
;
707 uschar
* relaxed_data
= NULL
; /* Cache relaxed version of data */
710 /* Traverse all signatures, updating their hashes. */
711 for (sig
= ctx
->sig
; sig
; sig
= sig
->next
)
713 /* Defaults to simple canon (no further treatment necessary) */
714 const uschar
*canon_data
= CUS data
;
717 if (sig
->canon_body
== PDKIM_CANON_RELAXED
)
719 /* Relax the line if not done already */
722 BOOL seen_wsp
= FALSE
;
726 /* We want to be able to free this else we allocate
727 for the entire message which could be many MB. Since
728 we don't know what allocations the SHA routines might
729 do, not safe to use store_get()/store_reset(). */
731 relaxed_data
= store_malloc(len
+1);
733 for (p
= data
; *p
; p
++)
738 if (q
> 0 && relaxed_data
[q
-1] == ' ')
741 else if (c
== '\t' || c
== ' ')
743 c
= ' '; /* Turns WSP into SP */
750 relaxed_data
[q
++] = c
;
752 relaxed_data
[q
] = '\0';
755 canon_data
= relaxed_data
;
756 canon_len
= relaxed_len
;
759 /* Make sure we don't exceed the to-be-signed body length */
760 if ( sig
->bodylength
>= 0
761 && sig
->signed_body_bytes
+ (unsigned long)canon_len
> sig
->bodylength
763 canon_len
= sig
->bodylength
- sig
->signed_body_bytes
;
767 exim_sha_update(&sig
->body_hash_ctx
, CUS canon_data
, canon_len
);
768 sig
->signed_body_bytes
+= canon_len
;
769 DEBUG(D_acl
) pdkim_quoteprint(canon_data
, canon_len
);
773 if (relaxed_data
) store_free(relaxed_data
);
778 /* -------------------------------------------------------------------------- */
781 pdkim_finish_bodyhash(pdkim_ctx
*ctx
)
783 pdkim_signature
*sig
;
785 /* Traverse all signatures */
786 for (sig
= ctx
->sig
; sig
; sig
= sig
->next
)
787 { /* Finish hashes */
790 exim_sha_finish(&sig
->body_hash_ctx
, &bh
);
794 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
795 "PDKIM [%s] Body hash computed: ",
796 sig
->domain
, sig
->signed_body_bytes
, sig
->domain
);
797 pdkim_hexprint(CUS bh
.data
, bh
.len
);
800 /* SIGNING -------------------------------------------------------------- */
801 if (ctx
->flags
& PDKIM_MODE_SIGN
)
805 /* If bodylength limit is set, and we have received less bytes
806 than the requested amount, effectively remove the limit tag. */
807 if (sig
->signed_body_bytes
< sig
->bodylength
)
808 sig
->bodylength
= -1;
812 /* VERIFICATION --------------------------------------------------------- */
813 /* Be careful that the header sig included a bodyash */
815 if (sig
->bodyhash
.data
&& memcmp(bh
.data
, sig
->bodyhash
.data
, bh
.len
) == 0)
817 DEBUG(D_acl
) debug_printf("PDKIM [%s] Body hash verified OK\n", sig
->domain
);
823 debug_printf("PDKIM [%s] Body hash signature from headers: ", sig
->domain
);
824 pdkim_hexprint(sig
->bodyhash
.data
, sig
->bodyhash
.len
);
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
;
836 pdkim_body_complete(pdkim_ctx
* ctx
)
838 pdkim_signature
* sig
= ctx
->sig
; /*XXX assumes only one sig */
840 /* In simple body mode, if any empty lines were buffered,
841 replace with one. rfc 4871 3.4.3 */
842 /*XXX checking the signed-body-bytes is a gross hack; I think
843 it indicates that all linebreaks should be buffered, including
844 the one terminating a text line */
846 if ( sig
&& sig
->canon_body
== PDKIM_CANON_SIMPLE
847 && sig
->signed_body_bytes
== 0
848 && ctx
->num_buffered_crlf
> 0
850 pdkim_update_bodyhash(ctx
, "\r\n", 2);
852 ctx
->flags
|= PDKIM_SEEN_EOD
;
853 ctx
->linebuf_offset
= 0;
859 /* -------------------------------------------------------------------------- */
860 /* Call from pdkim_feed below for processing complete body lines */
863 pdkim_bodyline_complete(pdkim_ctx
*ctx
)
865 char *p
= ctx
->linebuf
;
866 int n
= ctx
->linebuf_offset
;
867 pdkim_signature
*sig
= ctx
->sig
; /*XXX assumes only one sig */
869 /* Ignore extra data if we've seen the end-of-data marker */
870 if (ctx
->flags
& PDKIM_SEEN_EOD
) goto BAIL
;
872 /* We've always got one extra byte to stuff a zero ... */
873 ctx
->linebuf
[ctx
->linebuf_offset
] = '\0';
875 /* Terminate on EOD marker */
876 if (ctx
->flags
& PDKIM_DOT_TERM
)
878 if (memcmp(p
, ".\r\n", 3) == 0)
879 return pdkim_body_complete(ctx
);
882 if (memcmp(p
, "..", 2) == 0)
889 /* Empty lines need to be buffered until we find a non-empty line */
890 if (memcmp(p
, "\r\n", 2) == 0)
892 ctx
->num_buffered_crlf
++;
896 if (sig
&& sig
->canon_body
== PDKIM_CANON_RELAXED
)
898 /* Lines with just spaces need to be buffered too */
900 while (memcmp(check
, "\r\n", 2) != 0)
904 if (c
!= '\t' && c
!= ' ')
909 ctx
->num_buffered_crlf
++;
914 /* At this point, we have a non-empty line, so release the buffered ones. */
915 while (ctx
->num_buffered_crlf
)
917 pdkim_update_bodyhash(ctx
, "\r\n", 2);
918 ctx
->num_buffered_crlf
--;
921 pdkim_update_bodyhash(ctx
, p
, n
);
924 ctx
->linebuf_offset
= 0;
929 /* -------------------------------------------------------------------------- */
930 /* Callback from pdkim_feed below for processing complete headers */
931 #define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
934 pdkim_header_complete(pdkim_ctx
*ctx
)
936 /* Special case: The last header can have an extra \r appended */
937 if ( (ctx
->cur_header_len
> 1) &&
938 (ctx
->cur_header
[(ctx
->cur_header_len
)-1] == '\r') )
939 --ctx
->cur_header_len
;
940 ctx
->cur_header
[ctx
->cur_header_len
] = '\0';
943 if (ctx
->num_headers
> PDKIM_MAX_HEADERS
) goto BAIL
;
945 /* SIGNING -------------------------------------------------------------- */
946 if (ctx
->flags
& PDKIM_MODE_SIGN
)
948 pdkim_signature
*sig
;
950 for (sig
= ctx
->sig
; sig
; sig
= sig
->next
) /* Traverse all signatures */
952 /* Add header to the signed headers list (in reverse order) */
953 sig
->headers
= pdkim_prepend_stringlist(sig
->headers
,
957 /* VERIFICATION ----------------------------------------------------------- */
958 /* DKIM-Signature: headers are added to the verification list */
963 debug_printf("PDKIM >> raw hdr: ");
964 pdkim_quoteprint(CUS ctx
->cur_header
, Ustrlen(ctx
->cur_header
));
966 if (strncasecmp(CCS ctx
->cur_header
,
967 DKIM_SIGNATURE_HEADERNAME
,
968 Ustrlen(DKIM_SIGNATURE_HEADERNAME
)) == 0)
970 pdkim_signature
* new_sig
, * last_sig
;
972 /* Create and chain new signature block. We could error-check for all
973 required tags here, but prefer to create the internal sig and expicitly
974 fail verification of it later. */
976 DEBUG(D_acl
) debug_printf(
977 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
979 new_sig
= pdkim_parse_sig_header(ctx
, ctx
->cur_header
);
981 if (!(last_sig
= ctx
->sig
))
985 while (last_sig
->next
) last_sig
= last_sig
->next
;
986 last_sig
->next
= new_sig
;
990 /* all headers are 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
;
1033 ctx
->flags
&= ~PDKIM_SEEN_CR
;
1034 if ((rc
= pdkim_bodyline_complete(ctx
)) != PDKIM_OK
)
1038 if (ctx
->linebuf_offset
== PDKIM_MAX_BODY_LINE_LEN
-1)
1039 return PDKIM_ERR_LONG_LINE
;
1043 /* Processing header byte */
1045 ctx
->flags
|= PDKIM_SEEN_CR
;
1048 if (!(ctx
->flags
& PDKIM_SEEN_CR
)) /* emulate the CR */
1049 ctx
->cur_header
= string_catn(ctx
->cur_header
, &ctx
->cur_header_size
,
1050 &ctx
->cur_header_len
, CUS
"\r", 1);
1052 if (ctx
->flags
& PDKIM_SEEN_LF
) /* Seen last header line */
1054 if ((rc
= pdkim_header_complete(ctx
)) != PDKIM_OK
)
1057 ctx
->flags
= ctx
->flags
& ~(PDKIM_SEEN_LF
|PDKIM_SEEN_CR
) | PDKIM_PAST_HDRS
;
1058 DEBUG(D_acl
) debug_printf(
1059 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1063 ctx
->flags
= ctx
->flags
& ~PDKIM_SEEN_CR
| PDKIM_SEEN_LF
;
1065 else if (ctx
->flags
& PDKIM_SEEN_LF
)
1067 if (!(c
== '\t' || c
== ' ')) /* End of header */
1068 if ((rc
= pdkim_header_complete(ctx
)) != PDKIM_OK
)
1070 ctx
->flags
&= ~PDKIM_SEEN_LF
;
1073 if (ctx
->cur_header_len
< PDKIM_MAX_HEADER_LEN
)
1074 ctx
->cur_header
= string_catn(ctx
->cur_header
, &ctx
->cur_header_size
,
1075 &ctx
->cur_header_len
, CUS
&data
[p
], 1);
1083 /* Extend a grwong header with a continuation-linebreak */
1085 pdkim_hdr_cont(uschar
* str
, int * size
, int * ptr
, int * col
)
1088 return string_catn(str
, size
, ptr
, US
"\r\n\t", 3);
1094 * RFC 5322 specifies that header line length SHOULD be no more than 78
1098 * returns uschar * (not nul-terminated)
1100 * col: this int holds and receives column number (octets since last '\n')
1101 * str: partial string to append to
1102 * size: current buffer size for str
1103 * ptr: current tail-pointer for str
1104 * pad: padding, split line or space after before or after eg: ";"
1105 * intro: - must join to payload eg "h=", usually the tag name
1106 * payload: eg base64 data - long data can be split arbitrarily.
1108 * this code doesn't fold the header in some of the places that RFC4871
1109 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1110 * pairs and inside long values. it also always spaces or breaks after the
1113 * no guarantees are made for output given out-of range input. like tag
1114 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
1118 pdkim_headcat(int * col
, uschar
* str
, int * size
, int * ptr
,
1119 const uschar
* pad
, const uschar
* intro
, const uschar
* payload
)
1127 str
= pdkim_hdr_cont(str
, size
, ptr
, col
);
1128 str
= string_catn(str
, size
, ptr
, pad
, l
);
1132 l
= (pad
?1:0) + (intro
?Ustrlen(intro
):0);
1135 { /*can't fit intro - start a new line to make room.*/
1136 str
= pdkim_hdr_cont(str
, size
, ptr
, col
);
1137 l
= intro
?Ustrlen(intro
):0;
1140 l
+= payload
? Ustrlen(payload
):0 ;
1143 { /* this fragment will not fit on a single line */
1146 str
= string_catn(str
, size
, ptr
, US
" ", 1);
1148 pad
= NULL
; /* only want this once */
1154 size_t sl
= Ustrlen(intro
);
1156 str
= string_catn(str
, size
, ptr
, intro
, sl
);
1159 intro
= NULL
; /* only want this once */
1164 size_t sl
= Ustrlen(payload
);
1165 size_t chomp
= *col
+sl
< 77 ? sl
: 78-*col
;
1167 str
= string_catn(str
, size
, ptr
, payload
, chomp
);
1173 /* the while precondition tells us it didn't fit. */
1174 str
= pdkim_hdr_cont(str
, size
, ptr
, col
);
1179 str
= pdkim_hdr_cont(str
, size
, ptr
, col
);
1185 str
= string_catn(str
, size
, ptr
, US
" ", 1);
1192 size_t sl
= Ustrlen(intro
);
1194 str
= string_catn(str
, size
, ptr
, intro
, sl
);
1202 size_t sl
= Ustrlen(payload
);
1204 str
= string_catn(str
, size
, ptr
, payload
, sl
);
1212 /* -------------------------------------------------------------------------- */
1215 pdkim_create_header(pdkim_signature
*sig
, BOOL final
)
1220 uschar
* hdr
; int hdr_size
= 0, hdr_len
= 0;
1221 uschar
* canon_all
; int can_size
= 0, can_len
= 0;
1223 canon_all
= string_cat (NULL
, &can_size
, &can_len
,
1224 pdkim_canons
[sig
->canon_headers
]);
1225 canon_all
= string_catn(canon_all
, &can_size
, &can_len
, US
"/", 1);
1226 canon_all
= string_cat (canon_all
, &can_size
, &can_len
,
1227 pdkim_canons
[sig
->canon_body
]);
1228 canon_all
[can_len
] = '\0';
1230 hdr
= string_cat(NULL
, &hdr_size
, &hdr_len
,
1231 US
"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION
);
1234 /* Required and static bits */
1235 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"a=",
1236 pdkim_algos
[sig
->algo
]);
1237 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"q=",
1238 pdkim_querymethods
[sig
->querymethod
]);
1239 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"c=",
1241 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"d=",
1243 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"s=",
1246 /* list of header names can be split between items. */
1248 uschar
* n
= string_copy(sig
->headernames
);
1249 uschar
* i
= US
"h=";
1254 uschar
* c
= Ustrchr(n
, ':');
1259 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, NULL
, NULL
, US
":");
1261 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, s
, i
, n
);
1272 base64_bh
= pdkim_encode_base64(&sig
->bodyhash
);
1273 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"bh=", base64_bh
);
1277 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"i=", sig
->identity
);
1279 if (sig
->created
> 0)
1283 snprintf(CS minibuf
, sizeof(minibuf
), "%lu", sig
->created
);
1284 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"t=", minibuf
);
1287 if (sig
->expires
> 0)
1291 snprintf(CS minibuf
, sizeof(minibuf
), "%lu", sig
->expires
);
1292 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"x=", minibuf
);
1295 if (sig
->bodylength
>= 0)
1299 snprintf(CS minibuf
, sizeof(minibuf
), "%lu", sig
->bodylength
);
1300 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"l=", minibuf
);
1303 /* Preliminary or final version? */
1304 base64_b
= final
? pdkim_encode_base64(&sig
->sighash
) : US
"";
1305 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"b=", base64_b
);
1307 /* add trailing semicolon: I'm not sure if this is actually needed */
1308 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, NULL
, US
";", US
"");
1310 hdr
[hdr_len
] = '\0';
1315 /* -------------------------------------------------------------------------- */
1317 static pdkim_pubkey
*
1318 pdkim_key_from_dns(pdkim_ctx
* ctx
, pdkim_signature
* sig
, ev_ctx
* vctx
)
1320 uschar
* dns_txt_name
, * dns_txt_reply
;
1322 const uschar
* errstr
;
1324 /* Fetch public key for signing domain, from DNS */
1326 dns_txt_name
= string_sprintf("%s._domainkey.%s.", sig
->selector
, sig
->domain
);
1328 dns_txt_reply
= store_get(PDKIM_DNS_TXT_MAX_RECLEN
);
1329 memset(dns_txt_reply
, 0, PDKIM_DNS_TXT_MAX_RECLEN
);
1331 if ( ctx
->dns_txt_callback(CS dns_txt_name
, CS dns_txt_reply
) != PDKIM_OK
1332 || dns_txt_reply
[0] == '\0'
1335 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1336 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE
;
1343 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1345 pdkim_quoteprint(CUS dns_txt_reply
, Ustrlen(dns_txt_reply
));
1348 if ( !(p
= pdkim_parse_pubkey_record(ctx
, CUS dns_txt_reply
))
1349 || (Ustrcmp(p
->srvtype
, "*") != 0 && Ustrcmp(p
->srvtype
, "email") != 0)
1352 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1353 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD
;
1358 debug_printf(" Invalid public key service type '%s'\n", p
->srvtype
);
1360 debug_printf(" Error while parsing public key record\n");
1362 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1367 DEBUG(D_acl
) debug_printf(
1368 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1370 /* Import public key */
1371 if ((errstr
= exim_rsa_verify_init(&p
->key
, vctx
)))
1373 DEBUG(D_acl
) debug_printf("verify_init: %s\n", errstr
);
1374 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1375 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_PUBKEY_IMPORT
;
1383 /* -------------------------------------------------------------------------- */
1386 pdkim_feed_finish(pdkim_ctx
*ctx
, pdkim_signature
**return_signatures
)
1388 pdkim_signature
*sig
= ctx
->sig
;
1390 /* Check if we must still flush a (partial) header. If that is the
1391 case, the message has no body, and we must compute a body hash
1392 out of '<CR><LF>' */
1393 if (ctx
->cur_header
&& ctx
->cur_header_len
)
1395 int rc
= pdkim_header_complete(ctx
);
1396 if (rc
!= PDKIM_OK
) return rc
;
1397 pdkim_update_bodyhash(ctx
, "\r\n", 2);
1400 DEBUG(D_acl
) debug_printf(
1401 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1403 /* Build (and/or evaluate) body hash */
1404 pdkim_finish_bodyhash(ctx
);
1408 BOOL is_sha1
= sig
->algo
== PDKIM_ALGO_RSA_SHA1
;
1410 uschar
* sig_hdr
= US
"";
1413 int hdata_alloc
= 0;
1418 if (!exim_sha_init(&hhash_ctx
, is_sha1
? HASH_SHA1
: HASH_SHA256
))
1420 DEBUG(D_acl
) debug_printf("PDKIM: hask setup internal error\n");
1424 DEBUG(D_acl
) debug_printf(
1425 "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>>>\n");
1427 /* SIGNING ---------------------------------------------------------------- */
1428 /* When signing, walk through our header list and add them to the hash. As we
1429 go, construct a list of the header's names to use for the h= parameter.
1430 Then append to that list any remaining header names for which there was no
1433 if (ctx
->flags
& PDKIM_MODE_SIGN
)
1435 uschar
* headernames
= NULL
; /* Collected signed header names */
1437 pdkim_stringlist
*p
;
1442 for (p
= sig
->headers
; p
; p
= p
->next
)
1443 if (header_name_match(p
->value
, sig
->sign_headers
) == PDKIM_OK
)
1446 /* Collect header names (Note: colon presence is guaranteed here) */
1447 uschar
* q
= Ustrchr(p
->value
, ':');
1449 headernames
= string_catn(headernames
, &hs
, &hl
,
1450 p
->value
, (q
- US p
->value
) + (p
->next
? 1 : 0));
1452 rh
= sig
->canon_headers
== PDKIM_CANON_RELAXED
1453 ? pdkim_relax_header(p
->value
, 1) /* cook header for relaxed canon */
1454 : string_copy(CUS p
->value
); /* just copy it for simple canon */
1456 /* Feed header to the hash algorithm */
1457 exim_sha_update(&hhash_ctx
, CUS rh
, Ustrlen(rh
));
1459 /* Remember headers block for signing (when the library cannot do incremental) */
1460 (void) exim_rsa_data_append(&hdata
, &hdata_alloc
, rh
);
1462 DEBUG(D_acl
) pdkim_quoteprint(rh
, Ustrlen(rh
));
1465 l
= sig
->sign_headers
;
1466 while((s
= string_nextinlist(&l
, &sep
, NULL
, 0)))
1468 { /*SSS string_append_listele() */
1469 if (hl
> 0 && headernames
[hl
-1] != ':')
1470 headernames
= string_catn(headernames
, &hs
, &hl
, US
":", 1);
1472 headernames
= string_cat(headernames
, &hs
, &hl
, s
);
1474 headernames
[hl
] = '\0';
1476 /* Copy headernames to signature struct */
1477 sig
->headernames
= headernames
;
1479 /* Create signature header with b= omitted */
1480 sig_hdr
= pdkim_create_header(sig
, FALSE
);
1483 /* VERIFICATION ----------------------------------------------------------- */
1484 /* When verifying, walk through the header name list in the h= parameter and
1485 add the headers to the hash in that order. */
1488 uschar
* p
= sig
->headernames
;
1490 pdkim_stringlist
* hdrs
;
1495 for (hdrs
= ctx
->headers
; hdrs
; hdrs
= hdrs
->next
)
1501 if ((q
= Ustrchr(p
, ':')))
1504 /*XXX walk the list of headers in same order as received. */
1505 for (hdrs
= ctx
->headers
; hdrs
; hdrs
= hdrs
->next
)
1507 && strncasecmp(CCS hdrs
->value
, CCS p
, Ustrlen(p
)) == 0
1508 && (hdrs
->value
)[Ustrlen(p
)] == ':'
1511 /* cook header for relaxed canon, or just copy it for simple */
1513 uschar
* rh
= sig
->canon_headers
== PDKIM_CANON_RELAXED
1514 ? pdkim_relax_header(hdrs
->value
, 1)
1515 : string_copy(CUS hdrs
->value
);
1517 /* Feed header to the hash algorithm */
1518 exim_sha_update(&hhash_ctx
, CUS rh
, Ustrlen(rh
));
1520 DEBUG(D_acl
) pdkim_quoteprint(rh
, Ustrlen(rh
));
1529 sig_hdr
= string_copy(sig
->rawsig_no_b_val
);
1533 DEBUG(D_acl
) debug_printf(
1534 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1536 /* Relax header if necessary */
1537 if (sig
->canon_headers
== PDKIM_CANON_RELAXED
)
1538 sig_hdr
= pdkim_relax_header(sig_hdr
, 0);
1543 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
1544 pdkim_quoteprint(CUS sig_hdr
, Ustrlen(sig_hdr
));
1546 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1549 /* Finalize header hash */
1550 exim_sha_update(&hhash_ctx
, CUS sig_hdr
, Ustrlen(sig_hdr
));
1551 exim_sha_finish(&hhash_ctx
, &hhash
);
1555 debug_printf("PDKIM [%s] Header hash computed: ", sig
->domain
);
1556 pdkim_hexprint(hhash
.data
, hhash
.len
);
1559 /* Remember headers block for signing (when the library cannot do incremental) */
1560 if (ctx
->flags
& PDKIM_MODE_SIGN
)
1561 (void) exim_rsa_data_append(&hdata
, &hdata_alloc
, US sig_hdr
);
1563 /* SIGNING ---------------------------------------------------------------- */
1564 if (ctx
->flags
& PDKIM_MODE_SIGN
)
1567 const uschar
* errstr
;
1569 /* Import private key */
1570 if ((errstr
= exim_rsa_signing_init(US sig
->rsa_privkey
, &sctx
)))
1572 DEBUG(D_acl
) debug_printf("signing_init: %s\n", errstr
);
1573 return PDKIM_ERR_RSA_PRIVKEY
;
1576 /* Do signing. With OpenSSL we are signing the hash of headers just
1577 calculated, with GnuTLS we have to sign an entire block of headers
1578 (due to available interfaces) and it recalculates the hash internally. */
1580 #if defined(RSA_OPENSSL) || defined(RSA_GCRYPT)
1584 if ((errstr
= exim_rsa_sign(&sctx
, is_sha1
, &hdata
, &sig
->sighash
)))
1586 DEBUG(D_acl
) debug_printf("signing: %s\n", errstr
);
1587 return PDKIM_ERR_RSA_SIGNING
;
1592 debug_printf( "PDKIM [%s] b computed: ", sig
->domain
);
1593 pdkim_hexprint(sig
->sighash
.data
, sig
->sighash
.len
);
1596 sig
->signature_header
= pdkim_create_header(sig
, TRUE
);
1599 /* VERIFICATION ----------------------------------------------------------- */
1603 const uschar
* errstr
;
1606 /* Make sure we have all required signature tags */
1607 if (!( sig
->domain
&& *sig
->domain
1608 && sig
->selector
&& *sig
->selector
1609 && sig
->headernames
&& *sig
->headernames
1610 && sig
->bodyhash
.data
1611 && sig
->sighash
.data
1616 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1617 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_SIGNATURE_ERROR
;
1619 DEBUG(D_acl
) debug_printf(
1620 " Error in DKIM-Signature header: tags missing or invalid\n"
1621 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1625 /* Make sure sig uses supported DKIM version (only v1) */
1626 if (sig
->version
!= 1)
1628 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1629 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_DKIM_VERSION
;
1631 DEBUG(D_acl
) debug_printf(
1632 " Error in DKIM-Signature header: unsupported DKIM version\n"
1633 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1637 if (!(sig
->pubkey
= pdkim_key_from_dns(ctx
, sig
, &vctx
)))
1640 /* Check the signature */
1641 if ((errstr
= exim_rsa_verify(&vctx
, is_sha1
, &hhash
, &sig
->sighash
)))
1643 DEBUG(D_acl
) debug_printf("headers verify: %s\n", errstr
);
1644 sig
->verify_status
= PDKIM_VERIFY_FAIL
;
1645 sig
->verify_ext_status
= PDKIM_VERIFY_FAIL_MESSAGE
;
1650 /* We have a winner! (if bodyhash was correct earlier) */
1651 if (sig
->verify_status
== PDKIM_VERIFY_NONE
)
1652 sig
->verify_status
= PDKIM_VERIFY_PASS
;
1658 debug_printf("PDKIM [%s] signature status: %s",
1659 sig
->domain
, pdkim_verify_status_str(sig
->verify_status
));
1660 if (sig
->verify_ext_status
> 0)
1661 debug_printf(" (%s)\n",
1662 pdkim_verify_ext_status_str(sig
->verify_ext_status
));
1671 /* If requested, set return pointer to signature(s) */
1672 if (return_signatures
)
1673 *return_signatures
= ctx
->sig
;
1679 /* -------------------------------------------------------------------------- */
1681 DLLEXPORT pdkim_ctx
*
1682 pdkim_init_verify(int(*dns_txt_callback
)(char *, char *), BOOL dot_stuffing
)
1686 ctx
= store_get(sizeof(pdkim_ctx
));
1687 memset(ctx
, 0, sizeof(pdkim_ctx
));
1689 if (dot_stuffing
) ctx
->flags
= PDKIM_DOT_TERM
;
1690 ctx
->linebuf
= store_get(PDKIM_MAX_BODY_LINE_LEN
);
1691 ctx
->dns_txt_callback
= dns_txt_callback
;
1697 /* -------------------------------------------------------------------------- */
1699 DLLEXPORT pdkim_ctx
*
1700 pdkim_init_sign(char * domain
, char * selector
, char * rsa_privkey
, int algo
,
1701 BOOL dot_stuffed
, int(*dns_txt_callback
)(char *, char *))
1704 pdkim_signature
* sig
;
1706 if (!domain
|| !selector
|| !rsa_privkey
)
1709 ctx
= store_get(sizeof(pdkim_ctx
) + PDKIM_MAX_BODY_LINE_LEN
+ sizeof(pdkim_signature
));
1710 memset(ctx
, 0, sizeof(pdkim_ctx
));
1712 ctx
->flags
= dot_stuffed
? PDKIM_MODE_SIGN
| PDKIM_DOT_TERM
: PDKIM_MODE_SIGN
;
1713 ctx
->linebuf
= CS (ctx
+1);
1715 DEBUG(D_acl
) ctx
->dns_txt_callback
= dns_txt_callback
;
1717 sig
= (pdkim_signature
*)(ctx
->linebuf
+ PDKIM_MAX_BODY_LINE_LEN
);
1718 memset(sig
, 0, sizeof(pdkim_signature
));
1720 sig
->bodylength
= -1;
1723 sig
->domain
= string_copy(US domain
);
1724 sig
->selector
= string_copy(US selector
);
1725 sig
->rsa_privkey
= string_copy(US rsa_privkey
);
1728 if (!exim_sha_init(&sig
->body_hash_ctx
,
1729 algo
== PDKIM_ALGO_RSA_SHA1
? HASH_SHA1
: HASH_SHA256
))
1731 DEBUG(D_acl
) debug_printf("PDKIM: hash setup internal error\n");
1737 pdkim_signature s
= *sig
;
1740 debug_printf("PDKIM (checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1741 if (!pdkim_key_from_dns(ctx
, &s
, &vctx
))
1742 debug_printf("WARNING: bad dkim key in dns\n");
1743 debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1749 /* -------------------------------------------------------------------------- */
1752 pdkim_set_optional(pdkim_ctx
*ctx
,
1758 unsigned long created
,
1759 unsigned long expires
)
1761 pdkim_signature
* sig
= ctx
->sig
;
1764 sig
->identity
= string_copy(US identity
);
1766 sig
->sign_headers
= string_copy(sign_headers
1767 ? US sign_headers
: US PDKIM_DEFAULT_SIGN_HEADERS
);
1769 sig
->canon_headers
= canon_headers
;
1770 sig
->canon_body
= canon_body
;
1771 sig
->bodylength
= bodylength
;
1772 sig
->created
= created
;
1773 sig
->expires
= expires
;
1787 #endif /*DISABLE_DKIM*/