From: Vsevolod Stakhov Date: Wed, 6 Jun 2018 07:58:20 +0000 (+0100) Subject: [Feature] Support ED25519 DKIM signatures X-Git-Tag: 1.7.6~51 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=573f8cd97a5f24949977b856b0108844b5bacf88;p=rspamd.git [Feature] Support ED25519 DKIM signatures --- diff --git a/src/libserver/dkim.c b/src/libserver/dkim.c index 5af61daf7..4aaa74a3b 100644 --- a/src/libserver/dkim.c +++ b/src/libserver/dkim.c @@ -65,12 +65,14 @@ enum rspamd_sign_type { DKIM_SIGN_RSASHA256, DKIM_SIGN_RSASHA512, DKIM_SIGN_ECDSASHA256, - DKIM_SIGN_ECDSASHA512 + DKIM_SIGN_ECDSASHA512, + DKIM_SIGN_EDDSASHA256, }; enum rspamd_dkim_key_type { RSPAMD_DKIM_KEY_RSA = 0, - RSPAMD_DKIM_KEY_ECDSA + RSPAMD_DKIM_KEY_ECDSA, + RSPAMD_DKIM_KEY_EDDSA }; #define RSPAMD_DKIM_MAX_ARC_IDX 10 @@ -152,6 +154,7 @@ struct rspamd_dkim_key_s { union { RSA *key_rsa; EC_KEY *key_ecdsa; + guchar *key_eddsa; } key; enum rspamd_dkim_key_type type; BIO *key_bio; @@ -315,6 +318,12 @@ rspamd_dkim_parse_signalg (rspamd_dkim_context_t * ctx, return TRUE; } } + else if (len == sizeof ("ed25519") - 1) { + if (memcmp (param, "ed25519", len) == 0) { + ctx->sig_alg = DKIM_SIGN_EDDSASHA256; + return TRUE; + } + } g_set_error (err, DKIM_ERROR, @@ -1219,7 +1228,10 @@ rspamd_dkim_make_key (rspamd_dkim_context_t *ctx, const gchar *keydata, rspamd_dkim_key_t *key = NULL; if (keylen < 3) { - msg_err_dkim ("DKIM key is too short to be valid"); + g_set_error (err, + DKIM_ERROR, + DKIM_SIGERROR_KEYFAIL, + "DKIM key is too short to be valid"); return NULL; } @@ -1233,55 +1245,71 @@ rspamd_dkim_make_key (rspamd_dkim_context_t *ctx, const gchar *keydata, rspamd_cryptobox_base64_decode (keydata, keylen, key->keydata, &key->decoded_len); - key->key_bio = BIO_new_mem_buf (key->keydata, key->decoded_len); + if (key->type == RSPAMD_DKIM_KEY_EDDSA) { + key->key.key_eddsa = key->keydata; - if (key->key_bio == NULL) { - g_set_error (err, - DKIM_ERROR, - DKIM_SIGERROR_KEYFAIL, - "cannot make ssl bio from key"); - REF_RELEASE (key); - - return NULL; - } - - key->key_evp = d2i_PUBKEY_bio (key->key_bio, NULL); - - if (key->key_evp == NULL) { - g_set_error (err, - DKIM_ERROR, - DKIM_SIGERROR_KEYFAIL, - "cannot extract pubkey from bio"); - REF_RELEASE (key); + if (key->decoded_len != rspamd_cryptobox_pk_sig_bytes ( + RSPAMD_CRYPTOBOX_MODE_25519)) { + g_set_error (err, + DKIM_ERROR, + DKIM_SIGERROR_KEYFAIL, + "DKIM key is has invalid length %d for eddsa", + (gint)key->decoded_len); + REF_RELEASE (key); - return NULL; + return NULL; + } } + else { + key->key_bio = BIO_new_mem_buf (key->keydata, key->decoded_len); - if (type == RSPAMD_DKIM_KEY_RSA) { - key->key.key_rsa = EVP_PKEY_get1_RSA (key->key_evp); - - if (key->key.key_rsa == NULL) { + if (key->key_bio == NULL) { g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_KEYFAIL, - "cannot extract rsa key from evp key"); + "cannot make ssl bio from key"); REF_RELEASE (key); return NULL; } - } - else { - key->key.key_ecdsa = EVP_PKEY_get1_EC_KEY (key->key_evp); - if (key->key.key_ecdsa == NULL) { + key->key_evp = d2i_PUBKEY_bio (key->key_bio, NULL); + + if (key->key_evp == NULL) { g_set_error (err, DKIM_ERROR, DKIM_SIGERROR_KEYFAIL, - "cannot extract ecdsa key from evp key"); + "cannot extract pubkey from bio"); REF_RELEASE (key); return NULL; } + + if (type == RSPAMD_DKIM_KEY_RSA) { + key->key.key_rsa = EVP_PKEY_get1_RSA (key->key_evp); + + if (key->key.key_rsa == NULL) { + g_set_error (err, + DKIM_ERROR, + DKIM_SIGERROR_KEYFAIL, + "cannot extract rsa key from evp key"); + REF_RELEASE (key); + + return NULL; + } + } else { + key->key.key_ecdsa = EVP_PKEY_get1_EC_KEY (key->key_evp); + + if (key->key.key_ecdsa == NULL) { + g_set_error (err, + DKIM_ERROR, + DKIM_SIGERROR_KEYFAIL, + "cannot extract ecdsa key from evp key"); + REF_RELEASE (key); + + return NULL; + } + } } return key; @@ -1303,11 +1331,12 @@ rspamd_dkim_key_free (rspamd_dkim_key_t *key) RSA_free (key->key.key_rsa); } } - else { + else if (key->type == RSPAMD_DKIM_KEY_ECDSA) { if (key->key.key_ecdsa) { EC_KEY_free (key->key.key_ecdsa); } } + /* Nothing in case of eddsa key */ if (key->key_bio) { BIO_free (key->key_bio); } @@ -1433,14 +1462,18 @@ rspamd_dkim_parse_key (rspamd_dkim_context_t *ctx, const gchar *txt, alglen = 3; } - if (alglen == 8 && rspamd_lc_cmp (alg, "ecdsa256", alglen) == 0) { - if (keylen) { - *keylen = klen; - } + if (keylen) { + *keylen = klen; + } + if (alglen == 8 && rspamd_lc_cmp (alg, "ecdsa256", alglen) == 0) { return rspamd_dkim_make_key (ctx, c, klen, RSPAMD_DKIM_KEY_ECDSA, err); } + else if (alglen == 7 && rspamd_lc_cmp (alg, "ed25519", alglen) == 0) { + return rspamd_dkim_make_key (ctx, c, klen, + RSPAMD_DKIM_KEY_EDDSA, err); + } else { /* We assume RSA default in all cases */ if (alglen != 3 || rspamd_lc_cmp (alg, "rsa", alglen) != 0) { @@ -2419,7 +2452,8 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx, nid = NID_sha1; } else if (ctx->sig_alg == DKIM_SIGN_RSASHA256 || - ctx->sig_alg == DKIM_SIGN_ECDSASHA256) { + ctx->sig_alg == DKIM_SIGN_ECDSASHA256 || + ctx->sig_alg == DKIM_SIGN_EDDSASHA256) { nid = NID_sha256; } else if (ctx->sig_alg == DKIM_SIGN_RSASHA512 || @@ -2431,21 +2465,31 @@ rspamd_dkim_check (rspamd_dkim_context_t *ctx, nid = NID_sha1; } - if (key->type == RSPAMD_DKIM_KEY_RSA) { + switch (key->type) { + case RSPAMD_DKIM_KEY_RSA: if (RSA_verify (nid, raw_digest, dlen, ctx->b, ctx->blen, key->key.key_rsa) != 1) { msg_debug_dkim ("rsa verify failed"); res = DKIM_REJECT; } - } - else { + break; + case RSPAMD_DKIM_KEY_ECDSA: if (ECDSA_verify (nid, raw_digest, dlen, ctx->b, ctx->blen, key->key.key_ecdsa) != 1) { msg_debug_dkim ("ecdsa verify failed"); res = DKIM_REJECT; } + break; + case RSPAMD_DKIM_KEY_EDDSA: + if (!rspamd_cryptobox_verify (ctx->b, ctx->blen, raw_digest, dlen, + key->key.key_eddsa, RSPAMD_CRYPTOBOX_MODE_25519)) { + msg_debug_dkim ("eddsa verify failed"); + res = DKIM_REJECT; + } + break; } + if (ctx->common.type == RSPAMD_DKIM_ARC_SEAL && res == DKIM_CONTINUE) { switch (ctx->cv) { case RSPAMD_ARC_INVALID: