]> source.dussan.org Git - rspamd.git/commitdiff
[Feature] Support ED25519 DKIM signatures
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 6 Jun 2018 07:58:20 +0000 (08:58 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Wed, 6 Jun 2018 07:58:20 +0000 (08:58 +0100)
src/libserver/dkim.c

index 5af61daf75c90e8298029c4f80868bcfa7704252..4aaa74a3b574e15c28d825d7c53608b99ebf3565 100644 (file)
@@ -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: