From: Vsevolod Stakhov Date: Tue, 26 Feb 2019 14:54:40 +0000 (+0000) Subject: [Feature] Support ed25519 dkim keys generation X-Git-Tag: 1.9.0~83 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8b5cd205ada30cb3e05d154efb078fb69a53c358;p=thirdparty%2Frspamd.git [Feature] Support ed25519 dkim keys generation --- diff --git a/src/libutil/str_util.c b/src/libutil/str_util.c index 0defa2acf1..ac7471adab 100644 --- a/src/libutil/str_util.c +++ b/src/libutil/str_util.c @@ -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) { diff --git a/src/libutil/str_util.h b/src/libutil/str_util.h index 34c1271d4f..9145b97b46 100644 --- a/src/libutil/str_util.h +++ b/src/libutil/str_util.h @@ -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 diff --git a/src/rspamadm/dkim_keygen.c b/src/rspamadm/dkim_keygen.c index 86b228d018..86f786295e 100644 --- a/src/rspamadm/dkim_keygen.c +++ b/src/rspamadm/dkim_keygen.c @@ -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 #include @@ -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) {