8463312b691a90306619ec7149e6ee232bddca96
[users/jgh/exim.git] / src / src / pdkim / pdkim.h
1 /* $Cambridge: exim/src/src/pdkim/pdkim.h,v 1.1.2.5 2009/03/17 12:57:37 tom Exp $ */
2 /* pdkim.h */
3
4 #include "sha1.h"
5 #include "sha2.h"
6 #include "rsa.h"
7 #include "base64.h"
8
9 #define PDKIM_SIGNATURE_VERSION     "1"
10 #define PDKIM_PUB_RECORD_VERSION    "DKIM1"
11
12 #define PDKIM_MAX_HEADER_LEN        65536
13 #define PDKIM_MAX_HEADERS           512
14 #define PDKIM_MAX_BODY_LINE_LEN     1024
15 #define PDKIM_DNS_TXT_MAX_NAMELEN   1024
16 #define PDKIM_DNS_TXT_MAX_RECLEN    4096
17 #define PDKIM_DEBUG
18 #define PDKIM_DEFAULT_SIGN_HEADERS "From:Sender:Reply-To:Subject:Date:"\
19                              "Message-ID:To:Cc:MIME-Version:Content-Type:"\
20                              "Content-Transfer-Encoding:Content-ID:"\
21                              "Content-Description:Resent-Date:Resent-From:"\
22                              "Resent-Sender:Resent-To:Resent-Cc:"\
23                              "Resent-Message-ID:In-Reply-To:References:"\
24                              "List-Id:List-Help:List-Unsubscribe:"\
25                              "List-Subscribe:List-Post:List-Owner:List-Archive"
26
27
28 /* Function success / error codes */
29 #define PDKIM_OK                      0
30 #define PDKIM_FAIL                   -1
31 #define PDKIM_ERR_OOM              -100
32 #define PDKIM_ERR_RSA_PRIVKEY      -101
33 #define PDKIM_ERR_RSA_SIGNING      -102
34 #define PDKIM_ERR_LONG_LINE        -103
35 #define PDKIM_ERR_BUFFER_TOO_SMALL -104
36
37 /* Main verification status */
38 #define PDKIM_VERIFY_NONE      0
39 #define PDKIM_VERIFY_INVALID   1
40 #define PDKIM_VERIFY_FAIL      2
41 #define PDKIM_VERIFY_PASS      3
42
43 /* Extended verification status */
44 #define PDKIM_VERIFY_FAIL_BODY    1
45 #define PDKIM_VERIFY_FAIL_MESSAGE 2
46
47 #define PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE 3
48 #define PDKIM_VERIFY_INVALID_BUFFER_SIZE        4
49 #define PDKIM_VERIFY_INVALID_PUBKEY_PARSING     5
50
51
52 #ifdef PDKIM_DEBUG
53 void pdkim_quoteprint(FILE *, char *, int, int);
54 #endif
55
56 typedef struct pdkim_stringlist {
57   char *value;
58   void *next;
59 } pdkim_stringlist;
60 pdkim_stringlist *pdkim_append_stringlist(pdkim_stringlist *, char *);
61
62
63 #define PDKIM_STR_ALLOC_FRAG 256
64 typedef struct pdkim_str {
65   char         *str;
66   unsigned int  len;
67   unsigned int  allocated;
68 } pdkim_str;
69 pdkim_str *pdkim_strnew (char *);
70 char      *pdkim_strcat (pdkim_str *, char *);
71 char      *pdkim_strncat(pdkim_str *, char *, int);
72 void       pdkim_strfree(pdkim_str *);
73
74 #define PDKIM_QUERYMETHOD_DNS_TXT 0
75
76 #define PDKIM_ALGO_RSA_SHA256     0
77 #define PDKIM_ALGO_RSA_SHA1       1
78
79 #define PDKIM_CANON_SIMPLE        0
80 #define PDKIM_CANON_RELAXED       1
81
82 #define PDKIM_HASH_SHA256         0
83 #define PDKIM_HASH_SHA1           1
84
85 #define PDKIM_KEYTYPE_RSA         0
86
87
88 /* -------------------------------------------------------------------------- */
89 /* Public key as (usually) fetched from DNS */
90 typedef struct pdkim_pubkey {
91   char *version;                  /* v=  */
92   char *granularity;              /* g=  */
93
94   char *hashes;                   /* h=  */
95   char *keytype;                  /* k=  */
96   char *srvtype;                  /* s=  */
97   char *notes;                    /* n=  */
98
99   char *key;                      /* p=  */
100   int   key_len;
101
102   int   testing;                  /* t=y */
103   int   no_subdomaining;          /* t=s */
104 } pdkim_pubkey;
105
106 /* -------------------------------------------------------------------------- */
107 /* Signature as it appears in a DKIM-Signature header */
108 typedef struct pdkim_signature {
109
110   /* Bits stored in a DKIM signature header --------------------------- */
111
112   /* (v=) The version, as an integer. Currently, always "1" */
113   int version;
114
115   /* (a=) The signature algorithm. Either PDKIM_ALGO_RSA_SHA256
116      or PDKIM_ALGO_RSA_SHA1 */
117   int algo;
118
119   /* (c=x/) Header canonicalization method. Either PDKIM_CANON_SIMPLE
120      or PDKIM_CANON_RELAXED */
121   int canon_headers;
122
123   /* (c=/x) Body canonicalization method. Either PDKIM_CANON_SIMPLE
124      or PDKIM_CANON_RELAXED */
125   int canon_body;
126
127   /* (q=) Query Method. Currently, only PDKIM_QUERYMETHOD_DNS_TXT
128      is specified */
129   int querymethod;
130
131   /* (s=) The selector string as given in the signature */
132   char *selector;
133
134   /* (d=) The domain as given in the signature */
135   char *domain;
136
137   /* (i=) The identity as given in the signature */
138   char *identity;
139
140   /* (t=) Timestamp of signature creation */
141   unsigned long created;
142
143   /* (x=) Timestamp of expiry of signature */
144   unsigned long expires;
145
146   /* (l=) Amount of hashed body bytes (after canonicalization) */
147   unsigned long bodylength;
148
149   /* (h=) Colon-separated list of header names that are included in the
150      signature */
151   char *headernames;
152
153   /* (z=) */
154   char *copiedheaders;
155
156   /* (b=) Decoded raw signature data, along with its length in bytes */
157   char *sigdata;
158   int   sigdata_len;
159
160   /* (bh=) Decoded raw body hash data, along with its length in bytes */
161   char *bodyhash;
162   int   bodyhash_len;
163
164   /* The main verification status. One of:
165
166      PDKIM_VERIFY_NONE      Verification was not attempted. This status
167                             should not appear.
168
169      PDKIM_VERIFY_INVALID   There was an error while trying to verify
170                             the signature. A more precise description
171                             is available in verify_ext_status.
172
173      PDKIM_VERIFY_FAIL      Verification failed because either the body
174                             hash did not match, or the signature verification
175                             failed. This probably means the message was
176                             modified. Check verify_ext_status for the
177                             exact reason.
178
179      PDKIM_VERIFY_PASS      Verification succeeded.
180   */
181   int verify_status;
182
183
184   /* Extended verification status. Depending on the value of verify_status,
185      it can contain:
186
187      For verify_status == PDKIM_VERIFY_INVALID:
188
189         PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE
190           Unable to retrieve a public key container.
191
192         PDKIM_VERIFY_INVALID_BUFFER_SIZE
193           Either the DNS name constructed to retrieve the public key record
194           does not fit into PDKIM_DNS_TXT_MAX_NAMELEN bytes, or the retrieved
195           record is longer than PDKIM_DNS_TXT_MAX_RECLEN bytes.
196
197         PDKIM_VERIFY_INVALID_PUBKEY_PARSING
198           (Syntax) error while parsing the retrieved public key record.
199
200
201      For verify_status == PDKIM_VERIFY_FAIL:
202
203         PDKIM_VERIFY_FAIL_BODY
204         PDKIM_VERIFY_FAIL_MESSAGE
205
206
207   */
208   int verify_ext_status;
209
210
211
212   pdkim_pubkey *pubkey;  /* Public key used to verify this signature.   */
213   void *next;            /* Pointer to next signature in list.          */
214
215   /* Per-signature helper variables ----------------------------------- */
216   sha1_context sha1_body;
217   sha2_context sha2_body;
218   unsigned long signed_body_bytes;
219   pdkim_stringlist *headers;
220   /* Signing specific ------------------------------------------------- */
221   char *rsa_privkey;     /* Private RSA key                             */
222   char *sign_headers;    /* To-be-signed header names                   */
223   /* Verification specific -------------------------------------------- */
224   int headernames_pos;   /* Current position in header name list        */
225   char *rawsig_no_b_val; /* Original signature header w/o b= tag value. */
226 } pdkim_signature;
227
228
229 /* -------------------------------------------------------------------------- */
230 /* Context to keep state between all operations */
231
232 #define PDKIM_MODE_SIGN     0
233 #define PDKIM_MODE_VERIFY   1
234 #define PDKIM_INPUT_NORMAL  0
235 #define PDKIM_INPUT_SMTP    1
236
237 typedef struct pdkim_ctx {
238
239   /* PDKIM_MODE_VERIFY or PDKIM_MODE_SIGN */
240   int mode;
241
242   /* PDKIM_INPUT_SMTP or PDKIM_INPUT_NORMAL */
243   int input_mode;
244
245   /* One (signing) or several chained (verification) signatures */
246   pdkim_signature *sig;
247
248   /* Callback for dns/txt query method (verification only) */
249   int(*dns_txt_callback)(char *, char *);
250
251   /* Coder's little helpers */
252   pdkim_str *cur_header;
253   char       linebuf[PDKIM_MAX_BODY_LINE_LEN];
254   int        linebuf_offset;
255   int        seen_lf;
256   int        seen_eod;
257   int        past_headers;
258   int        num_buffered_crlf;
259   int        num_headers;
260
261 #ifdef PDKIM_DEBUG
262   /* A FILE pointer. When not NULL, debug output will be generated
263     and sent to this stream */
264   FILE *debug_stream;
265 #endif
266
267 } pdkim_ctx;
268
269
270 int   header_name_match       (char *, char *, int);
271 char *pdkim_relax_header      (char *, int);
272
273 int   pdkim_update_bodyhash   (pdkim_ctx *, char *, int);
274 int   pdkim_finish_bodyhash   (pdkim_ctx *);
275
276 int   pdkim_bodyline_complete (pdkim_ctx *);
277 int   pdkim_header_complete   (pdkim_ctx *);
278
279 int   pdkim_feed              (pdkim_ctx *, char *, int);
280 int   pdkim_feed_finish       (pdkim_ctx *, char **);
281
282 char *pdkim_create_header     (pdkim_signature *, int);
283
284 pdkim_ctx
285      *pdkim_init_sign         (int, char *, char *, char *);
286
287 pdkim_ctx
288      *pdkim_init_verify       (int, int(*dns_txt_callback)(char *, char *));
289
290 int   pdkim_set_optional      (pdkim_ctx *,
291                                char *, char *,
292                                int, int,
293                                unsigned long, int,
294                                unsigned long,
295                                unsigned long);
296
297 void  pdkim_free_pubkey       (pdkim_pubkey *);
298 void  pdkim_free_sig          (pdkim_signature *);
299 void  pdkim_free_ctx          (pdkim_ctx *);
300
301
302 #ifdef PDKIM_DEBUG
303 void  pdkim_set_debug_stream  (pdkim_ctx *, FILE *);
304 #endif