wip
[users/jgh/exim.git] / src / src / dkim.c
1 /* $Cambridge: exim/src/src/dkim.c,v 1.1.2.1 2009/02/24 15:57:55 tom Exp $ */
2
3 /*************************************************
4 *     Exim - an Internet mail transport agent    *
5 *************************************************/
6
7 /* Copyright (c) University of Cambridge 2009 */
8 /* See the file NOTICE for conditions of use and distribution. */
9
10 /* Code for DKIM support. Other DKIM relevant code is in
11    receive.c, transport.c and transports/smtp.c */
12
13 #include "exim.h"
14
15 #ifndef DISABLE_DKIM
16
17 #include "pdkim/pdkim.h"
18
19 uschar *dkim_exim_sign(int dkim_fd,
20                        uschar *dkim_private_key,
21                        uschar *dkim_domain,
22                        uschar *dkim_selector,
23                        uschar *dkim_canon,
24                        uschar *dkim_sign_headers) {
25   pdkim_ctx *ctx = NULL;
26   uschar *rc = NULL;
27   char *signature;
28   int pdkim_canon;
29   int sread;
30   char buf[4096];
31   int save_errno = 0;
32
33   dkim_domain = expand_string(dkim_domain);
34   if (dkim_domain == NULL) {
35     /* expansion error, do not send message. */
36     log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
37           "dkim_domain: %s", expand_string_message);
38     rc = NULL;
39     goto CLEANUP;
40   }
41   /* Set up $dkim_domain expansion variable. */
42   dkim_signing_domain = dkim_domain;
43
44   /* Get selector to use. */
45   dkim_selector = expand_string(dkim_selector);
46   if (dkim_selector == NULL) {
47     log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
48       "dkim_selector: %s", expand_string_message);
49     rc = NULL;
50     goto CLEANUP;
51   }
52   /* Set up $dkim_selector expansion variable. */
53   dkim_signing_selector = dkim_selector;
54
55   /* Get canonicalization to use */
56   dkim_canon = expand_string(dkim_canon?dkim_canon:US"relaxed");
57   if (dkim_canon == NULL) {
58     /* expansion error, do not send message. */
59     log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
60           "dkim_canon: %s", expand_string_message);
61     rc = NULL;
62     goto CLEANUP;
63   }
64   if (Ustrcmp(dkim_canon, "relaxed") == 0)
65     pdkim_canon = PDKIM_CANON_RELAXED;
66   else if (Ustrcmp(dkim_canon, "simple") == 0)
67     pdkim_canon = PDKIM_CANON_RELAXED;
68   else {
69     log_write(0, LOG_MAIN, "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",dkim_canon);
70     pdkim_canon = PDKIM_CANON_RELAXED;
71   }
72
73   /* Expand signing headers once */
74   if (dkim_sign_headers != NULL) {
75     dkim_sign_headers = expand_string(dkim_sign_headers);
76     if (dkim_sign_headers == NULL) {
77       log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
78         "dkim_sign_headers: %s", expand_string_message);
79       rc = NULL;
80       goto CLEANUP;
81     }
82   }
83   dkim_exim_sign_headers = dkim_sign_headers;
84
85   /* Get private key to use. */
86   dkim_private_key = expand_string(dkim_private_key);
87   if (dkim_private_key == NULL) {
88     log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
89       "dkim_private_key: %s", expand_string_message);
90     rc = NULL;
91     goto CLEANUP;
92   }
93   if ( (Ustrlen(dkim_private_key) == 0) ||
94        (Ustrcmp(dkim_private_key,"0") == 0) ||
95        (Ustrcmp(dkim_private_key,"false") == 0) ) {
96     /* don't sign, but no error */
97     rc = US"";
98     goto CLEANUP;
99   }
100
101   if (dkim_private_key[0] == '/') {
102     int privkey_fd = 0;
103     /* Looks like a filename, load the private key. */
104     memset(big_buffer,0,big_buffer_size);
105     privkey_fd = open(CS dkim_private_key,O_RDONLY);
106     (void)read(privkey_fd,big_buffer,16383);
107     (void)close(privkey_fd);
108     dkim_private_key = big_buffer;
109   }
110
111   ctx = pdkim_init_sign((char *)dkim_signing_domain,
112                         (char *)dkim_signing_selector,
113                         dkim_private_key
114                        );
115
116   pdkim_set_debug_stream(ctx,debug_file);
117
118   pdkim_set_optional(ctx,
119                      PDKIM_INPUT_SMTP,
120                      (char *)dkim_exim_sign_headers,
121                      NULL,
122                      pdkim_canon,
123                      pdkim_canon,
124                      0,
125                      PDKIM_ALGO_RSA_SHA1,
126                      0,
127                      0);
128
129   while((sread = read(dkim_fd,&buf,4096)) > 0) {
130     if (pdkim_feed(ctx,buf,sread) != PDKIM_OK) {
131       rc = NULL;
132       goto CLEANUP;
133     }
134   }
135   /* Handle failed read above. */
136   if (sread == -1) {
137     debug_printf("DKIM: Error reading -K file.\n");
138     save_errno = errno;
139     rc = NULL;
140     goto CLEANUP;
141   }
142
143   if (pdkim_feed_finish(ctx,&signature) != PDKIM_OK)
144     goto CLEANUP;
145
146   rc = store_get(strlen(signature)+3);
147   Ustrcpy(rc,US signature);
148   Ustrcat(rc,US"\r\n");
149
150   CLEANUP:
151   if (ctx != NULL) {
152     pdkim_free_ctx(ctx);
153   }
154   store_pool = old_pool;
155   errno = save_errno;
156   return rc;
157 };
158
159 #endif