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 /* String package: should be replaced by Exim standard ones */
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 */
218 pdkim_strnew (const char *cstr)
220 unsigned int len = cstr ? strlen(cstr) : 0;
221 pdkim_str *p = malloc(sizeof(pdkim_str));
224 memset(p, 0, sizeof(pdkim_str));
225 if (!(p->str = malloc(len+1)))
230 p->allocated = len+1;
233 strcpy(p->str, cstr);
235 p->str[p->len] = '\0';
240 pdkim_strncat(pdkim_str *str, const char *data, int len)
242 if ((str->allocated - str->len) < (len+1))
244 /* Extend the buffer */
245 int num_frags = ((len+1)/PDKIM_STR_ALLOC_FRAG)+1;
246 char *n = realloc(str->str,
247 (str->allocated+(num_frags*PDKIM_STR_ALLOC_FRAG)));
248 if (n == NULL) return NULL;
250 str->allocated += (num_frags*PDKIM_STR_ALLOC_FRAG);
252 strncpy(&(str->str[str->len]), data, len);
254 str->str[str->len] = '\0';
259 pdkim_strcat(pdkim_str *str, const char *cstr)
261 return pdkim_strncat(str, cstr, strlen(cstr));
265 pdkim_strtrim(pdkim_str *str)
269 while ( (*p != '\0') && ((*p == '\t') || (*p == ' ')) ) p++;
270 while (*p != '\0') {*q = *p; q++; p++;}
272 while ( (q != str->str) && ( (*q == '\0') || (*q == '\t') || (*q == ' ') ) )
277 str->len = strlen(str->str);
282 pdkim_strclear(pdkim_str *str)
290 pdkim_strfree(pdkim_str *str)
293 if (str->str) free(str->str);
299 /* -------------------------------------------------------------------------- */
302 pdkim_free_pubkey(pdkim_pubkey *pub)
306 if (pub->version ) free(pub->version);
307 if (pub->granularity) free(pub->granularity);
308 if (pub->hashes ) free(pub->hashes);
309 if (pub->keytype ) free(pub->keytype);
310 if (pub->srvtype ) free(pub->srvtype);
311 if (pub->notes ) free(pub->notes);
317 /* -------------------------------------------------------------------------- */
320 pdkim_free_sig(pdkim_signature *sig)
324 pdkim_signature *next = (pdkim_signature *)sig->next;
326 pdkim_stringlist *e = sig->headers;
329 pdkim_stringlist *c = e;
330 if (e->value) free(e->value);
335 if (sig->selector ) free(sig->selector);
336 if (sig->domain ) free(sig->domain);
337 if (sig->identity ) free(sig->identity);
338 if (sig->copiedheaders ) free(sig->copiedheaders);
339 if (sig->rsa_privkey ) free(sig->rsa_privkey);
340 if (sig->sign_headers ) free(sig->sign_headers);
341 if (sig->signature_header) free(sig->signature_header);
343 if (sig->pubkey) pdkim_free_pubkey(sig->pubkey);
346 if (next) pdkim_free_sig(next);
351 /* -------------------------------------------------------------------------- */
354 pdkim_free_ctx(pdkim_ctx *ctx)
358 pdkim_stringlist *e = ctx->headers;
361 pdkim_stringlist *c = e;
362 if (e->value) free(e->value);
366 pdkim_free_sig(ctx->sig);
367 pdkim_strfree(ctx->cur_header);
373 /* -------------------------------------------------------------------------- */
374 /* Matches the name of the passed raw "header" against
375 the passed colon-separated "list", starting at entry
376 "start". Returns the position of the header name in
380 header_name_match(const char *header,
390 /* Get header name */
391 char *hcolon = strchr(header, ':');
393 if (!hcolon) return rc; /* This isn't a header */
395 if (!(hname = malloc((hcolon-header)+1)))
396 return PDKIM_ERR_OOM;
397 memset(hname, 0, (hcolon-header)+1);
398 strncpy(hname, header, (hcolon-header));
400 /* Copy tick-off list locally, so we can punch zeroes into it */
401 if (!(lcopy = strdup(tick)))
404 return PDKIM_ERR_OOM;
412 if (strcasecmp(p, hname) == 0)
415 /* Invalidate header name instance in tick-off list */
416 if (do_tick) tick[p-lcopy] = '_';
424 if (strcasecmp(p, hname) == 0)
427 /* Invalidate header name instance in tick-off list */
428 if (do_tick) tick[p-lcopy] = '_';
438 /* -------------------------------------------------------------------------- */
439 /* Performs "relaxed" canonicalization of a header. The returned pointer needs
443 pdkim_relax_header (char *header, int crlf)
445 BOOL past_field_name = FALSE;
446 BOOL seen_wsp = FALSE;
449 char *relaxed = malloc(strlen(header)+3);
451 if (!relaxed) return NULL;
454 for (p = header; *p != '\0'; p++)
458 if (c == '\r' || c == '\n')
460 if (c == '\t' || c == ' ')
464 c = ' '; /* Turns WSP into SP */
468 if (!past_field_name && c == ':')
470 if (seen_wsp) q--; /* This removes WSP before the colon */
471 seen_wsp = TRUE; /* This removes WSP after the colon */
472 past_field_name = TRUE;
477 /* Lowercase header name */
478 if (!past_field_name) c = tolower(c);
482 if (q > relaxed && q[-1] == ' ') q--; /* Squash eventual trailing SP */
485 if (crlf) strcat(relaxed, "\r\n");
490 /* -------------------------------------------------------------------------- */
491 #define PDKIM_QP_ERROR_DECODE -1
494 pdkim_decode_qp_char(char *qp_p, int *c)
496 char *initial_pos = qp_p;
498 /* Advance one char */
501 /* Check for two hex digits and decode them */
502 if (isxdigit(*qp_p) && isxdigit(qp_p[1]))
504 /* Do hex conversion */
505 *c = (isdigit(*qp_p) ? *qp_p - '0' : toupper(*qp_p) - 'A' + 10) << 4;
506 *c |= isdigit(qp_p[1]) ? qp_p[1] - '0' : toupper(qp_p[1]) - 'A' + 10;
510 /* Illegal char here */
511 *c = PDKIM_QP_ERROR_DECODE;
516 /* -------------------------------------------------------------------------- */
519 pdkim_decode_qp(char *str)
524 char *n = malloc(strlen(p)+1);
534 p = pdkim_decode_qp_char(p, &nchar);
550 /* -------------------------------------------------------------------------- */
553 pdkim_decode_base64(uschar *str, blob * b)
557 dlen = b64decode(str, &b->data);
558 if (dlen < 0) b->data = NULL;
562 /* -------------------------------------------------------------------------- */
565 pdkim_encode_base64(blob * b)
568 int old_pool = store_pool;
570 store_pool = POOL_PERM;
571 ret = CS b64encode(b->data, b->len);
572 store_pool = old_pool;
577 /* -------------------------------------------------------------------------- */
578 #define PDKIM_HDR_LIMBO 0
579 #define PDKIM_HDR_TAG 1
580 #define PDKIM_HDR_VALUE 2
582 static pdkim_signature *
583 pdkim_parse_sig_header(pdkim_ctx *ctx, char *raw_hdr)
585 pdkim_signature *sig ;
587 pdkim_str *cur_tag = NULL;
588 pdkim_str *cur_val = NULL;
589 BOOL past_hname = FALSE;
590 BOOL in_b_val = FALSE;
591 int where = PDKIM_HDR_LIMBO;
593 int old_pool = store_pool;
595 /* There is a store-reset between header & body reception
596 so cannot use the main pool. Any allocs done by Exim
597 memory-handling must use the perm pool. */
599 store_pool = POOL_PERM;
601 if (!(sig = malloc(sizeof(pdkim_signature)))) return NULL;
602 memset(sig, 0, sizeof(pdkim_signature));
603 sig->bodylength = -1;
605 if (!(sig->rawsig_no_b_val = malloc(strlen(raw_hdr)+1)))
611 q = sig->rawsig_no_b_val;
613 for (p = raw_hdr; ; p++)
618 if (c == '\r' || c == '\n')
621 /* Fast-forward through header name */
624 if (c == ':') past_hname = TRUE;
628 if (where == PDKIM_HDR_LIMBO)
630 /* In limbo, just wait for a tag-char to appear */
631 if (!(c >= 'a' && c <= 'z'))
634 where = PDKIM_HDR_TAG;
637 if (where == PDKIM_HDR_TAG)
640 cur_tag = pdkim_strnew(NULL);
642 if (c >= 'a' && c <= 'z')
643 pdkim_strncat(cur_tag, p, 1);
647 if (strcmp(cur_tag->str, "b") == 0)
652 where = PDKIM_HDR_VALUE;
657 if (where == PDKIM_HDR_VALUE)
660 cur_val = pdkim_strnew(NULL);
662 if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
665 if (c == ';' || c == '\0')
667 if (cur_tag->len > 0)
669 pdkim_strtrim(cur_val);
671 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag->str, cur_val->str);
673 switch (cur_tag->str[0])
676 if (cur_tag->str[1] == 'h')
677 pdkim_decode_base64(US cur_val->str, &sig->bodyhash);
679 pdkim_decode_base64(US cur_val->str, &sig->sigdata);
682 /* We only support version 1, and that is currently the
683 only version there is. */
684 if (strcmp(cur_val->str, PDKIM_SIGNATURE_VERSION) == 0)
688 for (i = 0; pdkim_algos[i]; i++)
689 if (strcmp(cur_val->str, pdkim_algos[i]) == 0)
696 for (i = 0; pdkim_combined_canons[i].str; i++)
697 if (strcmp(cur_val->str, pdkim_combined_canons[i].str) == 0)
699 sig->canon_headers = pdkim_combined_canons[i].canon_headers;
700 sig->canon_body = pdkim_combined_canons[i].canon_body;
705 for (i = 0; pdkim_querymethods[i]; i++)
706 if (strcmp(cur_val->str, pdkim_querymethods[i]) == 0)
708 sig->querymethod = i;
713 sig->selector = strdup(cur_val->str); break;
715 sig->domain = strdup(cur_val->str); break;
717 sig->identity = pdkim_decode_qp(cur_val->str); break;
719 sig->created = strtoul(cur_val->str, NULL, 10); break;
721 sig->expires = strtoul(cur_val->str, NULL, 10); break;
723 sig->bodylength = strtol(cur_val->str, NULL, 10); break;
725 sig->headernames = string_copy(cur_val->str); break;
727 sig->copiedheaders = pdkim_decode_qp(cur_val->str); break;
729 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
733 pdkim_strclear(cur_tag);
734 pdkim_strclear(cur_val);
736 where = PDKIM_HDR_LIMBO;
739 pdkim_strncat(cur_val, p, 1);
750 store_pool = old_pool;
752 /* Make sure the most important bits are there. */
753 if (!(sig->domain && (*(sig->domain) != '\0') &&
754 sig->selector && (*(sig->selector) != '\0') &&
755 sig->headernames && (*(sig->headernames) != '\0') &&
763 /* Chomp raw header. The final newline must not be added to the signature. */
765 while (q > sig->rawsig_no_b_val && (*q == '\r' || *q == '\n'))
766 *q = '\0'; q--; /*XXX questionable code layout; possible bug */
771 "PDKIM >> Raw signature w/o b= tag value >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
772 pdkim_quoteprint(sig->rawsig_no_b_val, strlen(sig->rawsig_no_b_val));
774 "PDKIM >> Sig size: %4d bits\n", sig->sigdata.len*8);
776 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
779 exim_sha_init(&sig->body_hash, sig->algo == PDKIM_ALGO_RSA_SHA1);
784 /* -------------------------------------------------------------------------- */
786 static pdkim_pubkey *
787 pdkim_parse_pubkey_record(pdkim_ctx *ctx, char *raw_record)
791 pdkim_str *cur_tag = NULL;
792 pdkim_str *cur_val = NULL;
793 int where = PDKIM_HDR_LIMBO;
795 if (!(pub = malloc(sizeof(pdkim_pubkey)))) return NULL;
796 memset(pub, 0, sizeof(pdkim_pubkey));
798 for (p = raw_record; ; p++)
803 if (c == '\r' || c == '\n')
806 if (where == PDKIM_HDR_LIMBO)
808 /* In limbo, just wait for a tag-char to appear */
809 if (!(c >= 'a' && c <= 'z'))
812 where = PDKIM_HDR_TAG;
815 if (where == PDKIM_HDR_TAG)
818 cur_tag = pdkim_strnew(NULL);
820 if (c >= 'a' && c <= 'z')
821 pdkim_strncat(cur_tag, p, 1);
825 where = PDKIM_HDR_VALUE;
830 if (where == PDKIM_HDR_VALUE)
833 cur_val = pdkim_strnew(NULL);
835 if (c == '\r' || c == '\n')
838 if (c == ';' || c == '\0')
840 if (cur_tag->len > 0)
842 pdkim_strtrim(cur_val);
843 DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag->str, cur_val->str);
845 switch (cur_tag->str[0])
848 /* This tag isn't evaluated because:
849 - We only support version DKIM1.
850 - Which is the default for this value (set below)
851 - Other versions are currently not specified. */
854 pub->hashes = strdup(cur_val->str); break;
856 pub->granularity = strdup(cur_val->str); break;
858 pub->notes = pdkim_decode_qp(cur_val->str); break;
860 pdkim_decode_base64(US cur_val->str, &pub->key);
863 pub->hashes = strdup(cur_val->str); break;
865 pub->srvtype = strdup(cur_val->str); break;
867 if (strchr(cur_val->str, 'y') != NULL) pub->testing = 1;
868 if (strchr(cur_val->str, 's') != NULL) pub->no_subdomaining = 1;
871 DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
875 pdkim_strclear(cur_tag);
876 pdkim_strclear(cur_val);
877 where = PDKIM_HDR_LIMBO;
880 pdkim_strncat(cur_val, p, 1);
884 if (c == '\0') break;
887 /* Set fallback defaults */
888 if (!pub->version ) pub->version = strdup(PDKIM_PUB_RECORD_VERSION);
889 if (!pub->granularity) pub->granularity = strdup("*");
890 if (!pub->keytype ) pub->keytype = strdup("rsa");
891 if (!pub->srvtype ) pub->srvtype = strdup("*");
897 pdkim_free_pubkey(pub);
902 /* -------------------------------------------------------------------------- */
905 pdkim_update_bodyhash(pdkim_ctx *ctx, const char *data, int len)
907 pdkim_signature *sig = ctx->sig;
908 /* Cache relaxed version of data */
909 char *relaxed_data = NULL;
912 /* Traverse all signatures, updating their hashes. */
915 /* Defaults to simple canon (no further treatment necessary) */
916 const char *canon_data = data;
919 if (sig->canon_body == PDKIM_CANON_RELAXED)
921 /* Relax the line if not done already */
924 BOOL seen_wsp = FALSE;
928 if (!(relaxed_data = malloc(len+1)))
929 return PDKIM_ERR_OOM;
931 for (p = data; *p; p++)
936 if (q > 0 && relaxed_data[q-1] == ' ')
939 else if (c == '\t' || c == ' ')
941 c = ' '; /* Turns WSP into SP */
948 relaxed_data[q++] = c;
950 relaxed_data[q] = '\0';
953 canon_data = relaxed_data;
954 canon_len = relaxed_len;
957 /* Make sure we don't exceed the to-be-signed body length */
958 if ( sig->bodylength >= 0
959 && sig->signed_body_bytes + (unsigned long)canon_len > sig->bodylength
961 canon_len = sig->bodylength - sig->signed_body_bytes;
965 exim_sha_update(&sig->body_hash, canon_data, canon_len);
966 sig->signed_body_bytes += canon_len;
967 DEBUG(D_acl) pdkim_quoteprint(canon_data, canon_len);
973 if (relaxed_data) free(relaxed_data);
978 /* -------------------------------------------------------------------------- */
981 pdkim_finish_bodyhash(pdkim_ctx *ctx)
983 pdkim_signature *sig;
985 /* Traverse all signatures */
986 for (sig = ctx->sig; sig; sig = sig->next)
987 { /* Finish hashes */
990 exim_sha_finish(&sig->body_hash, &bh);
994 debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
995 "PDKIM [%s] bh computed: ",
996 sig->domain, sig->signed_body_bytes, sig->domain);
997 pdkim_hexprint(CS bh.data, bh.len);
1000 /* SIGNING -------------------------------------------------------------- */
1001 if (ctx->mode == PDKIM_MODE_SIGN)
1005 /* If bodylength limit is set, and we have received less bytes
1006 than the requested amount, effectively remove the limit tag. */
1007 if (sig->signed_body_bytes < sig->bodylength)
1008 sig->bodylength = -1;
1011 /* VERIFICATION --------------------------------------------------------- */
1014 /* Compare bodyhash */
1015 if (memcmp(bh.data, sig->bodyhash.data, bh.len) == 0)
1017 DEBUG(D_acl) debug_printf("PDKIM [%s] Body hash verified OK\n", sig->domain);
1023 debug_printf("PDKIM [%s] bh signature: ", sig->domain);
1024 pdkim_hexprint(sig->bodyhash.data,
1025 exim_sha_hashlen(&sig->body_hash));
1026 debug_printf("PDKIM [%s] Body hash did NOT verify\n", sig->domain);
1028 sig->verify_status = PDKIM_VERIFY_FAIL;
1029 sig->verify_ext_status = PDKIM_VERIFY_FAIL_BODY;
1039 /* -------------------------------------------------------------------------- */
1040 /* Callback from pdkim_feed below for processing complete body lines */
1043 pdkim_bodyline_complete(pdkim_ctx *ctx)
1045 char *p = ctx->linebuf;
1046 int n = ctx->linebuf_offset;
1047 pdkim_signature *sig = ctx->sig; /*XXX assumes only one sig */
1049 /* Ignore extra data if we've seen the end-of-data marker */
1050 if (ctx->seen_eod) goto BAIL;
1052 /* We've always got one extra byte to stuff a zero ... */
1053 ctx->linebuf[ctx->linebuf_offset] = '\0';
1055 /* Terminate on EOD marker */
1056 if (memcmp(p, ".\r\n", 3) == 0)
1058 /* In simple body mode, if any empty lines were buffered,
1059 replace with one. rfc 4871 3.4.3 */
1060 /*XXX checking the signed-body-bytes is a gross hack; I think
1061 it indicates that all linebreaks should be buffered, including
1062 the one terminating a text line */
1063 if ( sig && sig->canon_body == PDKIM_CANON_SIMPLE
1064 && sig->signed_body_bytes == 0
1065 && ctx->num_buffered_crlf > 0
1067 pdkim_update_bodyhash(ctx, "\r\n", 2);
1069 ctx->seen_eod = TRUE;
1073 if (memcmp(p, "..", 2) == 0)
1079 /* Empty lines need to be buffered until we find a non-empty line */
1080 if (memcmp(p, "\r\n", 2) == 0)
1082 ctx->num_buffered_crlf++;
1086 if (sig && sig->canon_body == PDKIM_CANON_RELAXED)
1088 /* Lines with just spaces need to be buffered too */
1090 while (memcmp(check, "\r\n", 2) != 0)
1094 if (c != '\t' && c != ' ')
1099 ctx->num_buffered_crlf++;
1104 /* At this point, we have a non-empty line, so release the buffered ones. */
1105 while (ctx->num_buffered_crlf)
1107 pdkim_update_bodyhash(ctx, "\r\n", 2);
1108 ctx->num_buffered_crlf--;
1111 pdkim_update_bodyhash(ctx, p, n);
1114 ctx->linebuf_offset = 0;
1119 /* -------------------------------------------------------------------------- */
1120 /* Callback from pdkim_feed below for processing complete headers */
1121 #define DKIM_SIGNATURE_HEADERNAME "DKIM-Signature:"
1124 pdkim_header_complete(pdkim_ctx *ctx)
1126 /* Special case: The last header can have an extra \r appended */
1127 if ( (ctx->cur_header->len > 1) &&
1128 (ctx->cur_header->str[(ctx->cur_header->len)-1] == '\r') )
1130 ctx->cur_header->str[(ctx->cur_header->len)-1] = '\0';
1131 ctx->cur_header->len--;
1135 if (ctx->num_headers > PDKIM_MAX_HEADERS) goto BAIL;
1137 /* SIGNING -------------------------------------------------------------- */
1138 if (ctx->mode == PDKIM_MODE_SIGN)
1140 pdkim_signature *sig;
1142 for (sig = ctx->sig; sig; sig = sig->next) /* Traverse all signatures */
1143 if (header_name_match(ctx->cur_header->str,
1146 PDKIM_DEFAULT_SIGN_HEADERS, 0) == PDKIM_OK)
1148 pdkim_stringlist *list;
1150 /* Add header to the signed headers list (in reverse order) */
1151 if (!(list = pdkim_prepend_stringlist(sig->headers,
1152 ctx->cur_header->str)))
1153 return PDKIM_ERR_OOM;
1154 sig->headers = list;
1158 /* VERIFICATION ----------------------------------------------------------- */
1159 /* DKIM-Signature: headers are added to the verification list */
1160 if (ctx->mode == PDKIM_MODE_VERIFY)
1162 if (strncasecmp(ctx->cur_header->str,
1163 DKIM_SIGNATURE_HEADERNAME,
1164 strlen(DKIM_SIGNATURE_HEADERNAME)) == 0)
1166 pdkim_signature *new_sig;
1168 /* Create and chain new signature block */
1169 DEBUG(D_acl) debug_printf(
1170 "PDKIM >> Found sig, trying to parse >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1172 if ((new_sig = pdkim_parse_sig_header(ctx, ctx->cur_header->str)))
1174 pdkim_signature *last_sig = ctx->sig;
1179 while (last_sig->next) last_sig = last_sig->next;
1180 last_sig->next = new_sig;
1184 DEBUG(D_acl) debug_printf(
1185 "Error while parsing signature header\n"
1186 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1189 /* every other header is stored for signature verification */
1192 pdkim_stringlist *list;
1194 if (!(list = pdkim_prepend_stringlist(ctx->headers, ctx->cur_header->str)))
1195 return PDKIM_ERR_OOM;
1196 ctx->headers = list;
1201 pdkim_strclear(ctx->cur_header); /* Re-use existing pdkim_str */
1207 /* -------------------------------------------------------------------------- */
1208 #define HEADER_BUFFER_FRAG_SIZE 256
1211 pdkim_feed (pdkim_ctx *ctx, char *data, int len)
1215 for (p = 0; p<len; p++)
1219 if (ctx->past_headers)
1221 /* Processing body byte */
1222 ctx->linebuf[ctx->linebuf_offset++] = c;
1225 int rc = pdkim_bodyline_complete(ctx); /* End of line */
1226 if (rc != PDKIM_OK) return rc;
1228 if (ctx->linebuf_offset == (PDKIM_MAX_BODY_LINE_LEN-1))
1229 return PDKIM_ERR_LONG_LINE;
1233 /* Processing header byte */
1240 int rc = pdkim_header_complete(ctx); /* Seen last header line */
1241 if (rc != PDKIM_OK) return rc;
1243 ctx->past_headers = TRUE;
1245 DEBUG(D_acl) debug_printf(
1246 "PDKIM >> Hashed body data, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
1250 ctx->seen_lf = TRUE;
1252 else if (ctx->seen_lf)
1254 if (!(c == '\t' || c == ' '))
1256 int rc = pdkim_header_complete(ctx); /* End of header */
1257 if (rc != PDKIM_OK) return rc;
1259 ctx->seen_lf = FALSE;
1263 if (!ctx->cur_header)
1264 if (!(ctx->cur_header = pdkim_strnew(NULL)))
1265 return PDKIM_ERR_OOM;
1267 if (ctx->cur_header->len < PDKIM_MAX_HEADER_LEN)
1268 if (!pdkim_strncat(ctx->cur_header, &data[p], 1))
1269 return PDKIM_ERR_OOM;
1276 * RFC 5322 specifies that header line length SHOULD be no more than 78
1281 * col: this int holds and receives column number (octets since last '\n')
1282 * str: partial string to append to
1283 * pad: padding, split line or space after before or after eg: ";"
1284 * intro: - must join to payload eg "h=", usually the tag name
1285 * payload: eg base64 data - long data can be split arbitrarily.
1287 * this code doesn't fold the header in some of the places that RFC4871
1288 * allows: As per RFC5322(2.2.3) it only folds before or after tag-value
1289 * pairs and inside long values. it also always spaces or breaks after the
1292 * no guarantees are made for output given out-of range input. like tag
1293 * names longer than 78, or bogus col. Input is assumed to be free of line breaks.
1297 pdkim_headcat(int *col, pdkim_str *str, const char * pad,
1298 const char *intro, const char *payload)
1307 pdkim_strcat(str, "\r\n\t");
1310 pdkim_strncat(str, pad, l);
1314 l = (pad?1:0) + (intro?strlen(intro):0);
1317 { /*can't fit intro - start a new line to make room.*/
1318 pdkim_strcat(str, "\r\n\t");
1320 l = intro?strlen(intro):0;
1323 l += payload ? strlen(payload):0 ;
1326 { /* this fragment will not fit on a single line */
1329 pdkim_strcat(str, " ");
1331 pad = NULL; /* only want this once */
1337 size_t sl = strlen(intro);
1339 pdkim_strncat(str, intro, sl);
1342 intro = NULL; /* only want this once */
1347 size_t sl = strlen(payload);
1348 size_t chomp = *col+sl < 77 ? sl : 78-*col;
1350 pdkim_strncat(str, payload, chomp);
1356 /* the while precondition tells us it didn't fit. */
1357 pdkim_strcat(str, "\r\n\t");
1363 pdkim_strcat(str, "\r\n\t");
1370 pdkim_strcat(str, " ");
1377 size_t sl = strlen(intro);
1379 pdkim_strncat(str, intro, sl);
1387 size_t sl = strlen(payload);
1389 pdkim_strncat(str, payload, sl);
1397 /* -------------------------------------------------------------------------- */
1400 pdkim_create_header(pdkim_signature *sig, BOOL final)
1403 char *base64_bh = NULL;
1404 char *base64_b = NULL;
1407 pdkim_str *canon_all;
1409 if (!(hdr = pdkim_strnew("DKIM-Signature: v="PDKIM_SIGNATURE_VERSION)))
1412 if (!(canon_all = pdkim_strnew(pdkim_canons[sig->canon_headers])))
1415 if (!(base64_bh = pdkim_encode_base64(&sig->bodyhash)))
1418 col = strlen(hdr->str);
1420 /* Required and static bits */
1421 if ( pdkim_headcat(&col, hdr, ";", "a=", pdkim_algos[sig->algo])
1422 && pdkim_headcat(&col, hdr, ";", "q=", pdkim_querymethods[sig->querymethod])
1423 && pdkim_strcat(canon_all, "/")
1424 && pdkim_strcat(canon_all, pdkim_canons[sig->canon_body])
1425 && pdkim_headcat(&col, hdr, ";", "c=", canon_all->str)
1426 && pdkim_headcat(&col, hdr, ";", "d=", sig->domain)
1427 && pdkim_headcat(&col, hdr, ";", "s=", sig->selector)
1430 /* list of header names can be split between items. */
1432 char *n = CS string_copy(sig->headernames);
1440 char *c = strchr(n, ':');
1445 if (!pdkim_headcat(&col, hdr, NULL, NULL, ":"))
1448 if (!pdkim_headcat(&col, hdr, s, i, n))
1460 if(!pdkim_headcat(&col, hdr, ";", "bh=", base64_bh))
1465 if(!pdkim_headcat(&col, hdr, ";", "i=", sig->identity))
1468 if (sig->created > 0)
1472 snprintf(minibuf, 20, "%lu", sig->created);
1473 if(!pdkim_headcat(&col, hdr, ";", "t=", minibuf))
1477 if (sig->expires > 0)
1481 snprintf(minibuf, 20, "%lu", sig->expires);
1482 if(!pdkim_headcat(&col, hdr, ";", "x=", minibuf))
1486 if (sig->bodylength >= 0)
1490 snprintf(minibuf, 20, "%lu", sig->bodylength);
1491 if(!pdkim_headcat(&col, hdr, ";", "l=", minibuf))
1495 /* Preliminary or final version? */
1498 if (!(base64_b = pdkim_encode_base64(&sig->sigdata)))
1500 if (!pdkim_headcat(&col, hdr, ";", "b=", base64_b))
1504 if(!pdkim_headcat(&col, hdr, ";", "b=", ""))
1507 /* add trailing semicolon: I'm not sure if this is actually needed */
1508 if (!pdkim_headcat(&col, hdr, NULL, ";", ""))
1512 rc = strdup(hdr->str);
1516 if (canon_all) pdkim_strfree(canon_all);
1521 /* -------------------------------------------------------------------------- */
1524 pdkim_feed_finish(pdkim_ctx *ctx, pdkim_signature **return_signatures)
1526 pdkim_signature *sig = ctx->sig;
1527 pdkim_str *headernames = NULL; /* Collected signed header names */
1529 /* Check if we must still flush a (partial) header. If that is the
1530 case, the message has no body, and we must compute a body hash
1531 out of '<CR><LF>' */
1532 if (ctx->cur_header && ctx->cur_header->len)
1534 int rc = pdkim_header_complete(ctx);
1535 if (rc != PDKIM_OK) return rc;
1536 pdkim_update_bodyhash(ctx, "\r\n", 2);
1539 DEBUG(D_acl) debug_printf(
1540 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1542 /* Build (and/or evaluate) body hash */
1543 if (pdkim_finish_bodyhash(ctx) != PDKIM_OK)
1544 return PDKIM_ERR_OOM;
1546 /* SIGNING -------------------------------------------------------------- */
1547 if (ctx->mode == PDKIM_MODE_SIGN)
1548 if (!(headernames = pdkim_strnew(NULL)))
1549 return PDKIM_ERR_OOM;
1550 /* ---------------------------------------------------------------------- */
1554 BOOL is_sha1 = sig->algo == PDKIM_ALGO_RSA_SHA1;
1559 int hdata_alloc = 0;
1564 exim_sha_init(&hhash_ctx, is_sha1);
1566 DEBUG(D_acl) debug_printf(
1567 "PDKIM >> Hashed header data, canonicalized, in sequence >>>>>>>>>>>>>>\n");
1569 /* SIGNING ---------------------------------------------------------------- */
1570 /* When signing, walk through our header list and add them to the hash. As we
1571 go, construct a list of the header's names to use for the h= parameter. */
1573 if (ctx->mode == PDKIM_MODE_SIGN)
1575 pdkim_stringlist *p;
1577 for (p = sig->headers; p; p = p->next)
1580 /* Collect header names (Note: colon presence is guaranteed here) */
1581 uschar * q = Ustrchr(p->value, ':');
1583 if (!(pdkim_strncat(headernames, p->value,
1584 (q-US (p->value)) + (p->next ? 1 : 0))))
1585 return PDKIM_ERR_OOM;
1587 rh = sig->canon_headers == PDKIM_CANON_RELAXED
1588 ? US pdkim_relax_header(p->value, 1) /* cook header for relaxed canon */
1589 : string_copy(p->value); /* just copy it for simple canon */
1591 return PDKIM_ERR_OOM;
1593 /* Feed header to the hash algorithm */
1594 exim_sha_update(&hhash_ctx, rh, strlen(rh));
1596 /* Remember headers block for signing (when the library cannot do incremental) */
1597 (void) exim_rsa_data_append(&hdata, &hdata_alloc, rh);
1599 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1603 /* VERIFICATION ----------------------------------------------------------- */
1604 /* When verifying, walk through the header name list in the h= parameter and
1605 add the headers to the hash in that order. */
1608 uschar * b = string_copy(sig->headernames);
1611 pdkim_stringlist * hdrs;
1613 if (!b) return PDKIM_ERR_OOM;
1616 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1621 if ((q = Ustrchr(p, ':')))
1624 for (hdrs = ctx->headers; hdrs; hdrs = hdrs->next)
1626 && strncasecmp(hdrs->value, CS p, Ustrlen(p)) == 0
1627 && (hdrs->value)[Ustrlen(p)] == ':'
1630 uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
1631 ? US pdkim_relax_header(hdrs->value, 1) /* cook header for relaxed canon */
1632 : string_copy(hdrs->value); /* just copy it for simple canon */
1634 return PDKIM_ERR_OOM;
1636 /* Feed header to the hash algorithm */
1637 exim_sha_update(&hhash_ctx, rh, strlen(rh));
1639 DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1649 DEBUG(D_acl) debug_printf(
1650 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1652 /* SIGNING ---------------------------------------------------------------- */
1653 if (ctx->mode == PDKIM_MODE_SIGN)
1655 /* Copy headernames to signature struct */
1656 sig->headernames = string_copy(US headernames->str);
1657 pdkim_strfree(headernames);
1659 /* Create signature header with b= omitted */
1660 sig_hdr = pdkim_create_header(ctx->sig, FALSE);
1663 /* VERIFICATION ----------------------------------------------------------- */
1665 sig_hdr = strdup(sig->rawsig_no_b_val);
1666 /* ------------------------------------------------------------------------ */
1669 return PDKIM_ERR_OOM;
1671 /* Relax header if necessary */
1672 if (sig->canon_headers == PDKIM_CANON_RELAXED)
1674 char *relaxed_hdr = pdkim_relax_header(sig_hdr, 0);
1678 return PDKIM_ERR_OOM;
1679 sig_hdr = relaxed_hdr;
1685 "PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>\n");
1686 pdkim_quoteprint(sig_hdr, strlen(sig_hdr));
1688 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1691 /* Finalize header hash */
1692 exim_sha_update(&hhash_ctx, sig_hdr, strlen(sig_hdr));
1693 exim_sha_finish(&hhash_ctx, &hhash);
1697 debug_printf("PDKIM [%s] hh computed: ", sig->domain);
1698 pdkim_hexprint(hhash.data, hhash.len);
1701 /* Remember headers block for signing (when the library cannot do incremental) */
1702 if (ctx->mode == PDKIM_MODE_SIGN)
1703 (void) exim_rsa_data_append(&hdata, &hdata_alloc, sig_hdr);
1707 /* SIGNING ---------------------------------------------------------------- */
1708 if (ctx->mode == PDKIM_MODE_SIGN)
1711 const uschar * errstr;
1713 /* Import private key */
1714 if ((errstr = exim_rsa_signing_init(sig->rsa_privkey, &sctx)))
1716 DEBUG(D_acl) debug_printf("signing_init: %s\n", errstr);
1717 return PDKIM_ERR_RSA_PRIVKEY;
1720 /* Do signing. With OpenSSL we are signing the hash of headers just
1721 calculated, with GnuTLS we have to sign an entire block of headers
1722 (due to available interfaces) and it recalculates the hash internally. */
1724 #if defined(RSA_OPENSSL) || defined(RSA_GCRYPT)
1728 if ((errstr = exim_rsa_sign(&sctx, is_sha1, &hdata, &sig->sigdata)))
1730 DEBUG(D_acl) debug_printf("signing: %s\n", errstr);
1731 return PDKIM_ERR_RSA_SIGNING;
1736 debug_printf( "PDKIM [%s] b computed: ", sig->domain);
1737 pdkim_hexprint(sig->sigdata.data, sig->sigdata.len);
1740 if (!(sig->signature_header = pdkim_create_header(ctx->sig, TRUE)))
1741 return PDKIM_ERR_OOM;
1744 /* VERIFICATION ----------------------------------------------------------- */
1748 const uschar * errstr;
1750 char *dns_txt_name, *dns_txt_reply;
1752 /* Fetch public key for signing domain, from DNS */
1754 if (!(dns_txt_name = malloc(PDKIM_DNS_TXT_MAX_NAMELEN)))
1755 return PDKIM_ERR_OOM;
1757 if (!(dns_txt_reply = malloc(PDKIM_DNS_TXT_MAX_RECLEN)))
1760 return PDKIM_ERR_OOM;
1763 memset(dns_txt_reply, 0, PDKIM_DNS_TXT_MAX_RECLEN);
1764 memset(dns_txt_name , 0, PDKIM_DNS_TXT_MAX_NAMELEN);
1766 if (snprintf(dns_txt_name, PDKIM_DNS_TXT_MAX_NAMELEN,
1767 "%s._domainkey.%s.",
1768 sig->selector, sig->domain) >= PDKIM_DNS_TXT_MAX_NAMELEN)
1770 sig->verify_status = PDKIM_VERIFY_INVALID;
1771 sig->verify_ext_status = PDKIM_VERIFY_INVALID_BUFFER_SIZE;
1775 if ( ctx->dns_txt_callback(dns_txt_name, dns_txt_reply) != PDKIM_OK
1776 || dns_txt_reply[0] == '\0')
1778 sig->verify_status = PDKIM_VERIFY_INVALID;
1779 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE;
1786 "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
1788 pdkim_quoteprint(dns_txt_reply, strlen(dns_txt_reply));
1791 if (!(sig->pubkey = pdkim_parse_pubkey_record(ctx, dns_txt_reply)))
1793 sig->verify_status = PDKIM_VERIFY_INVALID;
1794 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD;
1796 DEBUG(D_acl) debug_printf(
1797 " Error while parsing public key record\n"
1798 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1802 DEBUG(D_acl) debug_printf(
1803 "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
1805 /* Import public key */
1806 if ((errstr = exim_rsa_verify_init(&sig->pubkey->key, &vctx)))
1808 DEBUG(D_acl) debug_printf("verify_init: %s\n", errstr);
1809 sig->verify_status = PDKIM_VERIFY_INVALID;
1810 sig->verify_ext_status = PDKIM_VERIFY_INVALID_PUBKEY_IMPORT;
1814 /* Check the signature */
1815 if ((errstr = exim_rsa_verify(&vctx, is_sha1, &hhash, &sig->sigdata)))
1817 DEBUG(D_acl) debug_printf("headers verify: %s\n", errstr);
1818 sig->verify_status = PDKIM_VERIFY_FAIL;
1819 sig->verify_ext_status = PDKIM_VERIFY_FAIL_MESSAGE;
1824 /* We have a winner! (if bodydhash was correct earlier) */
1825 if (sig->verify_status == PDKIM_VERIFY_NONE)
1826 sig->verify_status = PDKIM_VERIFY_PASS;
1832 debug_printf("PDKIM [%s] signature status: %s",
1833 sig->domain, pdkim_verify_status_str(sig->verify_status));
1834 if (sig->verify_ext_status > 0)
1835 debug_printf(" (%s)\n",
1836 pdkim_verify_ext_status_str(sig->verify_ext_status));
1842 free(dns_txt_reply);
1848 /* If requested, set return pointer to signature(s) */
1849 if (return_signatures)
1850 *return_signatures = ctx->sig;
1856 /* -------------------------------------------------------------------------- */
1858 DLLEXPORT pdkim_ctx *
1859 pdkim_init_verify(int(*dns_txt_callback)(char *, char *))
1861 pdkim_ctx *ctx = malloc(sizeof(pdkim_ctx));
1865 memset(ctx, 0, sizeof(pdkim_ctx));
1867 if (!(ctx->linebuf = malloc(PDKIM_MAX_BODY_LINE_LEN)))
1873 ctx->mode = PDKIM_MODE_VERIFY;
1874 ctx->dns_txt_callback = dns_txt_callback;
1880 /* -------------------------------------------------------------------------- */
1882 DLLEXPORT pdkim_ctx *
1883 pdkim_init_sign(char *domain, char *selector, char *rsa_privkey, int algo)
1886 pdkim_signature *sig;
1888 if (!domain || !selector || !rsa_privkey)
1891 if (!(ctx = malloc(sizeof(pdkim_ctx))))
1893 memset(ctx, 0, sizeof(pdkim_ctx));
1895 if (!(ctx->linebuf = malloc(PDKIM_MAX_BODY_LINE_LEN)))
1901 if (!(sig = malloc(sizeof(pdkim_signature))))
1907 memset(sig, 0, sizeof(pdkim_signature));
1909 sig->bodylength = -1;
1911 ctx->mode = PDKIM_MODE_SIGN;
1914 sig->domain = strdup(domain);
1915 sig->selector = strdup(selector);
1916 sig->rsa_privkey = strdup(rsa_privkey);
1919 if (!sig->domain || !sig->selector || !sig->rsa_privkey)
1922 exim_sha_init(&sig->body_hash, algo == PDKIM_ALGO_RSA_SHA1);
1926 pdkim_free_ctx(ctx);
1931 /* -------------------------------------------------------------------------- */
1934 pdkim_set_optional(pdkim_ctx *ctx,
1940 unsigned long created,
1941 unsigned long expires)
1944 if (!(ctx->sig->identity = strdup(identity)))
1945 return PDKIM_ERR_OOM;
1948 if (!(ctx->sig->sign_headers = strdup(sign_headers)))
1949 return PDKIM_ERR_OOM;
1951 ctx->sig->canon_headers = canon_headers;
1952 ctx->sig->canon_body = canon_body;
1953 ctx->sig->bodylength = bodylength;
1954 ctx->sig->created = created;
1955 ctx->sig->expires = expires;
1969 #endif /*DISABLE_DKIM*/