diff options
Diffstat (limited to 'src/libserver/dkim.h')
-rw-r--r-- | src/libserver/dkim.h | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/src/libserver/dkim.h b/src/libserver/dkim.h new file mode 100644 index 0000000..50703da --- /dev/null +++ b/src/libserver/dkim.h @@ -0,0 +1,298 @@ +/*- + * Copyright 2016 Vsevolod Stakhov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef DKIM_H_ +#define DKIM_H_ + +#include "config.h" +#include "contrib/libev/ev.h" +#include "dns.h" +#include "ref.h" + + +/* Main types and definitions */ + +#define RSPAMD_DKIM_SIGNHEADER "DKIM-Signature" +#define RSPAMD_DKIM_ARC_SIGNHEADER "ARC-Message-Signature" +#define RSPAMD_DKIM_ARC_AUTHHEADER "ARC-Authentication-Results" +#define RSPAMD_DKIM_ARC_SEALHEADER "ARC-Seal" +/* DKIM signature header */ + + +/* Errors (from OpenDKIM) */ + +#define DKIM_SIGERROR_UNKNOWN (-1) /* unknown error */ +#define DKIM_SIGERROR_VERSION 1 /* unsupported version */ +#define DKIM_SIGERROR_EXPIRED 3 /* signature expired */ +#define DKIM_SIGERROR_FUTURE 4 /* signature in the future */ +#define DKIM_SIGERROR_NOREC 6 /* No record */ +#define DKIM_SIGERROR_INVALID_HC 7 /* c= invalid (header) */ +#define DKIM_SIGERROR_INVALID_BC 8 /* c= invalid (body) */ +#define DKIM_SIGERROR_INVALID_A 10 /* a= invalid */ +#define DKIM_SIGERROR_INVALID_L 12 /* l= invalid */ +#define DKIM_SIGERROR_EMPTY_D 16 /* d= empty */ +#define DKIM_SIGERROR_EMPTY_S 18 /* s= empty */ +#define DKIM_SIGERROR_EMPTY_B 20 /* b= empty */ +#define DKIM_SIGERROR_NOKEY 22 /* no key found in DNS */ +#define DKIM_SIGERROR_KEYFAIL 24 /* DNS query failed */ +#define DKIM_SIGERROR_EMPTY_BH 26 /* bh= empty */ +#define DKIM_SIGERROR_BADSIG 28 /* signature mismatch */ +#define DKIM_SIGERROR_EMPTY_H 31 /* h= empty */ +#define DKIM_SIGERROR_INVALID_H 32 /* h= missing req'd entries */ +#define DKIM_SIGERROR_KEYHASHMISMATCH 37 /* sig-key hash mismatch */ +#define DKIM_SIGERROR_EMPTY_V 45 /* v= tag empty */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Check results */ +enum rspamd_dkim_check_rcode { + DKIM_CONTINUE = 0, + DKIM_REJECT, + DKIM_TRYAGAIN, + DKIM_NOTFOUND, + DKIM_RECORD_ERROR, + DKIM_PERM_ERROR, +}; + +#define DKIM_CANON_SIMPLE 0 /* as specified in DKIM spec */ +#define DKIM_CANON_RELAXED 1 /* as specified in DKIM spec */ + +struct rspamd_dkim_context_s; +typedef struct rspamd_dkim_context_s rspamd_dkim_context_t; + +struct rspamd_dkim_sign_context_s; +typedef struct rspamd_dkim_sign_context_s rspamd_dkim_sign_context_t; + +struct rspamd_dkim_key_s; +typedef struct rspamd_dkim_key_s rspamd_dkim_key_t; +typedef struct rspamd_dkim_key_s rspamd_dkim_sign_key_t; + +struct rspamd_task; + +enum rspamd_dkim_key_format { + RSPAMD_DKIM_KEY_FILE = 0, + RSPAMD_DKIM_KEY_PEM, + RSPAMD_DKIM_KEY_BASE64, + RSPAMD_DKIM_KEY_RAW, + RSPAMD_DKIM_KEY_UNKNOWN +}; + +enum rspamd_dkim_type { + RSPAMD_DKIM_NORMAL, + RSPAMD_DKIM_ARC_SIG, + RSPAMD_DKIM_ARC_SEAL +}; + +/* Signature methods */ +enum rspamd_sign_type { + DKIM_SIGN_UNKNOWN = -2, + DKIM_SIGN_RSASHA1 = 0, + DKIM_SIGN_RSASHA256, + DKIM_SIGN_RSASHA512, + DKIM_SIGN_ECDSASHA256, + DKIM_SIGN_ECDSASHA512, + DKIM_SIGN_EDDSASHA256, +}; + +enum rspamd_dkim_key_type { + RSPAMD_DKIM_KEY_RSA = 0, + RSPAMD_DKIM_KEY_ECDSA, + RSPAMD_DKIM_KEY_EDDSA +}; + +struct rspamd_dkim_check_result { + enum rspamd_dkim_check_rcode rcode; + rspamd_dkim_context_t *ctx; + /* Processed parts */ + const gchar *selector; + const gchar *domain; + const gchar *short_b; + const gchar *fail_reason; +}; + + +/* Err MUST be freed if it is not NULL, key is allocated by slice allocator */ +typedef void (*dkim_key_handler_f)(rspamd_dkim_key_t *key, gsize keylen, + rspamd_dkim_context_t *ctx, gpointer ud, GError *err); + +/** + * Create new dkim context from signature + * @param sig message's signature + * @param pool pool to allocate memory from + * @param time_jitter jitter in seconds to allow time diff while checking + * @param err pointer to error object + * @return new context or NULL + */ +rspamd_dkim_context_t *rspamd_create_dkim_context(const gchar *sig, + rspamd_mempool_t *pool, + struct rspamd_dns_resolver *resolver, + guint time_jitter, + enum rspamd_dkim_type type, + GError **err); + +/** + * Create new dkim context for making a signature + * @param task + * @param priv_key + * @param err + * @return + */ +rspamd_dkim_sign_context_t *rspamd_create_dkim_sign_context(struct rspamd_task *task, + rspamd_dkim_sign_key_t *priv_key, + gint headers_canon, + gint body_canon, + const gchar *dkim_headers, + enum rspamd_dkim_type type, + GError **err); + +/** + * Load dkim key + * @param path + * @param err + * @return + */ +rspamd_dkim_sign_key_t *rspamd_dkim_sign_key_load(const gchar *what, gsize len, + enum rspamd_dkim_key_format type, + GError **err); + +/** + * Invalidate modified sign key + * @param key + * @return +*/ +gboolean rspamd_dkim_sign_key_maybe_invalidate(rspamd_dkim_sign_key_t *key, + time_t mtime); + +/** + * Make DNS request for specified context and obtain and parse key + * @param ctx dkim context from signature + * @param resolver dns resolver object + * @param s async session to make request + * @return + */ +gboolean rspamd_get_dkim_key(rspamd_dkim_context_t *ctx, + struct rspamd_task *task, + dkim_key_handler_f handler, + gpointer ud); + +/** + * Check task for dkim context using dkim key + * @param ctx dkim verify context + * @param key dkim key (from cache or from dns request) + * @param task task to check + * @return + */ +struct rspamd_dkim_check_result *rspamd_dkim_check(rspamd_dkim_context_t *ctx, + rspamd_dkim_key_t *key, + struct rspamd_task *task); + +struct rspamd_dkim_check_result * +rspamd_dkim_create_result(rspamd_dkim_context_t *ctx, + enum rspamd_dkim_check_rcode rcode, + struct rspamd_task *task); + +GString *rspamd_dkim_sign(struct rspamd_task *task, + const gchar *selector, + const gchar *domain, + time_t expire, + gsize len, + guint idx, + const gchar *arc_cv, + rspamd_dkim_sign_context_t *ctx); + +rspamd_dkim_key_t *rspamd_dkim_key_ref(rspamd_dkim_key_t *k); + +void rspamd_dkim_key_unref(rspamd_dkim_key_t *k); + +rspamd_dkim_sign_key_t *rspamd_dkim_sign_key_ref(rspamd_dkim_sign_key_t *k); + +void rspamd_dkim_sign_key_unref(rspamd_dkim_sign_key_t *k); + +const gchar *rspamd_dkim_get_domain(rspamd_dkim_context_t *ctx); + +const gchar *rspamd_dkim_get_selector(rspamd_dkim_context_t *ctx); + +const gchar *rspamd_dkim_get_dns_key(rspamd_dkim_context_t *ctx); + +guint rspamd_dkim_key_get_ttl(rspamd_dkim_key_t *k); + +/** + * Create DKIM public key from a raw data + * @param keydata + * @param keylen + * @param type + * @param err + * @return + */ +rspamd_dkim_key_t *rspamd_dkim_make_key(const gchar *keydata, guint keylen, + enum rspamd_dkim_key_type type, + GError **err); + +#define RSPAMD_DKIM_KEY_ID_LEN 16 +/** + * Returns key id for dkim key (raw md5 of RSPAMD_DKIM_KEY_ID_LEN) + * NOT ZERO TERMINATED, use RSPAMD_DKIM_KEY_ID_LEN for length + * @param key + * @return + */ +const guchar *rspamd_dkim_key_id(rspamd_dkim_key_t *key); + +/** + * Parse DKIM public key from a TXT record + * @param txt + * @param keylen + * @param err + * @return + */ +rspamd_dkim_key_t *rspamd_dkim_parse_key(const gchar *txt, gsize *keylen, + GError **err); + +/** + * Canonicalise header using relaxed algorithm + * @param hname + * @param hvalue + * @param out + * @param outlen + * @return + */ +goffset rspamd_dkim_canonize_header_relaxed_str(const gchar *hname, + const gchar *hvalue, + gchar *out, + gsize outlen); + +/** + * Checks public and private keys for match + * @param pk + * @param sk + * @param err + * @return + */ +gboolean rspamd_dkim_match_keys(rspamd_dkim_key_t *pk, + rspamd_dkim_sign_key_t *sk, + GError **err); + +/** + * Free DKIM key + * @param key + */ +void rspamd_dkim_key_free(rspamd_dkim_key_t *key); + +#ifdef __cplusplus +} +#endif + +#endif /* DKIM_H_ */ |