]> source.dussan.org Git - rspamd.git/commitdiff
[Feature] Support ed25519 dkim keys generation
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 26 Feb 2019 14:54:40 +0000 (14:54 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 26 Feb 2019 14:54:40 +0000 (14:54 +0000)
src/libutil/str_util.c
src/libutil/str_util.h
src/rspamadm/dkim_keygen.c

index 0defa2acf1db2885635773d532116e6a2c5c8c45..ac7471adab4623e06905669a225bf3401816ef83 100644 (file)
@@ -734,18 +734,7 @@ rspamd_decode_base32 (const gchar *in, gsize inlen, gsize *outlen)
 }
 
 
-
-/**
- * Decode string using base32 encoding
- * @param in input
- * @param inlen input length
- * @param out output buf (may overlap with `in`)
- * @param outlen output buf len
- * @return TRUE if in is valid base32 and `outlen` is enough to encode `inlen`
- */
-
-
-static gchar *
+gchar *
 rspamd_encode_base64_common (const guchar *in, gsize inlen, gint str_len,
                gsize *outlen, gboolean fold, enum rspamd_newlines_type how)
 {
index 34c1271d4fbe9b11382eed8f4cc2a56a17dc39e1..9145b97b465d898415db8baeea02b987da602001 100644 (file)
@@ -184,6 +184,7 @@ gint rspamd_decode_base32_buf (const gchar *in, gsize inlen,
 gint rspamd_encode_hex_buf (const guchar *in, gsize inlen, gchar *out,
                gsize outlen);
 
+
 /**
  * Decode string using hex encoding
  * @param in input
@@ -195,6 +196,23 @@ gint rspamd_encode_hex_buf (const guchar *in, gsize inlen, gchar *out,
 gssize rspamd_decode_hex_buf (const gchar *in, gsize inlen,
                guchar *out, gsize outlen);
 
+/**
+ * Common version of base64 encoder
+ * @param in
+ * @param inlen
+ * @param str_len
+ * @param outlen
+ * @param fold
+ * @param how
+ * @return
+ */
+gchar *
+rspamd_encode_base64_common (const guchar *in,
+                                                        gsize inlen,
+                                                        gint str_len,
+                                                        gsize *outlen,
+                                                        gboolean fold,
+                                                        enum rspamd_newlines_type how);
 /**
  * Encode string using base64 encoding
  * @param in input
index 86b228d018c3e0d0554ed5997d9c5682a0197ec4..86f786295e9b2a05cb95e6e64d6b9ba54ae9cc93 100644 (file)
@@ -17,6 +17,8 @@
 #include "rspamadm.h"
 #include "printf.h"
 #include "str_util.h"
+#include "libcryptobox/cryptobox.h"
+#include "contrib/libottery/ottery.h"
 #include "lua/lua_common.h"
 #include <openssl/rsa.h>
 #include <openssl/bn.h>
@@ -26,6 +28,7 @@ static gchar *privkey_file = NULL;
 static gchar *selector = NULL;
 static gchar *domain = NULL;
 static guint bits = 1024;
+static gchar *type = "rsa";
 
 static void rspamadm_dkim_keygen (gint argc, gchar **argv,
                                                                  const struct rspamadm_command *cmd);
@@ -50,6 +53,8 @@ static GOptionEntry entries[] = {
                                "Save private key in the specified file", NULL},
                {"bits",  'b', 0, G_OPTION_ARG_INT, &bits,
                                "Set key length to N bits (1024 by default)", NULL},
+               {"type",  't', 0, G_OPTION_ARG_STRING, &type,
+                               "Key type: rsa or ed25519 (rsa by default)", NULL},
                {NULL,       0,   0, G_OPTION_ARG_NONE, NULL, NULL, NULL}
 };
 
@@ -76,8 +81,9 @@ rspamadm_dkim_keygen_help (gboolean full_help, const struct rspamadm_command *cm
 }
 
 static void
-rspamadm_dkim_generate_keypair (const gchar *domain, const gchar *selector,
-               const gchar *priv_fname, const gchar *pub_fname, guint keylen)
+rspamd_dkim_generate_rsa_keypair (const gchar *domain, const gchar *selector,
+                                                                 const gchar *priv_fname, const gchar *pub_fname,
+                                                                 guint keylen)
 {
        BIGNUM *e;
        RSA *r;
@@ -109,8 +115,7 @@ rspamadm_dkim_generate_keypair (const gchar *domain, const gchar *selector,
                                        priv_fname, strerror (errno));
                        exit (EXIT_FAILURE);
                }
-       }
-       else {
+       } else {
                privout = BIO_new_fp (stdout, 0);
        }
 
@@ -125,7 +130,7 @@ rspamadm_dkim_generate_keypair (const gchar *domain, const gchar *selector,
        BIO_free (privout);
        fflush (stdout);
 
-       pubout = BIO_new (BIO_s_mem());
+       pubout = BIO_new (BIO_s_mem ());
 
        rc = i2d_RSA_PUBKEY_bio (pubout, r);
        publen = BIO_get_mem_data (pubout, &pubdata);
@@ -141,18 +146,16 @@ rspamadm_dkim_generate_keypair (const gchar *domain, const gchar *selector,
                                        pub_fname, strerror (errno));
                        exit (EXIT_FAILURE);
                }
-       }
-       else {
+       } else {
                pubfile = stdout;
        }
 
        if (b64_len < 255 - 2) {
                rspamd_fprintf (pubfile, "%s._domainkey IN TXT ( \"v=DKIM1; k=rsa; \"\n"
-                                               "\t\"p=%s\" ) ;\n",
+                                                                "\t\"p=%s\" ) ;\n",
                                selector ? selector : "selector",
                                b64_data);
-       }
-       else {
+       } else {
                guint i;
                gint step = 253, remain = b64_len;
 
@@ -162,8 +165,7 @@ rspamadm_dkim_generate_keypair (const gchar *domain, const gchar *selector,
                for (i = 0; i < b64_len; i += step, remain -= step) {
                        if (i == 0) {
                                rspamd_fprintf (pubfile, "\t\"p=%*s\"\n", MIN(step, remain), &b64_data[i]);
-                       }
-                       else {
+                       } else {
                                step = 255;
                                rspamd_fprintf (pubfile, "\t\"%*s\"\n", MIN(step, remain), &b64_data[i]);
                        }
@@ -183,6 +185,108 @@ rspamadm_dkim_generate_keypair (const gchar *domain, const gchar *selector,
        BN_free (e);
 }
 
+static void
+rspamd_dkim_generate_ed25519_keypair (const gchar *domain, const gchar *selector,
+                                                                 const gchar *priv_fname, const gchar *pub_fname,
+                                                                 guint keylen)
+{
+       rspamd_sig_sk_t ed_sk;
+       rspamd_sig_pk_t ed_pk;
+       gchar *base64_pk, *base64_sk;
+       FILE *pubfile = NULL, *privfile = NULL;
+
+       rspamd_cryptobox_keypair_sig (ed_pk, ed_sk, RSPAMD_CRYPTOBOX_MODE_25519);
+       /* Just encode seed, not the full sk */
+       base64_sk = rspamd_encode_base64_common (ed_sk, 32, 0, NULL, FALSE,
+                       RSPAMD_TASK_NEWLINES_LF);
+       base64_pk = rspamd_encode_base64_common (ed_pk, sizeof (ed_pk), 0, NULL, FALSE,
+                       RSPAMD_TASK_NEWLINES_LF);
+
+       /* Cleanup sensitive data */
+       rspamd_explicit_memzero (ed_sk, sizeof (ed_sk));
+
+       if (priv_fname) {
+               privfile = fopen (priv_fname, "w");
+
+               if (privfile == NULL) {
+                       rspamd_fprintf (stderr, "cannot open output file %s: %s\n",
+                                       priv_fname, strerror (errno));
+                       rspamd_explicit_memzero (base64_sk, strlen (base64_sk));
+                       g_free (base64_sk);
+                       g_free (base64_pk);
+                       exit (EXIT_FAILURE);
+               }
+       }
+       else {
+               privfile = stdout;
+       }
+
+       if (rspamd_fprintf (privfile, "%s\n", base64_sk) == -1) {
+               rspamd_fprintf (stderr, "cannot write to output file %s: %s\n",
+                               priv_fname, strerror (errno));
+               rspamd_explicit_memzero (base64_sk, strlen (base64_sk));
+               g_free (base64_sk);
+               g_free (base64_pk);
+
+               if (privfile != stdout) {
+                       fclose (privfile);
+               }
+
+               exit (EXIT_FAILURE);
+       }
+
+       if (privfile != stdout) {
+               fclose (privfile);
+       }
+
+       if (pub_fname) {
+               pubfile = fopen (pub_fname, "w");
+
+               if (pubfile == NULL) {
+                       rspamd_fprintf (stderr, "cannot open output file %s: %s\n",
+                                       pub_fname, strerror (errno));
+                       rspamd_explicit_memzero (base64_sk, strlen (base64_sk));
+                       g_free (base64_sk);
+                       g_free (base64_pk);
+                       exit (EXIT_FAILURE);
+               }
+       }
+       else {
+               pubfile = stdout;
+       }
+
+       rspamd_fprintf (pubfile, "%s._domainkey IN TXT ( \"v=DKIM1; k=ed25519; \"\n"
+                                                        "\t\"p=%s\" ) ;\n",
+                       selector ? selector : "selector",
+                       base64_pk);
+
+       if (pubfile != stdout) {
+               fclose (pubfile);
+       }
+
+       rspamd_explicit_memzero (base64_sk, strlen (base64_sk));
+       g_free (base64_sk);
+       g_free (base64_pk);
+}
+
+static void
+rspamadm_dkim_generate_keypair (const gchar *domain, const gchar *selector,
+               const gchar *priv_fname, const gchar *pub_fname, guint keylen)
+{
+       if (strcmp (type, "rsa") == 0) {
+               rspamd_dkim_generate_rsa_keypair (domain, selector, priv_fname,
+                               pub_fname, keylen);
+       }
+       else if (strcmp (type, "ed25519") == 0) {
+               rspamd_dkim_generate_ed25519_keypair (domain, selector, priv_fname,
+                               pub_fname, keylen);
+       }
+       else {
+               fprintf (stderr, "invalid key type: %s\n", type);
+               exit (EXIT_FAILURE);
+       }
+}
+
 static gint
 rspamadm_dkim_keygen_lua_generate (lua_State *L)
 {