1 /*-
2  * Copyright 2016 Vsevolod Stakhov
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #ifndef DKIM_H_
17 #define DKIM_H_
18 
19 #include "config.h"
20 #include "contrib/libev/ev.h"
21 #include "dns.h"
22 #include "ref.h"
23 
24 
25 /* Main types and definitions */
26 
27 #define RSPAMD_DKIM_SIGNHEADER     "DKIM-Signature"
28 #define RSPAMD_DKIM_ARC_SIGNHEADER     "ARC-Message-Signature"
29 #define RSPAMD_DKIM_ARC_AUTHHEADER     "ARC-Authentication-Results"
30 #define RSPAMD_DKIM_ARC_SEALHEADER     "ARC-Seal"
31 /* DKIM signature header */
32 
33 
34 /* Errors (from OpenDKIM) */
35 
36 #define DKIM_SIGERROR_UNKNOWN       (-1)    /* unknown error */
37 #define DKIM_SIGERROR_OK        0   /* no error */
38 #define DKIM_SIGERROR_VERSION       1   /* unsupported version */
39 #define DKIM_SIGERROR_DOMAIN        2   /* invalid domain (d=/i=) */
40 #define DKIM_SIGERROR_EXPIRED       3   /* signature expired */
41 #define DKIM_SIGERROR_FUTURE        4   /* signature in the future */
42 #define DKIM_SIGERROR_TIMESTAMPS    5   /* x= < t= */
43 #define DKIM_SIGERROR_NOREC         6   /* No record */
44 #define DKIM_SIGERROR_INVALID_HC    7   /* c= invalid (header) */
45 #define DKIM_SIGERROR_INVALID_BC    8   /* c= invalid (body) */
46 #define DKIM_SIGERROR_MISSING_A     9   /* a= missing */
47 #define DKIM_SIGERROR_INVALID_A     10  /* a= invalid */
48 #define DKIM_SIGERROR_MISSING_H     11  /* h= missing */
49 #define DKIM_SIGERROR_INVALID_L     12  /* l= invalid */
50 #define DKIM_SIGERROR_INVALID_Q     13  /* q= invalid */
51 #define DKIM_SIGERROR_INVALID_QO    14  /* q= option invalid */
52 #define DKIM_SIGERROR_MISSING_D     15  /* d= missing */
53 #define DKIM_SIGERROR_EMPTY_D       16  /* d= empty */
54 #define DKIM_SIGERROR_MISSING_S     17  /* s= missing */
55 #define DKIM_SIGERROR_EMPTY_S       18  /* s= empty */
56 #define DKIM_SIGERROR_MISSING_B     19  /* b= missing */
57 #define DKIM_SIGERROR_EMPTY_B       20  /* b= empty */
58 #define DKIM_SIGERROR_CORRUPT_B     21  /* b= corrupt */
59 #define DKIM_SIGERROR_NOKEY     22  /* no key found in DNS */
60 #define DKIM_SIGERROR_DNSSYNTAX     23  /* DNS reply corrupt */
61 #define DKIM_SIGERROR_KEYFAIL       24  /* DNS query failed */
62 #define DKIM_SIGERROR_MISSING_BH    25  /* bh= missing */
63 #define DKIM_SIGERROR_EMPTY_BH      26  /* bh= empty */
64 #define DKIM_SIGERROR_CORRUPT_BH    27  /* bh= corrupt */
65 #define DKIM_SIGERROR_BADSIG        28  /* signature mismatch */
66 #define DKIM_SIGERROR_SUBDOMAIN     29  /* unauthorized subdomain */
67 #define DKIM_SIGERROR_MULTIREPLY    30  /* multiple records returned */
68 #define DKIM_SIGERROR_EMPTY_H       31  /* h= empty */
69 #define DKIM_SIGERROR_INVALID_H     32  /* h= missing req'd entries */
70 #define DKIM_SIGERROR_TOOLARGE_L    33  /* l= value exceeds body size */
71 #define DKIM_SIGERROR_MBSFAILED     34  /* "must be signed" failure */
72 #define DKIM_SIGERROR_KEYVERSION    35  /* unknown key version */
73 #define DKIM_SIGERROR_KEYUNKNOWNHASH    36  /* unknown key hash */
74 #define DKIM_SIGERROR_KEYHASHMISMATCH   37  /* sig-key hash mismatch */
75 #define DKIM_SIGERROR_NOTEMAILKEY   38  /* not an e-mail key */
76 #define DKIM_SIGERROR_UNUSED2       39  /* OBSOLETE */
77 #define DKIM_SIGERROR_KEYTYPEMISSING    40  /* key type missing */
78 #define DKIM_SIGERROR_KEYTYPEUNKNOWN    41  /* key type unknown */
79 #define DKIM_SIGERROR_KEYREVOKED    42  /* key revoked */
80 #define DKIM_SIGERROR_KEYDECODE     43  /* key couldn't be decoded */
81 #define DKIM_SIGERROR_MISSING_V     44  /* v= tag missing */
82 #define DKIM_SIGERROR_EMPTY_V       45  /* v= tag empty */
83 
84 #ifdef  __cplusplus
85 extern "C" {
86 #endif
87 
88 /* Check results */
89 enum rspamd_dkim_check_rcode {
90 	DKIM_CONTINUE = 0,
91 	DKIM_REJECT,
92 	DKIM_TRYAGAIN,
93 	DKIM_NOTFOUND,
94 	DKIM_RECORD_ERROR,
95 	DKIM_PERM_ERROR,
96 };
97 
98 #define DKIM_CANON_SIMPLE   0   /* as specified in DKIM spec */
99 #define DKIM_CANON_RELAXED  1   /* as specified in DKIM spec */
100 
101 struct rspamd_dkim_context_s;
102 typedef struct rspamd_dkim_context_s rspamd_dkim_context_t;
103 
104 struct rspamd_dkim_sign_context_s;
105 typedef struct rspamd_dkim_sign_context_s rspamd_dkim_sign_context_t;
106 
107 struct rspamd_dkim_key_s;
108 typedef struct rspamd_dkim_key_s rspamd_dkim_key_t;
109 typedef struct rspamd_dkim_key_s rspamd_dkim_sign_key_t;
110 
111 struct rspamd_task;
112 
113 enum rspamd_dkim_key_format {
114 	RSPAMD_DKIM_KEY_FILE = 0,
115 	RSPAMD_DKIM_KEY_PEM,
116 	RSPAMD_DKIM_KEY_BASE64,
117 	RSPAMD_DKIM_KEY_RAW,
118 	RSPAMD_DKIM_KEY_UNKNOWN
119 };
120 
121 enum rspamd_dkim_type {
122 	RSPAMD_DKIM_NORMAL,
123 	RSPAMD_DKIM_ARC_SIG,
124 	RSPAMD_DKIM_ARC_SEAL
125 };
126 
127 /* Signature methods */
128 enum rspamd_sign_type {
129 	DKIM_SIGN_UNKNOWN = -2,
130 	DKIM_SIGN_RSASHA1 = 0,
131 	DKIM_SIGN_RSASHA256,
132 	DKIM_SIGN_RSASHA512,
133 	DKIM_SIGN_ECDSASHA256,
134 	DKIM_SIGN_ECDSASHA512,
135 	DKIM_SIGN_EDDSASHA256,
136 };
137 
138 enum rspamd_dkim_key_type {
139 	RSPAMD_DKIM_KEY_RSA = 0,
140 	RSPAMD_DKIM_KEY_ECDSA,
141 	RSPAMD_DKIM_KEY_EDDSA
142 };
143 
144 struct rspamd_dkim_check_result {
145 	enum rspamd_dkim_check_rcode rcode;
146 	rspamd_dkim_context_t *ctx;
147 	/* Processed parts */
148 	const gchar *selector;
149 	const gchar *domain;
150 	const gchar *short_b;
151 	const gchar *fail_reason;
152 };
153 
154 
155 /* Err MUST be freed if it is not NULL, key is allocated by slice allocator */
156 typedef void (*dkim_key_handler_f) (rspamd_dkim_key_t *key, gsize keylen,
157 									rspamd_dkim_context_t *ctx, gpointer ud, GError *err);
158 
159 /**
160  * Create new dkim context from signature
161  * @param sig message's signature
162  * @param pool pool to allocate memory from
163  * @param time_jitter jitter in seconds to allow time diff while checking
164  * @param err pointer to error object
165  * @return new context or NULL
166  */
167 rspamd_dkim_context_t *rspamd_create_dkim_context (const gchar *sig,
168 												   rspamd_mempool_t *pool,
169 												   struct rspamd_dns_resolver *resolver,
170 												   guint time_jitter,
171 												   enum rspamd_dkim_type type,
172 												   GError **err);
173 
174 /**
175  * Create new dkim context for making a signature
176  * @param task
177  * @param priv_key
178  * @param err
179  * @return
180  */
181 rspamd_dkim_sign_context_t *rspamd_create_dkim_sign_context (struct rspamd_task *task,
182 															 rspamd_dkim_sign_key_t *priv_key,
183 															 gint headers_canon,
184 															 gint body_canon,
185 															 const gchar *dkim_headers,
186 															 enum rspamd_dkim_type type,
187 															 GError **err);
188 
189 /**
190  * Load dkim key
191  * @param path
192  * @param err
193  * @return
194  */
195 rspamd_dkim_sign_key_t *rspamd_dkim_sign_key_load (const gchar *what, gsize len,
196 												   enum rspamd_dkim_key_format type,
197 												   GError **err);
198 
199 /**
200  * Invalidate modified sign key
201  * @param key
202  * @return
203 */
204 gboolean rspamd_dkim_sign_key_maybe_invalidate (rspamd_dkim_sign_key_t *key,
205 												time_t mtime);
206 
207 /**
208  * Make DNS request for specified context and obtain and parse key
209  * @param ctx dkim context from signature
210  * @param resolver dns resolver object
211  * @param s async session to make request
212  * @return
213  */
214 gboolean rspamd_get_dkim_key (rspamd_dkim_context_t *ctx,
215 							  struct rspamd_task *task,
216 							  dkim_key_handler_f handler,
217 							  gpointer ud);
218 
219 /**
220  * Check task for dkim context using dkim key
221  * @param ctx dkim verify context
222  * @param key dkim key (from cache or from dns request)
223  * @param task task to check
224  * @return
225  */
226 struct rspamd_dkim_check_result *rspamd_dkim_check (rspamd_dkim_context_t *ctx,
227 													rspamd_dkim_key_t *key,
228 													struct rspamd_task *task);
229 
230 struct rspamd_dkim_check_result *
231 rspamd_dkim_create_result (rspamd_dkim_context_t *ctx,
232 						   enum rspamd_dkim_check_rcode rcode,
233 						   struct rspamd_task *task);
234 
235 GString *rspamd_dkim_sign (struct rspamd_task *task,
236 						   const gchar *selector,
237 						   const gchar *domain,
238 						   time_t expire,
239 						   gsize len,
240 						   guint idx,
241 						   const gchar *arc_cv,
242 						   rspamd_dkim_sign_context_t *ctx);
243 
244 rspamd_dkim_key_t *rspamd_dkim_key_ref (rspamd_dkim_key_t *k);
245 
246 void rspamd_dkim_key_unref (rspamd_dkim_key_t *k);
247 
248 rspamd_dkim_sign_key_t *rspamd_dkim_sign_key_ref (rspamd_dkim_sign_key_t *k);
249 
250 void rspamd_dkim_sign_key_unref (rspamd_dkim_sign_key_t *k);
251 
252 const gchar *rspamd_dkim_get_domain (rspamd_dkim_context_t *ctx);
253 
254 const gchar *rspamd_dkim_get_selector (rspamd_dkim_context_t *ctx);
255 
256 const gchar *rspamd_dkim_get_dns_key (rspamd_dkim_context_t *ctx);
257 
258 guint rspamd_dkim_key_get_ttl (rspamd_dkim_key_t *k);
259 
260 /**
261  * Create DKIM public key from a raw data
262  * @param keydata
263  * @param keylen
264  * @param type
265  * @param err
266  * @return
267  */
268 rspamd_dkim_key_t *rspamd_dkim_make_key (const gchar *keydata, guint keylen,
269 										 enum rspamd_dkim_key_type type,
270 										 GError **err);
271 
272 #define RSPAMD_DKIM_KEY_ID_LEN 16
273 /**
274  * Returns key id for dkim key (raw md5 of RSPAMD_DKIM_KEY_ID_LEN)
275  * NOT ZERO TERMINATED, use RSPAMD_DKIM_KEY_ID_LEN for length
276  * @param key
277  * @return
278  */
279 const guchar *rspamd_dkim_key_id (rspamd_dkim_key_t *key);
280 
281 /**
282  * Parse DKIM public key from a TXT record
283  * @param txt
284  * @param keylen
285  * @param err
286  * @return
287  */
288 rspamd_dkim_key_t *rspamd_dkim_parse_key (const gchar *txt, gsize *keylen,
289 										  GError **err);
290 
291 /**
292  * Canonocalise header using relaxed algorithm
293  * @param hname
294  * @param hvalue
295  * @param out
296  * @param outlen
297  * @return
298  */
299 goffset rspamd_dkim_canonize_header_relaxed_str (const gchar *hname,
300 												 const gchar *hvalue,
301 												 gchar *out,
302 												 gsize outlen);
303 
304 /**
305  * Checks public and private keys for match
306  * @param pk
307  * @param sk
308  * @param err
309  * @return
310  */
311 gboolean rspamd_dkim_match_keys (rspamd_dkim_key_t *pk,
312 								 rspamd_dkim_sign_key_t *sk,
313 								 GError **err);
314 
315 /**
316  * Free DKIM key
317  * @param key
318  */
319 void rspamd_dkim_key_free (rspamd_dkim_key_t *key);
320 
321 #ifdef  __cplusplus
322 }
323 #endif
324 
325 #endif /* DKIM_H_ */
326