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 pdkim_decode_base64(cur_val
,
497 cur_tag
[1] == 'h' ? &sig
->bodyhash
: &sig
->sighash
);
500 /* We only support version 1, and that is currently the
501 only version there is. */
503 Ustrcmp(cur_val
, PDKIM_SIGNATURE_VERSION
) == 0 ? 1 : -1;
506 for (i
= 0; pdkim_algos
[i
]; i
++)
507 if (Ustrcmp(cur_val
, pdkim_algos
[i
]) == 0)
514 for (i
= 0; pdkim_combined_canons
[i
].str
; i
++)
515 if (Ustrcmp(cur_val
, pdkim_combined_canons
[i
].str
) == 0)
517 sig
->canon_headers
= pdkim_combined_canons
[i
].canon_headers
;
518 sig
->canon_body
= pdkim_combined_canons
[i
].canon_body
;
523 for (i
= 0; pdkim_querymethods
[i
]; i
++)
524 if (Ustrcmp(cur_val
, pdkim_querymethods
[i
]) == 0)
526 sig
->querymethod
= i
;
531 sig
->selector
= string_copy(cur_val
); break;
533 sig
->domain
= string_copy(cur_val
); break;
535 sig
->identity
= pdkim_decode_qp(cur_val
); break;
537 sig
->created
= strtoul(CS cur_val
, NULL
, 10); break;
539 sig
->expires
= strtoul(CS cur_val
, NULL
, 10); break;
541 sig
->bodylength
= strtol(CS cur_val
, NULL
, 10); break;
543 sig
->headernames
= string_copy(cur_val
); break;
545 sig
->copiedheaders
= pdkim_decode_qp(cur_val
); break;
547 DEBUG(D_acl
) debug_printf(" Unknown tag encountered\n");
554 where
= PDKIM_HDR_LIMBO
;
557 cur_val
= string_catn(cur_val
, &vs
, &vl
, p
, 1);
569 /* Chomp raw header. The final newline must not be added to the signature. */
570 while (--q
> sig
->rawsig_no_b_val
&& (*q
== '\r' || *q
== '\n'))
576 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
577 pdkim_quoteprint(US sig
->rawsig_no_b_val
, Ustrlen(sig
->rawsig_no_b_val
));
579 "PDKIM >> Sig size: %4u bits\n", (unsigned) sig
->sighash
.len
*8);
581 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
584 exim_sha_init(&sig
->body_hash_ctx
,
585 sig
->algo
== PDKIM_ALGO_RSA_SHA1
? HASH_SHA1
: HASH_SHA256
);
590 /* -------------------------------------------------------------------------- */
592 static pdkim_pubkey
*
593 pdkim_parse_pubkey_record(pdkim_ctx
*ctx
, const uschar
*raw_record
)
597 uschar
* cur_tag
= NULL
; int ts
= 0, tl
= 0;
598 uschar
* cur_val
= NULL
; int vs
= 0, vl
= 0;
599 int where
= PDKIM_HDR_LIMBO
;
601 pub
= store_get(sizeof(pdkim_pubkey
));
602 memset(pub
, 0, sizeof(pdkim_pubkey
));
604 for (p
= raw_record
; ; p
++)
609 if (c
!= '\r' && c
!= '\n') switch (where
)
611 case PDKIM_HDR_LIMBO
: /* In limbo, just wait for a tag-char to appear */
612 if (!(c
>= 'a' && c
<= 'z'))
614 where
= PDKIM_HDR_TAG
;
618 if (c
>= 'a' && c
<= 'z')
619 cur_tag
= string_catn(cur_tag
, &ts
, &tl
, p
, 1);
624 where
= PDKIM_HDR_VALUE
;
628 case PDKIM_HDR_VALUE
:
629 if (c
== ';' || c
== '\0')
634 pdkim_strtrim(cur_val
);
635 DEBUG(D_acl
) debug_printf(" %s=%s\n", cur_tag
, cur_val
);
640 pub
->version
= string_copy(cur_val
); break;
643 /* This field appears to never be used. Also, unclear why
644 a 'k' (key-type_ would go in this field name. There is a field
645 "keytype", also never used.
646 pub->hashes = string_copy(cur_val);
650 pub
->granularity
= string_copy(cur_val
); break;
652 pub
->notes
= pdkim_decode_qp(cur_val
); break;
654 pdkim_decode_base64(US cur_val
, &pub
->key
); break;
656 pub
->srvtype
= string_copy(cur_val
); break;
658 if (Ustrchr(cur_val
, 'y') != NULL
) pub
->testing
= 1;
659 if (Ustrchr(cur_val
, 's') != NULL
) pub
->no_subdomaining
= 1;
662 DEBUG(D_acl
) debug_printf(" Unknown tag encountered\n");
668 where
= PDKIM_HDR_LIMBO
;
671 cur_val
= string_catn(cur_val
, &vs
, &vl
, p
, 1);
675 if (c
== '\0') break;
678 /* Set fallback defaults */
679 if (!pub
->version
) pub
->version
= string_copy(PDKIM_PUB_RECORD_VERSION
);
680 else if (Ustrcmp(pub
->version
, PDKIM_PUB_RECORD_VERSION
) != 0) return NULL
;
682 if (!pub
->granularity
) pub
->granularity
= string_copy(US
"*");
684 if (!pub->keytype ) pub->keytype = string_copy(US"rsa");
686 if (!pub
->srvtype
) pub
->srvtype
= string_copy(US
"*");
696 /* -------------------------------------------------------------------------- */
699 pdkim_update_bodyhash(pdkim_ctx
* ctx
, const char * data
, int len
)
701 pdkim_signature
* sig
;
702 uschar
* relaxed_data
= NULL
; /* Cache relaxed version of data */
705 /* Traverse all signatures, updating their hashes. */
706 for (sig
= ctx
->sig
; sig
; sig
= sig
->next
)
708 /* Defaults to simple canon (no further treatment necessary) */
709 const uschar
*canon_data
= CUS data
;
712 if (sig
->canon_body
== PDKIM_CANON_RELAXED
)
714 /* Relax the line if not done already */
717 BOOL seen_wsp
= FALSE
;
721 /* We want to be able to free this else we allocate
722 for the entire message which could be many MB. Since
723 we don't know what allocations the SHA routines might
724 do, not safe to use store_get()/store_reset(). */
726 relaxed_data
= store_malloc(len
+1);
728 for (p
= data
; *p
; p
++)
733 if (q
> 0 && relaxed_data
[q
-1] == ' ')
736 else if (c
== '\t' || c
== ' ')
738 c
= ' '; /* Turns WSP into SP */
745 relaxed_data
[q
++] = c
;
747 relaxed_data
[q
] = '\0';
750 canon_data
= relaxed_data
;
751 canon_len
= relaxed_len
;
754 /* Make sure we don't exceed the to-be-signed body length */
755 if ( sig
->bodylength
>= 0
756 && sig
->signed_body_bytes
+ (unsigned long)canon_len
> sig
->bodylength
758 canon_len
= sig
->bodylength
- sig
->signed_body_bytes
;
762 exim_sha_update(&sig
->body_hash_ctx
, CUS canon_data
, canon_len
);
763 sig
->signed_body_bytes
+= canon_len
;
764 DEBUG(D_acl
) pdkim_quoteprint(canon_data
, canon_len
);
768 if (relaxed_data
) store_free(relaxed_data
);
773 /* -------------------------------------------------------------------------- */
776 pdkim_finish_bodyhash(pdkim_ctx
*ctx
)
778 pdkim_signature
*sig
;
780 /* Traverse all signatures */
781 for (sig
= ctx
->sig
; sig
; sig
= sig
->next
)
782 { /* Finish hashes */
785 exim_sha_finish(&sig
->body_hash_ctx
, &bh
);
789 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
790 "PDKIM [%s] Body hash computed: ",
791 sig
->domain
, sig
->signed_body_bytes
, sig
->domain
);
792 pdkim_hexprint(CUS bh
.data
, bh
.len
);
795 /* SIGNING -------------------------------------------------------------- */
796 if (ctx
->flags
& PDKIM_MODE_SIGN
)
800 /* If bodylength limit is set, and we have received less bytes
801 than the requested amount, effectively remove the limit tag. */
802 if (sig
->signed_body_bytes
< sig
->bodylength
)
803 sig
->bodylength
= -1;
806 /* VERIFICATION --------------------------------------------------------- */
809 /* Compare bodyhash */
810 if (memcmp(bh
.data
, sig
->bodyhash
.data
, bh
.len
) == 0)
812 DEBUG(D_acl
) debug_printf("PDKIM [%s] Body hash verified OK\n", sig
->domain
);
818 debug_printf("PDKIM [%s] Body hash signature from headers: ", sig
->domain
);
819 pdkim_hexprint(sig
->bodyhash
.data
, sig
->bodyhash
.len
);
820 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig
->domain
);
822 sig
->verify_status
= PDKIM_VERIFY_FAIL
;
823 sig
->verify_ext_status
= PDKIM_VERIFY_FAIL_BODY
;
831 pdkim_body_complete(pdkim_ctx
* ctx
)
833 pdkim_signature
* sig
= ctx
->sig
; /*XXX assumes only one sig */
835 /* In simple body mode, if any empty lines were buffered,
836 replace with one. rfc 4871 3.4.3 */
837 /*XXX checking the signed-body-bytes is a gross hack; I think
838 it indicates that all linebreaks should be buffered, including
839 the one terminating a text line */
841 if ( sig
&& sig
->canon_body
== PDKIM_CANON_SIMPLE
842 && sig
->signed_body_bytes
== 0
843 && ctx
->num_buffered_crlf
> 0
845 pdkim_update_bodyhash(ctx
, "\r\n", 2);
847 ctx
->flags
|= PDKIM_SEEN_EOD
;
848 ctx
->linebuf_offset
= 0;
854 /* -------------------------------------------------------------------------- */
855 /* Call from pdkim_feed below for processing complete body lines */
858 pdkim_bodyline_complete(pdkim_ctx
*ctx
)
860 char *p
= ctx
->linebuf
;
861 int n
= ctx
->linebuf_offset
;
862 pdkim_signature
*sig
= ctx
->sig
; /*XXX assumes only one sig */
864 /* Ignore extra data if we've seen the end-of-data marker */
865 if (ctx
->flags
& PDKIM_SEEN_EOD
) goto BAIL
;
867 /* We've always got one extra byte to stuff a zero ... */
868 ctx
->linebuf
[ctx
->linebuf_offset
] = '\0';
870 /* Terminate on EOD marker */
871 if (ctx
->flags
& PDKIM_DOT_TERM
)
873 if (memcmp(p
, ".\r\n", 3) == 0)
874 return pdkim_body_complete(ctx
);
877 if (memcmp(p
, "..", 2) == 0)
884 /* Empty lines need to be buffered until we find a non-empty line */
885 if (memcmp(p
, "\r\n", 2) == 0)
887 ctx
->num_buffered_crlf
++;
891 if (sig
&& sig
->canon_body
== PDKIM_CANON_RELAXED
)
893 /* Lines with just spaces need to be buffered too */
895 while (memcmp(check
, "\r\n", 2) != 0)
899 if (c
!= '\t' && c
!= ' ')
904 ctx
->num_buffered_crlf
++;
909 /* At this point, we have a non-empty line, so release the buffered ones. */
910 while (ctx
->num_buffered_crlf
)
912 pdkim_update_bodyhash(ctx
, "\r\n", 2);
913 ctx
->num_buffered_crlf
--;
916 pdkim_update_bodyhash(ctx
, p
, n
);
919 ctx
->linebuf_offset
= 0;
924 /* -------------------------------------------------------------------------- */
925 /* Callback from pdkim_feed below for processing complete headers */
926 #define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
929 pdkim_header_complete(pdkim_ctx
*ctx
)
931 /* Special case: The last header can have an extra \r appended */
932 if ( (ctx
->cur_header_len
> 1) &&
933 (ctx
->cur_header
[(ctx
->cur_header_len
)-1] == '\r') )
934 --ctx
->cur_header_len
;
935 ctx
->cur_header
[ctx
->cur_header_len
] = '\0';
938 if (ctx
->num_headers
> PDKIM_MAX_HEADERS
) goto BAIL
;
940 /* SIGNING -------------------------------------------------------------- */
941 if (ctx
->flags
& PDKIM_MODE_SIGN
)
943 pdkim_signature
*sig
;
945 for (sig
= ctx
->sig
; sig
; sig
= sig
->next
) /* Traverse all signatures */
947 /* Add header to the signed headers list (in reverse order) */
948 sig
->headers
= pdkim_prepend_stringlist(sig
->headers
,
952 /* VERIFICATION ----------------------------------------------------------- */
953 /* DKIM-Signature: headers are added to the verification list */
958 debug_printf("PDKIM >> raw hdr: ");
959 pdkim_quoteprint(CUS ctx
->cur_header
, Ustrlen(ctx
->cur_header
));
961 if (strncasecmp(CCS ctx
->cur_header
,
962 DKIM_SIGNATURE_HEADERNAME
,
963 Ustrlen(DKIM_SIGNATURE_HEADERNAME
)) == 0)
965 pdkim_signature
*new_sig
;
967 /* Create and chain new signature block */
968 DEBUG(D_acl
) debug_printf(
969 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
971 if ((new_sig
= pdkim_parse_sig_header(ctx
, ctx
->cur_header
)))
973 pdkim_signature
*last_sig
= ctx
->sig
;
978 while (last_sig
->next
) last_sig
= last_sig
->next
;
979 last_sig
->next
= new_sig
;
983 DEBUG(D_acl
) debug_printf(
984 "Error while parsing signature header\n"
985 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
988 /* all headers are stored for signature verification */
989 ctx
->headers
= pdkim_prepend_stringlist(ctx
->headers
, ctx
->cur_header
);
993 *ctx
->cur_header
= '\0';
994 ctx
->cur_header_len
= 0; /* leave buffer for reuse */
1000 /* -------------------------------------------------------------------------- */
1001 #define HEADER_BUFFER_FRAG_SIZE 256
1004 pdkim_feed(pdkim_ctx
*ctx
, char *data
, int len
)
1008 /* Alternate EOD signal, used in non-dotstuffing mode */
1010 pdkim_body_complete(ctx
);
1012 else for (p
= 0; p
<len
; p
++)
1016 if (ctx
->flags
& PDKIM_PAST_HDRS
)
1018 if (c
== '\n' && !(ctx
->flags
& PDKIM_SEEN_CR
)) /* emulate the CR */
1020 ctx
->linebuf
[ctx
->linebuf_offset
++] = '\r';
1021 if (ctx
->linebuf_offset
== PDKIM_MAX_BODY_LINE_LEN
-1)
1022 return PDKIM_ERR_LONG_LINE
;
1025 /* Processing body byte */
1026 ctx
->linebuf
[ctx
->linebuf_offset
++] = c
;
1028 ctx
->flags
|= PDKIM_SEEN_CR
;
1032 ctx
->flags
&= ~PDKIM_SEEN_CR
;
1033 if ((rc
= pdkim_bodyline_complete(ctx
)) != PDKIM_OK
)
1037 if (ctx
->linebuf_offset
== PDKIM_MAX_BODY_LINE_LEN
-1)
1038 return PDKIM_ERR_LONG_LINE
;
1042 /* Processing header byte */
1044 ctx
->flags
|= PDKIM_SEEN_CR
;
1047 if (!(ctx
->flags
& PDKIM_SEEN_CR
)) /* emulate the CR */
1048 ctx
->cur_header
= string_catn(ctx
->cur_header
, &ctx
->cur_header_size
,
1049 &ctx
->cur_header_len
, CUS
"\r", 1);
1051 if (ctx
->flags
& PDKIM_SEEN_LF
)
1053 int rc
= pdkim_header_complete(ctx
); /* Seen last header line */
1054 if (rc
!= PDKIM_OK
) return rc
;
1056 ctx
->flags
= ctx
->flags
& ~(PDKIM_SEEN_LF
|PDKIM_SEEN_CR
) | PDKIM_PAST_HDRS
;
1057 DEBUG(D_acl
) debug_printf(
1058 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>\n");
1062 ctx
->flags
= ctx
->flags
& ~PDKIM_SEEN_CR
| PDKIM_SEEN_LF
;
1064 else if (ctx
->flags
& PDKIM_SEEN_LF
)
1066 if (!(c
== '\t' || c
== ' '))
1068 int rc
= pdkim_header_complete(ctx
); /* End of header */
1069 if (rc
!= PDKIM_OK
) return rc
;
1071 ctx
->flags
&= ~PDKIM_SEEN_LF
;
1074 if (ctx
->cur_header_len
< PDKIM_MAX_HEADER_LEN
)
1075 ctx
->cur_header
= string_catn(ctx
->cur_header
, &ctx
->cur_header_size
,
1076 &ctx
->cur_header_len
, CUS
&data
[p
], 1);
1084 /* Extend a grwong header with a continuation-linebreak */
1086 pdkim_hdr_cont(uschar
* str
, int * size
, int * ptr
, int * col
)
1089 return string_catn(str
, size
, ptr
, US
"\r\n\t", 3);
1095 * RFC 5322 specifies that header line length SHOULD be no more than 78
1099 * returns uschar * (not nul-terminated)
1101 * col: this int holds and receives column number (octets since last '\n')
1102 * str: partial string to append to
1103 * size: current buffer size for str
1104 * ptr: current tail-pointer for str
1105 * pad: padding, split line or space after before or after eg: ";"
1106 * intro: - must join to payload eg "h=", usually the tag name
1107 * payload: eg base64 data - long data can be split arbitrarily.
1109 * this code doesn't fold the header in some of the places that RFC4871
1110 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1111 * pairs and inside long values. it also always spaces or breaks after the
1114 * no guarantees are made for output given out-of range input. like tag
1115 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
1119 pdkim_headcat(int * col
, uschar
* str
, int * size
, int * ptr
,
1120 const uschar
* pad
, const uschar
* intro
, const uschar
* payload
)
1128 str
= pdkim_hdr_cont(str
, size
, ptr
, col
);
1129 str
= string_catn(str
, size
, ptr
, pad
, l
);
1133 l
= (pad
?1:0) + (intro
?Ustrlen(intro
):0);
1136 { /*can't fit intro - start a new line to make room.*/
1137 str
= pdkim_hdr_cont(str
, size
, ptr
, col
);
1138 l
= intro
?Ustrlen(intro
):0;
1141 l
+= payload
? Ustrlen(payload
):0 ;
1144 { /* this fragment will not fit on a single line */
1147 str
= string_catn(str
, size
, ptr
, US
" ", 1);
1149 pad
= NULL
; /* only want this once */
1155 size_t sl
= Ustrlen(intro
);
1157 str
= string_catn(str
, size
, ptr
, intro
, sl
);
1160 intro
= NULL
; /* only want this once */
1165 size_t sl
= Ustrlen(payload
);
1166 size_t chomp
= *col
+sl
< 77 ? sl
: 78-*col
;
1168 str
= string_catn(str
, size
, ptr
, payload
, chomp
);
1174 /* the while precondition tells us it didn't fit. */
1175 str
= pdkim_hdr_cont(str
, size
, ptr
, col
);
1180 str
= pdkim_hdr_cont(str
, size
, ptr
, col
);
1186 str
= string_catn(str
, size
, ptr
, US
" ", 1);
1193 size_t sl
= Ustrlen(intro
);
1195 str
= string_catn(str
, size
, ptr
, intro
, sl
);
1203 size_t sl
= Ustrlen(payload
);
1205 str
= string_catn(str
, size
, ptr
, payload
, sl
);
1213 /* -------------------------------------------------------------------------- */
1216 pdkim_create_header(pdkim_signature
*sig
, BOOL final
)
1221 uschar
* hdr
; int hdr_size
= 0, hdr_len
= 0;
1222 uschar
* canon_all
; int can_size
= 0, can_len
= 0;
1224 canon_all
= string_cat (NULL
, &can_size
, &can_len
,
1225 pdkim_canons
[sig
->canon_headers
]);
1226 canon_all
= string_catn(canon_all
, &can_size
, &can_len
, US
"/", 1);
1227 canon_all
= string_cat (canon_all
, &can_size
, &can_len
,
1228 pdkim_canons
[sig
->canon_body
]);
1229 canon_all
[can_len
] = '\0';
1231 hdr
= string_cat(NULL
, &hdr_size
, &hdr_len
,
1232 US
"DKIM-Signature: v="PDKIM_SIGNATURE_VERSION
);
1235 /* Required and static bits */
1236 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"a=",
1237 pdkim_algos
[sig
->algo
]);
1238 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"q=",
1239 pdkim_querymethods
[sig
->querymethod
]);
1240 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"c=",
1242 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"d=",
1244 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"s=",
1247 /* list of header names can be split between items. */
1249 uschar
* n
= string_copy(sig
->headernames
);
1250 uschar
* i
= US
"h=";
1255 uschar
* c
= Ustrchr(n
, ':');
1260 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, NULL
, NULL
, US
":");
1262 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, s
, i
, n
);
1273 base64_bh
= pdkim_encode_base64(&sig
->bodyhash
);
1274 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"bh=", base64_bh
);
1278 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"i=", sig
->identity
);
1280 if (sig
->created
> 0)
1284 snprintf(CS minibuf
, sizeof(minibuf
), "%lu", sig
->created
);
1285 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"t=", minibuf
);
1288 if (sig
->expires
> 0)
1292 snprintf(CS minibuf
, sizeof(minibuf
), "%lu", sig
->expires
);
1293 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"x=", minibuf
);
1296 if (sig
->bodylength
>= 0)
1300 snprintf(CS minibuf
, sizeof(minibuf
), "%lu", sig
->bodylength
);
1301 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"l=", minibuf
);
1304 /* Preliminary or final version? */
1305 base64_b
= final
? pdkim_encode_base64(&sig
->sighash
) : US
"";
1306 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, US
";", US
"b=", base64_b
);
1308 /* add trailing semicolon: I'm not sure if this is actually needed */
1309 hdr
= pdkim_headcat(&col
, hdr
, &hdr_size
, &hdr_len
, NULL
, US
";", US
"");
1311 hdr
[hdr_len
] = '\0';
1316 /* -------------------------------------------------------------------------- */
1318 static pdkim_pubkey
*
1319 pdkim_key_from_dns(pdkim_ctx
* ctx
, pdkim_signature
* sig
, ev_ctx
* vctx
)
1321 uschar
* dns_txt_name
, * dns_txt_reply
;
1323 const uschar
* errstr
;
1325 /* Fetch public key for signing domain, from DNS */
1327 dns_txt_name
= string_sprintf("%s._domainkey.%s.", sig
->selector
, sig
->domain
);
1329 dns_txt_reply
= store_get(PDKIM_DNS_TXT_MAX_RECLEN
);
1330 memset(dns_txt_reply
, 0, PDKIM_DNS_TXT_MAX_RECLEN
);
1332 if ( ctx
->dns_txt_callback(CS dns_txt_name
, CS dns_txt_reply
) != PDKIM_OK
1333 || dns_txt_reply
[0] == '\0'
1336 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1337 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE
;
1344 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1346 pdkim_quoteprint(CUS dns_txt_reply
, Ustrlen(dns_txt_reply
));
1349 if ( !(p
= pdkim_parse_pubkey_record(ctx
, CUS dns_txt_reply
))
1350 || (Ustrcmp(p
->srvtype
, "*") != 0 && Ustrcmp(p
->srvtype
, "email") != 0)
1353 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1354 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD
;
1359 debug_printf(" Invalid public key service type '%s'\n", p
->srvtype
);
1361 debug_printf(" Error while parsing public key record\n");
1363 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1368 DEBUG(D_acl
) debug_printf(
1369 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1371 /* Import public key */
1372 if ((errstr
= exim_rsa_verify_init(&p
->key
, vctx
)))
1374 DEBUG(D_acl
) debug_printf("verify_init: %s\n", errstr
);
1375 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1376 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_PUBKEY_IMPORT
;
1384 /* -------------------------------------------------------------------------- */
1387 pdkim_feed_finish(pdkim_ctx
*ctx
, pdkim_signature
**return_signatures
)
1389 pdkim_signature
*sig
= ctx
->sig
;
1391 /* Check if we must still flush a (partial) header. If that is the
1392 case, the message has no body, and we must compute a body hash
1393 out of '<CR><LF>' */
1394 if (ctx
->cur_header
&& ctx
->cur_header_len
)
1396 int rc
= pdkim_header_complete(ctx
);
1397 if (rc
!= PDKIM_OK
) return rc
;
1398 pdkim_update_bodyhash(ctx
, "\r\n", 2);
1401 DEBUG(D_acl
) debug_printf(
1402 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1404 /* Build (and/or evaluate) body hash */
1405 pdkim_finish_bodyhash(ctx
);
1409 BOOL is_sha1
= sig
->algo
== PDKIM_ALGO_RSA_SHA1
;
1411 uschar
* sig_hdr
= US
"";
1414 int hdata_alloc
= 0;
1419 exim_sha_init(&hhash_ctx
, is_sha1
? HASH_SHA1
: HASH_SHA256
);
1421 DEBUG(D_acl
) debug_printf(
1422 "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>>>\n");
1424 /* SIGNING ---------------------------------------------------------------- */
1425 /* When signing, walk through our header list and add them to the hash. As we
1426 go, construct a list of the header's names to use for the h= parameter.
1427 Then append to that list any remaining header names for which there was no
1430 if (ctx
->flags
& PDKIM_MODE_SIGN
)
1432 uschar
* headernames
= NULL
; /* Collected signed header names */
1434 pdkim_stringlist
*p
;
1439 for (p
= sig
->headers
; p
; p
= p
->next
)
1440 if (header_name_match(p
->value
, sig
->sign_headers
) == PDKIM_OK
)
1443 /* Collect header names (Note: colon presence is guaranteed here) */
1444 uschar
* q
= Ustrchr(p
->value
, ':');
1446 headernames
= string_catn(headernames
, &hs
, &hl
,
1447 p
->value
, (q
- US p
->value
) + (p
->next
? 1 : 0));
1449 rh
= sig
->canon_headers
== PDKIM_CANON_RELAXED
1450 ? pdkim_relax_header(p
->value
, 1) /* cook header for relaxed canon */
1451 : string_copy(CUS p
->value
); /* just copy it for simple canon */
1453 /* Feed header to the hash algorithm */
1454 exim_sha_update(&hhash_ctx
, CUS rh
, Ustrlen(rh
));
1456 /* Remember headers block for signing (when the library cannot do incremental) */
1457 (void) exim_rsa_data_append(&hdata
, &hdata_alloc
, rh
);
1459 DEBUG(D_acl
) pdkim_quoteprint(rh
, Ustrlen(rh
));
1462 l
= sig
->sign_headers
;
1463 while((s
= string_nextinlist(&l
, &sep
, NULL
, 0)))
1465 { /*SSS string_append_listele() */
1466 if (hl
> 0 && headernames
[hl
-1] != ':')
1467 headernames
= string_catn(headernames
, &hs
, &hl
, US
":", 1);
1469 headernames
= string_cat(headernames
, &hs
, &hl
, s
);
1471 headernames
[hl
] = '\0';
1473 /* Copy headernames to signature struct */
1474 sig
->headernames
= headernames
;
1476 /* Create signature header with b= omitted */
1477 sig_hdr
= pdkim_create_header(sig
, FALSE
);
1480 /* VERIFICATION ----------------------------------------------------------- */
1481 /* When verifying, walk through the header name list in the h= parameter and
1482 add the headers to the hash in that order. */
1485 uschar
* p
= sig
->headernames
;
1487 pdkim_stringlist
* hdrs
;
1492 for (hdrs
= ctx
->headers
; hdrs
; hdrs
= hdrs
->next
)
1498 if ((q
= Ustrchr(p
, ':')))
1501 /*XXX walk the list of headers in same order as received. */
1502 for (hdrs
= ctx
->headers
; hdrs
; hdrs
= hdrs
->next
)
1504 && strncasecmp(CCS hdrs
->value
, CCS p
, Ustrlen(p
)) == 0
1505 && (hdrs
->value
)[Ustrlen(p
)] == ':'
1508 /* cook header for relaxed canon, or just copy it for simple */
1510 uschar
* rh
= sig
->canon_headers
== PDKIM_CANON_RELAXED
1511 ? pdkim_relax_header(hdrs
->value
, 1)
1512 : string_copy(CUS hdrs
->value
);
1514 /* Feed header to the hash algorithm */
1515 exim_sha_update(&hhash_ctx
, CUS rh
, Ustrlen(rh
));
1517 DEBUG(D_acl
) pdkim_quoteprint(rh
, Ustrlen(rh
));
1526 sig_hdr
= string_copy(sig
->rawsig_no_b_val
);
1530 DEBUG(D_acl
) debug_printf(
1531 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1533 /* Relax header if necessary */
1534 if (sig
->canon_headers
== PDKIM_CANON_RELAXED
)
1535 sig_hdr
= pdkim_relax_header(sig_hdr
, 0);
1540 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
1541 pdkim_quoteprint(CUS sig_hdr
, Ustrlen(sig_hdr
));
1543 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1546 /* Finalize header hash */
1547 exim_sha_update(&hhash_ctx
, CUS sig_hdr
, Ustrlen(sig_hdr
));
1548 exim_sha_finish(&hhash_ctx
, &hhash
);
1552 debug_printf("PDKIM [%s] Header hash computed: ", sig
->domain
);
1553 pdkim_hexprint(hhash
.data
, hhash
.len
);
1556 /* Remember headers block for signing (when the library cannot do incremental) */
1557 if (ctx
->flags
& PDKIM_MODE_SIGN
)
1558 (void) exim_rsa_data_append(&hdata
, &hdata_alloc
, US sig_hdr
);
1560 /* SIGNING ---------------------------------------------------------------- */
1561 if (ctx
->flags
& PDKIM_MODE_SIGN
)
1564 const uschar
* errstr
;
1566 /* Import private key */
1567 if ((errstr
= exim_rsa_signing_init(US sig
->rsa_privkey
, &sctx
)))
1569 DEBUG(D_acl
) debug_printf("signing_init: %s\n", errstr
);
1570 return PDKIM_ERR_RSA_PRIVKEY
;
1573 /* Do signing. With OpenSSL we are signing the hash of headers just
1574 calculated, with GnuTLS we have to sign an entire block of headers
1575 (due to available interfaces) and it recalculates the hash internally. */
1577 #if defined(RSA_OPENSSL) || defined(RSA_GCRYPT)
1581 if ((errstr
= exim_rsa_sign(&sctx
, is_sha1
, &hdata
, &sig
->sighash
)))
1583 DEBUG(D_acl
) debug_printf("signing: %s\n", errstr
);
1584 return PDKIM_ERR_RSA_SIGNING
;
1589 debug_printf( "PDKIM [%s] b computed: ", sig
->domain
);
1590 pdkim_hexprint(sig
->sighash
.data
, sig
->sighash
.len
);
1593 sig
->signature_header
= pdkim_create_header(sig
, TRUE
);
1596 /* VERIFICATION ----------------------------------------------------------- */
1600 const uschar
* errstr
;
1603 /* Make sure we have all required signature tags */
1604 if (!( sig
->domain
&& *sig
->domain
1605 && sig
->selector
&& *sig
->selector
1606 && sig
->headernames
&& *sig
->headernames
1607 && sig
->bodyhash
.data
1608 && sig
->sighash
.data
1613 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1614 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_SIGNATURE_ERROR
;
1616 DEBUG(D_acl
) debug_printf(
1617 " Error in DKIM-Signature header: tags missing or invalid\n"
1618 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1622 /* Make sure sig uses supported DKIM version (only v1) */
1623 if (sig
->version
!= 1)
1625 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1626 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_DKIM_VERSION
;
1628 DEBUG(D_acl
) debug_printf(
1629 " Error in DKIM-Signature header: unsupported DKIM version\n"
1630 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1634 if (!(sig
->pubkey
= pdkim_key_from_dns(ctx
, sig
, &vctx
)))
1637 /* Check the signature */
1638 if ((errstr
= exim_rsa_verify(&vctx
, is_sha1
, &hhash
, &sig
->sighash
)))
1640 DEBUG(D_acl
) debug_printf("headers verify: %s\n", errstr
);
1641 sig
->verify_status
= PDKIM_VERIFY_FAIL
;
1642 sig
->verify_ext_status
= PDKIM_VERIFY_FAIL_MESSAGE
;
1647 /* We have a winner! (if bodyhash was correct earlier) */
1648 if (sig
->verify_status
== PDKIM_VERIFY_NONE
)
1649 sig
->verify_status
= PDKIM_VERIFY_PASS
;
1655 debug_printf("PDKIM [%s] signature status: %s",
1656 sig
->domain
, pdkim_verify_status_str(sig
->verify_status
));
1657 if (sig
->verify_ext_status
> 0)
1658 debug_printf(" (%s)\n",
1659 pdkim_verify_ext_status_str(sig
->verify_ext_status
));
1668 /* If requested, set return pointer to signature(s) */
1669 if (return_signatures
)
1670 *return_signatures
= ctx
->sig
;
1676 /* -------------------------------------------------------------------------- */
1678 DLLEXPORT pdkim_ctx
*
1679 pdkim_init_verify(int(*dns_txt_callback
)(char *, char *), BOOL dot_stuffing
)
1683 ctx
= store_get(sizeof(pdkim_ctx
));
1684 memset(ctx
, 0, sizeof(pdkim_ctx
));
1686 if (dot_stuffing
) ctx
->flags
= PDKIM_DOT_TERM
;
1687 ctx
->linebuf
= store_get(PDKIM_MAX_BODY_LINE_LEN
);
1688 ctx
->dns_txt_callback
= dns_txt_callback
;
1694 /* -------------------------------------------------------------------------- */
1696 DLLEXPORT pdkim_ctx
*
1697 pdkim_init_sign(char * domain
, char * selector
, char * rsa_privkey
, int algo
,
1698 BOOL dot_stuffed
, int(*dns_txt_callback
)(char *, char *))
1701 pdkim_signature
* sig
;
1703 if (!domain
|| !selector
|| !rsa_privkey
)
1706 ctx
= store_get(sizeof(pdkim_ctx
) + PDKIM_MAX_BODY_LINE_LEN
+ sizeof(pdkim_signature
));
1707 memset(ctx
, 0, sizeof(pdkim_ctx
));
1709 ctx
->flags
= dot_stuffed
? PDKIM_MODE_SIGN
| PDKIM_DOT_TERM
: PDKIM_MODE_SIGN
;
1710 ctx
->linebuf
= CS (ctx
+1);
1712 DEBUG(D_acl
) ctx
->dns_txt_callback
= dns_txt_callback
;
1714 sig
= (pdkim_signature
*)(ctx
->linebuf
+ PDKIM_MAX_BODY_LINE_LEN
);
1715 memset(sig
, 0, sizeof(pdkim_signature
));
1717 sig
->bodylength
= -1;
1720 sig
->domain
= string_copy(US domain
);
1721 sig
->selector
= string_copy(US selector
);
1722 sig
->rsa_privkey
= string_copy(US rsa_privkey
);
1725 exim_sha_init(&sig
->body_hash_ctx
,
1726 algo
== PDKIM_ALGO_RSA_SHA1
? HASH_SHA1
: HASH_SHA256
);
1729 pdkim_signature s
= *sig
;
1732 debug_printf("PDKIM (checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1733 if (!pdkim_key_from_dns(ctx
, &s
, &vctx
))
1734 debug_printf("WARNING: bad dkim key in dns\n");
1735 debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1741 /* -------------------------------------------------------------------------- */
1744 pdkim_set_optional(pdkim_ctx
*ctx
,
1750 unsigned long created
,
1751 unsigned long expires
)
1753 pdkim_signature
* sig
= ctx
->sig
;
1756 sig
->identity
= string_copy(US identity
);
1758 sig
->sign_headers
= string_copy(sign_headers
1759 ? US sign_headers
: US PDKIM_DEFAULT_SIGN_HEADERS
);
1761 sig
->canon_headers
= canon_headers
;
1762 sig
->canon_body
= canon_body
;
1763 sig
->bodylength
= bodylength
;
1764 sig
->created
= created
;
1765 sig
->expires
= expires
;
1779 #endif /*DISABLE_DKIM*/