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