aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2018-06-06 08:58:20 +0100
committerVsevolod Stakhov <vsevolod@highsecure.ru>2018-06-06 08:58:20 +0100
commit573f8cd97a5f24949977b856b0108844b5bacf88 (patch)
tree0a367e7f7a4a813cc38f7b1942ee391d5ecabc04
parentdd8772c131f3b0c2dc40fd78df0f177285edb89f (diff)
downloadrspamd-573f8cd97a5f24949977b856b0108844b5bacf88.tar.gz
rspamd-573f8cd97a5f24949977b856b0108844b5bacf88.zip
[Feature] Support ED25519 DKIM signatures
-rw-r--r--src/libserver/dkim.c128
1 files changed, 86 insertions, 42 deletions
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: