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 "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 #define PDKIM_STR_ALLOC_FRAG 256
74 unsigned int allocated
;
77 /* -------------------------------------------------------------------------- */
78 /* A bunch of list constants */
79 const char *pdkim_querymethods
[] = {
83 const char *pdkim_algos
[] = {
88 const char *pdkim_canons
[] = {
93 const char *pdkim_hashes
[] = {
98 const char *pdkim_keytypes
[] = {
103 typedef struct pdkim_combined_canon_entry
{
107 } pdkim_combined_canon_entry
;
109 pdkim_combined_canon_entry pdkim_combined_canons
[] = {
110 { "simple/simple", PDKIM_CANON_SIMPLE
, PDKIM_CANON_SIMPLE
},
111 { "simple/relaxed", PDKIM_CANON_SIMPLE
, PDKIM_CANON_RELAXED
},
112 { "relaxed/simple", PDKIM_CANON_RELAXED
, PDKIM_CANON_SIMPLE
},
113 { "relaxed/relaxed", PDKIM_CANON_RELAXED
, PDKIM_CANON_RELAXED
},
114 { "simple", PDKIM_CANON_SIMPLE
, PDKIM_CANON_SIMPLE
},
115 { "relaxed", PDKIM_CANON_RELAXED
, PDKIM_CANON_SIMPLE
},
120 /* -------------------------------------------------------------------------- */
123 pdkim_verify_status_str(int status
)
126 case PDKIM_VERIFY_NONE
: return "PDKIM_VERIFY_NONE";
127 case PDKIM_VERIFY_INVALID
: return "PDKIM_VERIFY_INVALID";
128 case PDKIM_VERIFY_FAIL
: return "PDKIM_VERIFY_FAIL";
129 case PDKIM_VERIFY_PASS
: return "PDKIM_VERIFY_PASS";
130 default: return "PDKIM_VERIFY_UNKNOWN";
135 pdkim_verify_ext_status_str(int ext_status
)
138 case PDKIM_VERIFY_FAIL_BODY
: return "PDKIM_VERIFY_FAIL_BODY";
139 case PDKIM_VERIFY_FAIL_MESSAGE
: return "PDKIM_VERIFY_FAIL_MESSAGE";
140 case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE
: return "PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE";
141 case PDKIM_VERIFY_INVALID_BUFFER_SIZE
: return "PDKIM_VERIFY_INVALID_BUFFER_SIZE";
142 case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD
: return "PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD";
143 case PDKIM_VERIFY_INVALID_PUBKEY_IMPORT
: return "PDKIM_VERIFY_INVALID_PUBKEY_IMPORT";
144 default: return "PDKIM_VERIFY_UNKNOWN";
149 /* -------------------------------------------------------------------------- */
150 /* Print debugging functions */
152 pdkim_quoteprint(const char *data
, int len
)
155 const unsigned char *p
= (const unsigned char *)data
;
157 for (i
= 0; i
< len
; i
++)
162 case ' ' : debug_printf("{SP}"); break;
163 case '\t': debug_printf("{TB}"); break;
164 case '\r': debug_printf("{CR}"); break;
165 case '\n': debug_printf("{LF}"); break;
166 case '{' : debug_printf("{BO}"); break;
167 case '}' : debug_printf("{BC}"); break;
169 if ( (c
< 32) || (c
> 127) )
170 debug_printf("{%02x}", c
);
172 debug_printf("%c", c
);
180 pdkim_hexprint(const char *data
, int len
)
183 const unsigned char *p
= (const unsigned char *)data
;
185 for (i
= 0 ; i
< len
; i
++)
186 debug_printf("%02x", p
[i
]);
192 /* SSS probably want to keep the "stringlist" notion */
194 static pdkim_stringlist
*
195 pdkim_prepend_stringlist(pdkim_stringlist
*base
, char *str
)
197 pdkim_stringlist
*new_entry
= malloc(sizeof(pdkim_stringlist
));
199 if (!new_entry
) return NULL
;
200 memset(new_entry
, 0, sizeof(pdkim_stringlist
));
201 if (!(new_entry
->value
= strdup(str
))) return NULL
;
204 pdkim_stringlist
*last
= base
;
205 while (last
->next
!= NULL
) { last
= last
->next
; }
206 last
->next
= new_entry
;
214 /* -------------------------------------------------------------------------- */
215 /* A small "growing string" implementation to escape malloc/realloc hell */
216 /* String package: should be replaced by Exim standard ones */
220 pdkim_strnew (const char *cstr
)
222 unsigned int len
= cstr
? strlen(cstr
) : 0;
223 pdkim_str
*p
= malloc(sizeof(pdkim_str
));
226 memset(p
, 0, sizeof(pdkim_str
));
227 if (!(p
->str
= malloc(len
+1)))
232 p
->allocated
= len
+1;
235 strcpy(p
->str
, cstr
);
237 p
->str
[p
->len
] = '\0';
245 pdkim_strncat(pdkim_str
*str
, const char *data
, int len
)
247 if ((str
->allocated
- str
->len
) < (len
+1))
249 /* Extend the buffer */
250 int num_frags
= ((len
+1)/PDKIM_STR_ALLOC_FRAG
)+1;
251 char *n
= realloc(str
->str
,
252 (str
->allocated
+(num_frags
*PDKIM_STR_ALLOC_FRAG
)));
253 if (n
== NULL
) return NULL
;
255 str
->allocated
+= (num_frags
*PDKIM_STR_ALLOC_FRAG
);
257 strncpy(&(str
->str
[str
->len
]), data
, len
);
259 str
->str
[str
->len
] = '\0';
267 pdkim_strcat(pdkim_str
*str
, const char *cstr
)
269 return pdkim_strncat(str
, cstr
, strlen(cstr
));
274 /* Trim whitespace fore & aft */
277 pdkim_strtrim(pdkim_str
*str
)
281 while (*p
== '\t' || *p
== ' ') p
++; /* skip whitespace */
282 while (*p
) {*q
= *p
; q
++; p
++;} /* dump the leading whitespace */
284 while (q
!= str
->str
&& ( (*q
== '\0') || (*q
== '\t') || (*q
== ' ') ) )
285 { /* dump trailing whitespace */
289 str
->len
= strlen(str
->str
);
296 pdkim_strclear(pdkim_str
*str
)
306 pdkim_strfree(pdkim_str
*str
)
309 if (str
->str
) free(str
->str
);
315 pdkim_stringlist_free(pdkim_stringlist
* e
)
319 pdkim_stringlist
* c
= e
;
320 if (e
->value
) free(e
->value
);
328 /* -------------------------------------------------------------------------- */
331 pdkim_free_pubkey(pdkim_pubkey
*pub
)
335 if (pub
->version
) free(pub
->version
);
336 if (pub
->granularity
) free(pub
->granularity
);
337 if (pub
->hashes
) free(pub
->hashes
);
338 if (pub
->keytype
) free(pub
->keytype
);
339 if (pub
->srvtype
) free(pub
->srvtype
);
340 if (pub
->notes
) free(pub
->notes
);
346 /* -------------------------------------------------------------------------- */
349 pdkim_free_sig(pdkim_signature
*sig
)
353 pdkim_signature
*next
= (pdkim_signature
*)sig
->next
;
355 pdkim_stringlist_free(sig
->headers
);
356 if (sig
->selector
) free(sig
->selector
);
357 if (sig
->domain
) free(sig
->domain
);
358 if (sig
->identity
) free(sig
->identity
);
359 if (sig
->copiedheaders
) free(sig
->copiedheaders
);
360 if (sig
->rsa_privkey
) free(sig
->rsa_privkey
);
361 if (sig
->sign_headers
) free(sig
->sign_headers
);
362 if (sig
->signature_header
) free(sig
->signature_header
);
364 if (sig
->pubkey
) pdkim_free_pubkey(sig
->pubkey
);
367 if (next
) pdkim_free_sig(next
);
372 /* -------------------------------------------------------------------------- */
375 pdkim_free_ctx(pdkim_ctx
*ctx
)
379 pdkim_stringlist_free(ctx
->headers
);
380 pdkim_free_sig(ctx
->sig
);
381 pdkim_strfree(ctx
->cur_header
);
387 /* -------------------------------------------------------------------------- */
388 /* Matches the name of the passed raw "header" against
389 the passed colon-separated "tick", and invalidates
390 the entry in tick. Returns OK or fail-code */
391 /*XXX might be safer done using a pdkim_stringlist for "tick" */
394 header_name_match(const char * header
, char * tick
)
402 /* Get header name */
403 char *hcolon
= strchr(header
, ':');
405 if (!hcolon
) return rc
; /* This isn't a header */
407 if (!(hname
= malloc((hcolon
-header
)+1)))
408 return PDKIM_ERR_OOM
;
409 memset(hname
, 0, (hcolon
-header
)+1);
410 strncpy(hname
, header
, (hcolon
-header
));
412 /* Copy tick-off list locally, so we can punch zeroes into it */
413 if (!(lcopy
= strdup(tick
)))
416 return PDKIM_ERR_OOM
;
424 if (strcasecmp(p
, hname
) == 0)
427 /* Invalidate header name instance in tick-off list */
436 if (strcasecmp(p
, hname
) == 0)
439 /* Invalidate header name instance in tick-off list */
450 /* -------------------------------------------------------------------------- */
451 /* Performs "relaxed" canonicalization of a header. The returned pointer needs
455 pdkim_relax_header (char *header
, int crlf
)
457 BOOL past_field_name
= FALSE
;
458 BOOL seen_wsp
= FALSE
;
461 char *relaxed
= malloc(strlen(header
)+3);
463 if (!relaxed
) return NULL
;
466 for (p
= header
; *p
!= '\0'; p
++)
470 if (c
== '\r' || c
== '\n')
472 if (c
== '\t' || c
== ' ')
476 c
= ' '; /* Turns WSP into SP */
480 if (!past_field_name
&& c
== ':')
482 if (seen_wsp
) q
--; /* This removes WSP before the colon */
483 seen_wsp
= TRUE
; /* This removes WSP after the colon */
484 past_field_name
= TRUE
;
489 /* Lowercase header name */
490 if (!past_field_name
) c
= tolower(c
);
494 if (q
> relaxed
&& q
[-1] == ' ') q
--; /* Squash eventual trailing SP */
497 if (crlf
) strcat(relaxed
, "\r\n");
502 /* -------------------------------------------------------------------------- */
503 #define PDKIM_QP_ERROR_DECODE -1
506 pdkim_decode_qp_char(char *qp_p
, int *c
)
508 char *initial_pos
= qp_p
;
510 /* Advance one char */
513 /* Check for two hex digits and decode them */
514 if (isxdigit(*qp_p
) && isxdigit(qp_p
[1]))
516 /* Do hex conversion */
517 *c
= (isdigit(*qp_p
) ? *qp_p
- '0' : toupper(*qp_p
) - 'A' + 10) << 4;
518 *c
|= isdigit(qp_p
[1]) ? qp_p
[1] - '0' : toupper(qp_p
[1]) - 'A' + 10;
522 /* Illegal char here */
523 *c
= PDKIM_QP_ERROR_DECODE
;
528 /* -------------------------------------------------------------------------- */
531 pdkim_decode_qp(char *str
)
536 char *n
= malloc(strlen(p
)+1);
546 p
= pdkim_decode_qp_char(p
, &nchar
);
562 /* -------------------------------------------------------------------------- */
565 pdkim_decode_base64(uschar
*str
, blob
* b
)
569 dlen
= b64decode(str
, &b
->data
);
570 if (dlen
< 0) b
->data
= NULL
;
574 /* -------------------------------------------------------------------------- */
577 pdkim_encode_base64(blob
* b
)
580 int old_pool
= store_pool
;
582 store_pool
= POOL_PERM
;
583 ret
= CS
b64encode(b
->data
, b
->len
);
584 store_pool
= old_pool
;
589 /* -------------------------------------------------------------------------- */
590 #define PDKIM_HDR_LIMBO 0
591 #define PDKIM_HDR_TAG 1
592 #define PDKIM_HDR_VALUE 2
594 static pdkim_signature
*
595 pdkim_parse_sig_header(pdkim_ctx
*ctx
, char *raw_hdr
)
597 pdkim_signature
*sig
;
599 pdkim_str
*cur_tag
= NULL
;
600 pdkim_str
*cur_val
= NULL
;
601 BOOL past_hname
= FALSE
;
602 BOOL in_b_val
= FALSE
;
603 int where
= PDKIM_HDR_LIMBO
;
605 int old_pool
= store_pool
;
607 /* There is a store-reset between header & body reception
608 so cannot use the main pool. Any allocs done by Exim
609 memory-handling must use the perm pool. */
611 store_pool
= POOL_PERM
;
613 if (!(sig
= malloc(sizeof(pdkim_signature
)))) return NULL
;
614 memset(sig
, 0, sizeof(pdkim_signature
));
615 sig
->bodylength
= -1;
617 if (!(sig
->rawsig_no_b_val
= malloc(strlen(raw_hdr
)+1)))
623 q
= sig
->rawsig_no_b_val
;
625 for (p
= raw_hdr
; ; p
++)
630 if (c
== '\r' || c
== '\n')
633 /* Fast-forward through header name */
636 if (c
== ':') past_hname
= TRUE
;
640 if (where
== PDKIM_HDR_LIMBO
)
642 /* In limbo, just wait for a tag-char to appear */
643 if (!(c
>= 'a' && c
<= 'z'))
646 where
= PDKIM_HDR_TAG
;
649 if (where
== PDKIM_HDR_TAG
)
652 cur_tag
= pdkim_strnew(NULL
);
654 if (c
>= 'a' && c
<= 'z')
655 pdkim_strncat(cur_tag
, p
, 1);
659 if (strcmp(cur_tag
->str
, "b") == 0)
664 where
= PDKIM_HDR_VALUE
;
669 if (where
== PDKIM_HDR_VALUE
)
672 cur_val
= pdkim_strnew(NULL
);
674 if (c
== '\r' || c
== '\n' || c
== ' ' || c
== '\t')
677 if (c
== ';' || c
== '\0')
679 if (cur_tag
->len
> 0)
681 pdkim_strtrim(cur_val
);
683 DEBUG(D_acl
) debug_printf(" %s=%s\n", cur_tag
->str
, cur_val
->str
);
685 switch (cur_tag
->str
[0])
688 if (cur_tag
->str
[1] == 'h')
689 pdkim_decode_base64(US cur_val
->str
, &sig
->bodyhash
);
691 pdkim_decode_base64(US cur_val
->str
, &sig
->sigdata
);
694 /* We only support version 1, and that is currently the
695 only version there is. */
696 if (strcmp(cur_val
->str
, PDKIM_SIGNATURE_VERSION
) == 0)
700 for (i
= 0; pdkim_algos
[i
]; i
++)
701 if (strcmp(cur_val
->str
, pdkim_algos
[i
]) == 0)
708 for (i
= 0; pdkim_combined_canons
[i
].str
; i
++)
709 if (strcmp(cur_val
->str
, pdkim_combined_canons
[i
].str
) == 0)
711 sig
->canon_headers
= pdkim_combined_canons
[i
].canon_headers
;
712 sig
->canon_body
= pdkim_combined_canons
[i
].canon_body
;
717 for (i
= 0; pdkim_querymethods
[i
]; i
++)
718 if (strcmp(cur_val
->str
, pdkim_querymethods
[i
]) == 0)
720 sig
->querymethod
= i
;
725 sig
->selector
= strdup(cur_val
->str
); break;
727 sig
->domain
= strdup(cur_val
->str
); break;
729 sig
->identity
= pdkim_decode_qp(cur_val
->str
); break;
731 sig
->created
= strtoul(cur_val
->str
, NULL
, 10); break;
733 sig
->expires
= strtoul(cur_val
->str
, NULL
, 10); break;
735 sig
->bodylength
= strtol(cur_val
->str
, NULL
, 10); break;
737 sig
->headernames
= string_copy(cur_val
->str
); break;
739 sig
->copiedheaders
= pdkim_decode_qp(cur_val
->str
); break;
741 DEBUG(D_acl
) debug_printf(" Unknown tag encountered\n");
745 pdkim_strclear(cur_tag
);
746 pdkim_strclear(cur_val
);
748 where
= PDKIM_HDR_LIMBO
;
751 pdkim_strncat(cur_val
, p
, 1);
762 store_pool
= old_pool
;
764 /* Make sure the most important bits are there. */
765 if (!(sig
->domain
&& (*(sig
->domain
) != '\0') &&
766 sig
->selector
&& (*(sig
->selector
) != '\0') &&
767 sig
->headernames
&& (*(sig
->headernames
) != '\0') &&
775 /* Chomp raw header. The final newline must not be added to the signature. */
777 while (q
> sig
->rawsig_no_b_val
&& (*q
== '\r' || *q
== '\n'))
778 *q
= '\0'; q
--; /*XXX questionable code layout; possible bug */
783 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
784 pdkim_quoteprint(sig
->rawsig_no_b_val
, strlen(sig
->rawsig_no_b_val
));
786 "PDKIM >> Sig size: %4d bits\n", sig
->sigdata
.len
*8);
788 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
791 exim_sha_init(&sig
->body_hash
, sig
->algo
== PDKIM_ALGO_RSA_SHA1
);
796 /* -------------------------------------------------------------------------- */
798 static pdkim_pubkey
*
799 pdkim_parse_pubkey_record(pdkim_ctx
*ctx
, char *raw_record
)
803 pdkim_str
*cur_tag
= NULL
;
804 pdkim_str
*cur_val
= NULL
;
805 int where
= PDKIM_HDR_LIMBO
;
807 if (!(pub
= malloc(sizeof(pdkim_pubkey
)))) return NULL
;
808 memset(pub
, 0, sizeof(pdkim_pubkey
));
810 for (p
= raw_record
; ; p
++)
815 if (c
== '\r' || c
== '\n')
818 if (where
== PDKIM_HDR_LIMBO
)
820 /* In limbo, just wait for a tag-char to appear */
821 if (!(c
>= 'a' && c
<= 'z'))
824 where
= PDKIM_HDR_TAG
;
827 if (where
== PDKIM_HDR_TAG
)
830 cur_tag
= pdkim_strnew(NULL
);
832 if (c
>= 'a' && c
<= 'z')
833 pdkim_strncat(cur_tag
, p
, 1);
837 where
= PDKIM_HDR_VALUE
;
842 if (where
== PDKIM_HDR_VALUE
)
845 cur_val
= pdkim_strnew(NULL
);
847 if (c
== '\r' || c
== '\n')
850 if (c
== ';' || c
== '\0')
852 if (cur_tag
->len
> 0)
854 pdkim_strtrim(cur_val
);
855 DEBUG(D_acl
) debug_printf(" %s=%s\n", cur_tag
->str
, cur_val
->str
);
857 switch (cur_tag
->str
[0])
860 /* This tag isn't evaluated because:
861 - We only support version DKIM1.
862 - Which is the default for this value (set below)
863 - Other versions are currently not specified. */
866 pub
->hashes
= strdup(cur_val
->str
); break;
868 pub
->granularity
= strdup(cur_val
->str
); break;
870 pub
->notes
= pdkim_decode_qp(cur_val
->str
); break;
872 pdkim_decode_base64(US cur_val
->str
, &pub
->key
);
875 pub
->hashes
= strdup(cur_val
->str
); break;
877 pub
->srvtype
= strdup(cur_val
->str
); break;
879 if (strchr(cur_val
->str
, 'y') != NULL
) pub
->testing
= 1;
880 if (strchr(cur_val
->str
, 's') != NULL
) pub
->no_subdomaining
= 1;
883 DEBUG(D_acl
) debug_printf(" Unknown tag encountered\n");
887 pdkim_strclear(cur_tag
);
888 pdkim_strclear(cur_val
);
889 where
= PDKIM_HDR_LIMBO
;
892 pdkim_strncat(cur_val
, p
, 1);
896 if (c
== '\0') break;
899 /* Set fallback defaults */
900 if (!pub
->version
) pub
->version
= strdup(PDKIM_PUB_RECORD_VERSION
);
901 if (!pub
->granularity
) pub
->granularity
= strdup("*");
902 if (!pub
->keytype
) pub
->keytype
= strdup("rsa");
903 if (!pub
->srvtype
) pub
->srvtype
= strdup("*");
909 pdkim_free_pubkey(pub
);
914 /* -------------------------------------------------------------------------- */
917 pdkim_update_bodyhash(pdkim_ctx
*ctx
, const char *data
, int len
)
919 pdkim_signature
*sig
= ctx
->sig
;
920 /* Cache relaxed version of data */
921 char *relaxed_data
= NULL
;
924 /* Traverse all signatures, updating their hashes. */
927 /* Defaults to simple canon (no further treatment necessary) */
928 const char *canon_data
= data
;
931 if (sig
->canon_body
== PDKIM_CANON_RELAXED
)
933 /* Relax the line if not done already */
936 BOOL seen_wsp
= FALSE
;
940 if (!(relaxed_data
= malloc(len
+1)))
941 return PDKIM_ERR_OOM
;
943 for (p
= data
; *p
; p
++)
948 if (q
> 0 && relaxed_data
[q
-1] == ' ')
951 else if (c
== '\t' || c
== ' ')
953 c
= ' '; /* Turns WSP into SP */
960 relaxed_data
[q
++] = c
;
962 relaxed_data
[q
] = '\0';
965 canon_data
= relaxed_data
;
966 canon_len
= relaxed_len
;
969 /* Make sure we don't exceed the to-be-signed body length */
970 if ( sig
->bodylength
>= 0
971 && sig
->signed_body_bytes
+ (unsigned long)canon_len
> sig
->bodylength
973 canon_len
= sig
->bodylength
- sig
->signed_body_bytes
;
977 exim_sha_update(&sig
->body_hash
, canon_data
, canon_len
);
978 sig
->signed_body_bytes
+= canon_len
;
979 DEBUG(D_acl
) pdkim_quoteprint(canon_data
, canon_len
);
985 if (relaxed_data
) free(relaxed_data
);
990 /* -------------------------------------------------------------------------- */
993 pdkim_finish_bodyhash(pdkim_ctx
*ctx
)
995 pdkim_signature
*sig
;
997 /* Traverse all signatures */
998 for (sig
= ctx
->sig
; sig
; sig
= sig
->next
)
999 { /* Finish hashes */
1002 exim_sha_finish(&sig
->body_hash
, &bh
);
1006 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
1007 "PDKIM [%s] bh computed: ",
1008 sig
->domain
, sig
->signed_body_bytes
, sig
->domain
);
1009 pdkim_hexprint(CS bh
.data
, bh
.len
);
1012 /* SIGNING -------------------------------------------------------------- */
1013 if (ctx
->mode
== PDKIM_MODE_SIGN
)
1017 /* If bodylength limit is set, and we have received less bytes
1018 than the requested amount, effectively remove the limit tag. */
1019 if (sig
->signed_body_bytes
< sig
->bodylength
)
1020 sig
->bodylength
= -1;
1023 /* VERIFICATION --------------------------------------------------------- */
1026 /* Compare bodyhash */
1027 if (memcmp(bh
.data
, sig
->bodyhash
.data
, bh
.len
) == 0)
1029 DEBUG(D_acl
) debug_printf("PDKIM [%s] Body hash verified OK\n", sig
->domain
);
1035 debug_printf("PDKIM [%s] bh signature: ", sig
->domain
);
1036 pdkim_hexprint(sig
->bodyhash
.data
,
1037 exim_sha_hashlen(&sig
->body_hash
));
1038 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig
->domain
);
1040 sig
->verify_status
= PDKIM_VERIFY_FAIL
;
1041 sig
->verify_ext_status
= PDKIM_VERIFY_FAIL_BODY
;
1051 /* -------------------------------------------------------------------------- */
1052 /* Callback from pdkim_feed below for processing complete body lines */
1055 pdkim_bodyline_complete(pdkim_ctx
*ctx
)
1057 char *p
= ctx
->linebuf
;
1058 int n
= ctx
->linebuf_offset
;
1059 pdkim_signature
*sig
= ctx
->sig
; /*XXX assumes only one sig */
1061 /* Ignore extra data if we've seen the end-of-data marker */
1062 if (ctx
->seen_eod
) goto BAIL
;
1064 /* We've always got one extra byte to stuff a zero ... */
1065 ctx
->linebuf
[ctx
->linebuf_offset
] = '\0';
1067 /* Terminate on EOD marker */
1068 if (memcmp(p
, ".\r\n", 3) == 0)
1070 /* In simple body mode, if any empty lines were buffered,
1071 replace with one. rfc 4871 3.4.3 */
1072 /*XXX checking the signed-body-bytes is a gross hack; I think
1073 it indicates that all linebreaks should be buffered, including
1074 the one terminating a text line */
1075 if ( sig
&& sig
->canon_body
== PDKIM_CANON_SIMPLE
1076 && sig
->signed_body_bytes
== 0
1077 && ctx
->num_buffered_crlf
> 0
1079 pdkim_update_bodyhash(ctx
, "\r\n", 2);
1081 ctx
->seen_eod
= TRUE
;
1085 if (memcmp(p
, "..", 2) == 0)
1091 /* Empty lines need to be buffered until we find a non-empty line */
1092 if (memcmp(p
, "\r\n", 2) == 0)
1094 ctx
->num_buffered_crlf
++;
1098 if (sig
&& sig
->canon_body
== PDKIM_CANON_RELAXED
)
1100 /* Lines with just spaces need to be buffered too */
1102 while (memcmp(check
, "\r\n", 2) != 0)
1106 if (c
!= '\t' && c
!= ' ')
1111 ctx
->num_buffered_crlf
++;
1116 /* At this point, we have a non-empty line, so release the buffered ones. */
1117 while (ctx
->num_buffered_crlf
)
1119 pdkim_update_bodyhash(ctx
, "\r\n", 2);
1120 ctx
->num_buffered_crlf
--;
1123 pdkim_update_bodyhash(ctx
, p
, n
);
1126 ctx
->linebuf_offset
= 0;
1131 /* -------------------------------------------------------------------------- */
1132 /* Callback from pdkim_feed below for processing complete headers */
1133 #define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
1136 pdkim_header_complete(pdkim_ctx
*ctx
)
1138 /* Special case: The last header can have an extra \r appended */
1139 if ( (ctx
->cur_header
->len
> 1) &&
1140 (ctx
->cur_header
->str
[(ctx
->cur_header
->len
)-1] == '\r') )
1142 ctx
->cur_header
->str
[(ctx
->cur_header
->len
)-1] = '\0';
1143 ctx
->cur_header
->len
--;
1147 if (ctx
->num_headers
> PDKIM_MAX_HEADERS
) goto BAIL
;
1149 /* SIGNING -------------------------------------------------------------- */
1150 if (ctx
->mode
== PDKIM_MODE_SIGN
)
1152 pdkim_signature
*sig
;
1154 for (sig
= ctx
->sig
; sig
; sig
= sig
->next
) /* Traverse all signatures */
1155 if (header_name_match(ctx
->cur_header
->str
,
1156 sig
->sign_headers
) == PDKIM_OK
)
1158 pdkim_stringlist
*list
;
1160 /* Add header to the signed headers list (in reverse order) */
1161 if (!(list
= pdkim_prepend_stringlist(sig
->headers
,
1162 ctx
->cur_header
->str
)))
1163 return PDKIM_ERR_OOM
;
1164 sig
->headers
= list
;
1168 /* VERIFICATION ----------------------------------------------------------- */
1169 /* DKIM-Signature: headers are added to the verification list */
1170 if (ctx
->mode
== PDKIM_MODE_VERIFY
)
1172 if (strncasecmp(ctx
->cur_header
->str
,
1173 DKIM_SIGNATURE_HEADERNAME
,
1174 strlen(DKIM_SIGNATURE_HEADERNAME
)) == 0)
1176 pdkim_signature
*new_sig
;
1178 /* Create and chain new signature block */
1179 DEBUG(D_acl
) debug_printf(
1180 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1182 if ((new_sig
= pdkim_parse_sig_header(ctx
, ctx
->cur_header
->str
)))
1184 pdkim_signature
*last_sig
= ctx
->sig
;
1189 while (last_sig
->next
) last_sig
= last_sig
->next
;
1190 last_sig
->next
= new_sig
;
1194 DEBUG(D_acl
) debug_printf(
1195 "Error while parsing signature header\n"
1196 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1199 /* every other header is stored for signature verification */
1202 pdkim_stringlist
*list
;
1204 if (!(list
= pdkim_prepend_stringlist(ctx
->headers
, ctx
->cur_header
->str
)))
1205 return PDKIM_ERR_OOM
;
1206 ctx
->headers
= list
;
1211 pdkim_strclear(ctx
->cur_header
); /* Re-use existing pdkim_str */
1217 /* -------------------------------------------------------------------------- */
1218 #define HEADER_BUFFER_FRAG_SIZE 256
1221 pdkim_feed (pdkim_ctx
*ctx
, char *data
, int len
)
1225 for (p
= 0; p
<len
; p
++)
1229 if (ctx
->past_headers
)
1231 /* Processing body byte */
1232 ctx
->linebuf
[ctx
->linebuf_offset
++] = c
;
1235 int rc
= pdkim_bodyline_complete(ctx
); /* End of line */
1236 if (rc
!= PDKIM_OK
) return rc
;
1238 if (ctx
->linebuf_offset
== (PDKIM_MAX_BODY_LINE_LEN
-1))
1239 return PDKIM_ERR_LONG_LINE
;
1243 /* Processing header byte */
1250 int rc
= pdkim_header_complete(ctx
); /* Seen last header line */
1251 if (rc
!= PDKIM_OK
) return rc
;
1253 ctx
->past_headers
= TRUE
;
1255 DEBUG(D_acl
) debug_printf(
1256 "PDKIM >> Body data for hash, canonicalized >>>>>>>>>>>>>>>>>>>>>>\n");
1260 ctx
->seen_lf
= TRUE
;
1262 else if (ctx
->seen_lf
)
1264 if (!(c
== '\t' || c
== ' '))
1266 int rc
= pdkim_header_complete(ctx
); /* End of header */
1267 if (rc
!= PDKIM_OK
) return rc
;
1269 ctx
->seen_lf
= FALSE
;
1273 if (!ctx
->cur_header
)
1274 if (!(ctx
->cur_header
= pdkim_strnew(NULL
)))
1275 return PDKIM_ERR_OOM
;
1277 if (ctx
->cur_header
->len
< PDKIM_MAX_HEADER_LEN
)
1278 if (!pdkim_strncat(ctx
->cur_header
, &data
[p
], 1))
1279 return PDKIM_ERR_OOM
;
1286 * RFC 5322 specifies that header line length SHOULD be no more than 78
1291 * col: this int holds and receives column number (octets since last '\n')
1292 * str: partial string to append to
1293 * pad: padding, split line or space after before or after eg: ";"
1294 * intro: - must join to payload eg "h=", usually the tag name
1295 * payload: eg base64 data - long data can be split arbitrarily.
1297 * this code doesn't fold the header in some of the places that RFC4871
1298 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1299 * pairs and inside long values. it also always spaces or breaks after the
1302 * no guarantees are made for output given out-of range input. like tag
1303 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
1307 pdkim_headcat(int *col
, pdkim_str
*str
, const char * pad
,
1308 const char *intro
, const char *payload
)
1317 pdkim_strcat(str
, "\r\n\t");
1320 pdkim_strncat(str
, pad
, l
);
1324 l
= (pad
?1:0) + (intro
?strlen(intro
):0);
1327 { /*can't fit intro - start a new line to make room.*/
1328 pdkim_strcat(str
, "\r\n\t");
1330 l
= intro
?strlen(intro
):0;
1333 l
+= payload
? strlen(payload
):0 ;
1336 { /* this fragment will not fit on a single line */
1339 pdkim_strcat(str
, " ");
1341 pad
= NULL
; /* only want this once */
1347 size_t sl
= strlen(intro
);
1349 pdkim_strncat(str
, intro
, sl
);
1352 intro
= NULL
; /* only want this once */
1357 size_t sl
= strlen(payload
);
1358 size_t chomp
= *col
+sl
< 77 ? sl
: 78-*col
;
1360 pdkim_strncat(str
, payload
, chomp
);
1366 /* the while precondition tells us it didn't fit. */
1367 pdkim_strcat(str
, "\r\n\t");
1373 pdkim_strcat(str
, "\r\n\t");
1380 pdkim_strcat(str
, " ");
1387 size_t sl
= strlen(intro
);
1389 pdkim_strncat(str
, intro
, sl
);
1397 size_t sl
= strlen(payload
);
1399 pdkim_strncat(str
, payload
, sl
);
1407 /* -------------------------------------------------------------------------- */
1410 pdkim_create_header(pdkim_signature
*sig
, BOOL final
)
1413 char *base64_bh
= NULL
;
1414 char *base64_b
= NULL
;
1417 pdkim_str
*canon_all
;
1419 if (!(hdr
= pdkim_strnew("DKIM-Signature: v="PDKIM_SIGNATURE_VERSION
)))
1422 if (!(canon_all
= pdkim_strnew(pdkim_canons
[sig
->canon_headers
])))
1425 if (!(base64_bh
= pdkim_encode_base64(&sig
->bodyhash
)))
1428 col
= strlen(hdr
->str
);
1430 /* Required and static bits */
1431 if ( pdkim_headcat(&col
, hdr
, ";", "a=", pdkim_algos
[sig
->algo
])
1432 && pdkim_headcat(&col
, hdr
, ";", "q=", pdkim_querymethods
[sig
->querymethod
])
1433 && pdkim_strcat(canon_all
, "/")
1434 && pdkim_strcat(canon_all
, pdkim_canons
[sig
->canon_body
])
1435 && pdkim_headcat(&col
, hdr
, ";", "c=", canon_all
->str
)
1436 && pdkim_headcat(&col
, hdr
, ";", "d=", sig
->domain
)
1437 && pdkim_headcat(&col
, hdr
, ";", "s=", sig
->selector
)
1440 /* list of header names can be split between items. */
1442 char *n
= CS
string_copy(sig
->headernames
);
1450 char *c
= strchr(n
, ':');
1455 if (!pdkim_headcat(&col
, hdr
, NULL
, NULL
, ":"))
1460 if (!pdkim_headcat(&col
, hdr
, s
, i
, n
))
1474 if(!pdkim_headcat(&col
, hdr
, ";", "bh=", base64_bh
))
1479 if(!pdkim_headcat(&col
, hdr
, ";", "i=", sig
->identity
))
1482 if (sig
->created
> 0)
1486 snprintf(minibuf
, 20, "%lu", sig
->created
);
1487 if(!pdkim_headcat(&col
, hdr
, ";", "t=", minibuf
))
1491 if (sig
->expires
> 0)
1495 snprintf(minibuf
, 20, "%lu", sig
->expires
);
1496 if(!pdkim_headcat(&col
, hdr
, ";", "x=", minibuf
))
1500 if (sig
->bodylength
>= 0)
1504 snprintf(minibuf
, 20, "%lu", sig
->bodylength
);
1505 if(!pdkim_headcat(&col
, hdr
, ";", "l=", minibuf
))
1509 /* Preliminary or final version? */
1512 if (!(base64_b
= pdkim_encode_base64(&sig
->sigdata
)))
1514 if (!pdkim_headcat(&col
, hdr
, ";", "b=", base64_b
))
1518 if(!pdkim_headcat(&col
, hdr
, ";", "b=", ""))
1521 /* add trailing semicolon: I'm not sure if this is actually needed */
1522 if (!pdkim_headcat(&col
, hdr
, NULL
, ";", ""))
1526 rc
= strdup(hdr
->str
);
1530 if (canon_all
) pdkim_strfree(canon_all
);
1535 /* -------------------------------------------------------------------------- */
1538 pdkim_feed_finish(pdkim_ctx
*ctx
, pdkim_signature
**return_signatures
)
1540 pdkim_signature
*sig
= ctx
->sig
;
1541 pdkim_str
*headernames
= NULL
; /* Collected signed header names */
1543 /* Check if we must still flush a (partial) header. If that is the
1544 case, the message has no body, and we must compute a body hash
1545 out of '<CR><LF>' */
1546 if (ctx
->cur_header
&& ctx
->cur_header
->len
)
1548 int rc
= pdkim_header_complete(ctx
);
1549 if (rc
!= PDKIM_OK
) return rc
;
1550 pdkim_update_bodyhash(ctx
, "\r\n", 2);
1553 DEBUG(D_acl
) debug_printf(
1554 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1556 /* Build (and/or evaluate) body hash */
1557 if (pdkim_finish_bodyhash(ctx
) != PDKIM_OK
)
1558 return PDKIM_ERR_OOM
;
1560 /* SIGNING -------------------------------------------------------------- */
1561 if (ctx
->mode
== PDKIM_MODE_SIGN
)
1562 if (!(headernames
= pdkim_strnew(NULL
)))
1563 return PDKIM_ERR_OOM
;
1564 /* ---------------------------------------------------------------------- */
1568 BOOL is_sha1
= sig
->algo
== PDKIM_ALGO_RSA_SHA1
;
1573 int hdata_alloc
= 0;
1578 exim_sha_init(&hhash_ctx
, is_sha1
);
1580 DEBUG(D_acl
) debug_printf(
1581 "PDKIM >> Hashed header data, canonicalized, in sequence >>>>>>>>>>>>>>\n");
1583 /* SIGNING ---------------------------------------------------------------- */
1584 /* When signing, walk through our header list and add them to the hash. As we
1585 go, construct a list of the header's names to use for the h= parameter.
1586 Then append to that list any remaining header names for which there was no
1589 if (ctx
->mode
== PDKIM_MODE_SIGN
)
1591 pdkim_stringlist
*p
;
1596 for (p
= sig
->headers
; p
; p
= p
->next
)
1599 /* Collect header names (Note: colon presence is guaranteed here) */
1600 uschar
* q
= Ustrchr(p
->value
, ':');
1602 if (!(pdkim_strncat(headernames
, p
->value
,
1603 (q
- US p
->value
) + (p
->next
? 1 : 0))))
1604 return PDKIM_ERR_OOM
;
1606 rh
= sig
->canon_headers
== PDKIM_CANON_RELAXED
1607 ? US
pdkim_relax_header(p
->value
, 1) /* cook header for relaxed canon */
1608 : string_copy(p
->value
); /* just copy it for simple canon */
1610 return PDKIM_ERR_OOM
;
1612 /* Feed header to the hash algorithm */
1613 exim_sha_update(&hhash_ctx
, rh
, strlen(rh
));
1615 /* Remember headers block for signing (when the library cannot do incremental) */
1616 (void) exim_rsa_data_append(&hdata
, &hdata_alloc
, rh
);
1618 DEBUG(D_acl
) pdkim_quoteprint(rh
, Ustrlen(rh
));
1621 l
= US sig
->sign_headers
;
1622 while((s
= string_nextinlist(&l
, &sep
, NULL
, 0)))
1625 if (headernames
->len
> 0)
1626 if (!(pdkim_strncat(headernames
, ":", 1)))
1627 return PDKIM_ERR_OOM
;
1628 if (!(pdkim_strncat(headernames
, CS s
, Ustrlen(s
))))
1629 return PDKIM_ERR_OOM
;
1633 /* VERIFICATION ----------------------------------------------------------- */
1634 /* When verifying, walk through the header name list in the h= parameter and
1635 add the headers to the hash in that order. */
1638 uschar
* b
= string_copy(sig
->headernames
);
1641 pdkim_stringlist
* hdrs
;
1643 if (!b
) return PDKIM_ERR_OOM
;
1646 for (hdrs
= ctx
->headers
; hdrs
; hdrs
= hdrs
->next
)
1651 if ((q
= Ustrchr(p
, ':')))
1654 for (hdrs
= ctx
->headers
; hdrs
; hdrs
= hdrs
->next
)
1656 && strncasecmp(hdrs
->value
, CS p
, Ustrlen(p
)) == 0
1657 && (hdrs
->value
)[Ustrlen(p
)] == ':'
1660 uschar
* rh
= sig
->canon_headers
== PDKIM_CANON_RELAXED
1661 ? US
pdkim_relax_header(hdrs
->value
, 1) /* cook header for relaxed canon */
1662 : string_copy(hdrs
->value
); /* just copy it for simple canon */
1664 return PDKIM_ERR_OOM
;
1666 /* Feed header to the hash algorithm */
1667 exim_sha_update(&hhash_ctx
, rh
, strlen(rh
));
1669 DEBUG(D_acl
) pdkim_quoteprint(rh
, Ustrlen(rh
));
1679 DEBUG(D_acl
) debug_printf(
1680 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1682 /* SIGNING ---------------------------------------------------------------- */
1683 if (ctx
->mode
== PDKIM_MODE_SIGN
)
1685 /* Copy headernames to signature struct */
1686 sig
->headernames
= string_copy(US headernames
->str
);
1687 pdkim_strfree(headernames
);
1689 /* Create signature header with b= omitted */
1690 sig_hdr
= pdkim_create_header(sig
, FALSE
);
1693 /* VERIFICATION ----------------------------------------------------------- */
1695 sig_hdr
= strdup(sig
->rawsig_no_b_val
);
1696 /* ------------------------------------------------------------------------ */
1699 return PDKIM_ERR_OOM
;
1701 /* Relax header if necessary */
1702 if (sig
->canon_headers
== PDKIM_CANON_RELAXED
)
1704 char *relaxed_hdr
= pdkim_relax_header(sig_hdr
, 0);
1708 return PDKIM_ERR_OOM
;
1709 sig_hdr
= relaxed_hdr
;
1715 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
1716 pdkim_quoteprint(sig_hdr
, strlen(sig_hdr
));
1718 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1721 /* Finalize header hash */
1722 exim_sha_update(&hhash_ctx
, sig_hdr
, strlen(sig_hdr
));
1723 exim_sha_finish(&hhash_ctx
, &hhash
);
1727 debug_printf("PDKIM [%s] hh computed: ", sig
->domain
);
1728 pdkim_hexprint(hhash
.data
, hhash
.len
);
1731 /* Remember headers block for signing (when the library cannot do incremental) */
1732 if (ctx
->mode
== PDKIM_MODE_SIGN
)
1733 (void) exim_rsa_data_append(&hdata
, &hdata_alloc
, sig_hdr
);
1737 /* SIGNING ---------------------------------------------------------------- */
1738 if (ctx
->mode
== PDKIM_MODE_SIGN
)
1741 const uschar
* errstr
;
1743 /* Import private key */
1744 if ((errstr
= exim_rsa_signing_init(sig
->rsa_privkey
, &sctx
)))
1746 DEBUG(D_acl
) debug_printf("signing_init: %s\n", errstr
);
1747 return PDKIM_ERR_RSA_PRIVKEY
;
1750 /* Do signing. With OpenSSL we are signing the hash of headers just
1751 calculated, with GnuTLS we have to sign an entire block of headers
1752 (due to available interfaces) and it recalculates the hash internally. */
1754 #if defined(RSA_OPENSSL) || defined(RSA_GCRYPT)
1758 if ((errstr
= exim_rsa_sign(&sctx
, is_sha1
, &hdata
, &sig
->sigdata
)))
1760 DEBUG(D_acl
) debug_printf("signing: %s\n", errstr
);
1761 return PDKIM_ERR_RSA_SIGNING
;
1766 debug_printf( "PDKIM [%s] b computed: ", sig
->domain
);
1767 pdkim_hexprint(sig
->sigdata
.data
, sig
->sigdata
.len
);
1770 if (!(sig
->signature_header
= pdkim_create_header(sig
, TRUE
)))
1771 return PDKIM_ERR_OOM
;
1774 /* VERIFICATION ----------------------------------------------------------- */
1778 const uschar
* errstr
;
1780 char *dns_txt_name
, *dns_txt_reply
;
1782 /* Fetch public key for signing domain, from DNS */
1784 if (!(dns_txt_name
= malloc(PDKIM_DNS_TXT_MAX_NAMELEN
)))
1785 return PDKIM_ERR_OOM
;
1787 if (!(dns_txt_reply
= malloc(PDKIM_DNS_TXT_MAX_RECLEN
)))
1790 return PDKIM_ERR_OOM
;
1793 memset(dns_txt_reply
, 0, PDKIM_DNS_TXT_MAX_RECLEN
);
1794 memset(dns_txt_name
, 0, PDKIM_DNS_TXT_MAX_NAMELEN
);
1796 if (snprintf(dns_txt_name
, PDKIM_DNS_TXT_MAX_NAMELEN
,
1797 "%s._domainkey.%s.",
1798 sig
->selector
, sig
->domain
) >= PDKIM_DNS_TXT_MAX_NAMELEN
)
1800 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1801 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_BUFFER_SIZE
;
1805 if ( ctx
->dns_txt_callback(dns_txt_name
, dns_txt_reply
) != PDKIM_OK
1806 || dns_txt_reply
[0] == '\0')
1808 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1809 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE
;
1816 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1818 pdkim_quoteprint(dns_txt_reply
, strlen(dns_txt_reply
));
1821 if (!(sig
->pubkey
= pdkim_parse_pubkey_record(ctx
, dns_txt_reply
)))
1823 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1824 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD
;
1826 DEBUG(D_acl
) debug_printf(
1827 " Error while parsing public key record\n"
1828 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1832 DEBUG(D_acl
) debug_printf(
1833 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1835 /* Import public key */
1836 if ((errstr
= exim_rsa_verify_init(&sig
->pubkey
->key
, &vctx
)))
1838 DEBUG(D_acl
) debug_printf("verify_init: %s\n", errstr
);
1839 sig
->verify_status
= PDKIM_VERIFY_INVALID
;
1840 sig
->verify_ext_status
= PDKIM_VERIFY_INVALID_PUBKEY_IMPORT
;
1844 /* Check the signature */
1845 if ((errstr
= exim_rsa_verify(&vctx
, is_sha1
, &hhash
, &sig
->sigdata
)))
1847 DEBUG(D_acl
) debug_printf("headers verify: %s\n", errstr
);
1848 sig
->verify_status
= PDKIM_VERIFY_FAIL
;
1849 sig
->verify_ext_status
= PDKIM_VERIFY_FAIL_MESSAGE
;
1854 /* We have a winner! (if bodydhash was correct earlier) */
1855 if (sig
->verify_status
== PDKIM_VERIFY_NONE
)
1856 sig
->verify_status
= PDKIM_VERIFY_PASS
;
1862 debug_printf("PDKIM [%s] signature status: %s",
1863 sig
->domain
, pdkim_verify_status_str(sig
->verify_status
));
1864 if (sig
->verify_ext_status
> 0)
1865 debug_printf(" (%s)\n",
1866 pdkim_verify_ext_status_str(sig
->verify_ext_status
));
1872 free(dns_txt_reply
);
1878 /* If requested, set return pointer to signature(s) */
1879 if (return_signatures
)
1880 *return_signatures
= ctx
->sig
;
1886 /* -------------------------------------------------------------------------- */
1888 DLLEXPORT pdkim_ctx
*
1889 pdkim_init_verify(int(*dns_txt_callback
)(char *, char *))
1891 pdkim_ctx
*ctx
= malloc(sizeof(pdkim_ctx
));
1895 memset(ctx
, 0, sizeof(pdkim_ctx
));
1897 if (!(ctx
->linebuf
= malloc(PDKIM_MAX_BODY_LINE_LEN
)))
1903 ctx
->mode
= PDKIM_MODE_VERIFY
;
1904 ctx
->dns_txt_callback
= dns_txt_callback
;
1910 /* -------------------------------------------------------------------------- */
1912 DLLEXPORT pdkim_ctx
*
1913 pdkim_init_sign(char *domain
, char *selector
, char *rsa_privkey
, int algo
)
1916 pdkim_signature
*sig
;
1918 if (!domain
|| !selector
|| !rsa_privkey
)
1921 if (!(ctx
= malloc(sizeof(pdkim_ctx
))))
1923 memset(ctx
, 0, sizeof(pdkim_ctx
));
1925 if (!(ctx
->linebuf
= malloc(PDKIM_MAX_BODY_LINE_LEN
)))
1931 if (!(sig
= malloc(sizeof(pdkim_signature
))))
1937 memset(sig
, 0, sizeof(pdkim_signature
));
1939 sig
->bodylength
= -1;
1941 ctx
->mode
= PDKIM_MODE_SIGN
;
1944 sig
->domain
= strdup(domain
);
1945 sig
->selector
= strdup(selector
);
1946 sig
->rsa_privkey
= strdup(rsa_privkey
);
1949 if (!sig
->domain
|| !sig
->selector
|| !sig
->rsa_privkey
)
1952 exim_sha_init(&sig
->body_hash
, algo
== PDKIM_ALGO_RSA_SHA1
);
1956 pdkim_free_ctx(ctx
);
1961 /* -------------------------------------------------------------------------- */
1964 pdkim_set_optional(pdkim_ctx
*ctx
,
1970 unsigned long created
,
1971 unsigned long expires
)
1973 pdkim_signature
* sig
= ctx
->sig
;
1976 if (!(sig
->identity
= strdup(identity
)))
1977 return PDKIM_ERR_OOM
;
1979 if (!(sig
->sign_headers
= strdup(sign_headers
1980 ? sign_headers
: PDKIM_DEFAULT_SIGN_HEADERS
)))
1981 return PDKIM_ERR_OOM
;
1983 sig
->canon_headers
= canon_headers
;
1984 sig
->canon_body
= canon_body
;
1985 sig
->bodylength
= bodylength
;
1986 sig
->created
= created
;
1987 sig
->expires
= expires
;
2001 #endif /*DISABLE_DKIM*/