commit 8b5cd20: [Feature] Support ed25519 dkim keys generation

Vsevolod Stakhov vsevolod at highsecure.ru
Tue Feb 26 14:56:03 UTC 2019


Author: Vsevolod Stakhov
Date: 2019-02-26 14:54:40 +0000
URL: https://github.com/rspamd/rspamd/commit/8b5cd205ada30cb3e05d154efb078fb69a53c358 (HEAD -> master)

[Feature] Support ed25519 dkim keys generation

---
 src/libutil/str_util.c     |  13 +----
 src/libutil/str_util.h     |  18 +++++++
 src/rspamadm/dkim_keygen.c | 128 ++++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 135 insertions(+), 24 deletions(-)

diff --git a/src/libutil/str_util.c b/src/libutil/str_util.c
index 0defa2acf..ac7471ada 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 34c1271d4..9145b97b4 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 86b228d01..86f786295 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 <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)
 {


More information about the Commits mailing list