aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2013-06-12 17:50:35 +0100
committerVsevolod Stakhov <vsevolod@highsecure.ru>2013-06-12 17:50:35 +0100
commitdf2e93c58c0a537c8dd6e6f5c07371ad800a2bc4 (patch)
tree320b6a7540748ad91e0fffef18e11a28d62a1cfa /src
parent2be05d7af71ac14a9f515254185e16522310b5ad (diff)
downloadrspamd-df2e93c58c0a537c8dd6e6f5c07371ad800a2bc4.tar.gz
rspamd-df2e93c58c0a537c8dd6e6f5c07371ad800a2bc4.zip
Add preliminary API for rsa verify to lua.
Diffstat (limited to 'src')
-rw-r--r--src/lua/CMakeLists.txt3
-rw-r--r--src/lua/lua_cfg_file.c7
-rw-r--r--src/lua/lua_rsa.c393
-rw-r--r--src/main.c13
4 files changed, 414 insertions, 2 deletions
diff --git a/src/lua/CMakeLists.txt b/src/lua/CMakeLists.txt
index 8d05c65e5..765d3041d 100644
--- a/src/lua/CMakeLists.txt
+++ b/src/lua/CMakeLists.txt
@@ -14,7 +14,8 @@ SET(LUASRC lua_common.c
lua_mempool.c
lua_session.c
lua_buffer.c
- lua_dns.c)
+ lua_dns.c
+ lua_rsa.c)
ADD_LIBRARY(rspamd-lua ${LINK_TYPE} ${LUASRC})
SET_TARGET_PROPERTIES(rspamd-lua PROPERTIES VERSION ${RSPAMD_VERSION})
diff --git a/src/lua/lua_cfg_file.c b/src/lua/lua_cfg_file.c
index b23ba10f8..433e70fc7 100644
--- a/src/lua/lua_cfg_file.c
+++ b/src/lua/lua_cfg_file.c
@@ -482,6 +482,13 @@ lua_check_condition (struct config_file *cfg, const gchar *condition)
lua_setglobal (L, "osrelease");
#endif
+#ifdef HAVE_OPENSSL
+ lua_pushboolean (L, TRUE);
+#else
+ lua_pushboolean (L, FALSE);
+#endif
+ lua_setglobal (L, "rspamd_supports_rsa");
+
/* Rspamd paths */
lua_newtable (L);
lua_set_table_index (L, "etcdir", ETC_PREFIX);
diff --git a/src/lua/lua_rsa.c b/src/lua/lua_rsa.c
new file mode 100644
index 000000000..b9b4e907c
--- /dev/null
+++ b/src/lua/lua_rsa.c
@@ -0,0 +1,393 @@
+/* Copyright (c) 2013, Vsevolod Stakhov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/**
+ * @file lua_rsa.c
+ * This module exports routines to load rsa keys, check inline or external
+ * rsa signatures. It assumes sha256 based signatures.
+ */
+
+#include "lua_common.h"
+
+#ifdef HAVE_OPENSSL
+#include <openssl/err.h>
+#include <openssl/sha.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+
+LUA_FUNCTION_DEF (rsa_key, load);
+LUA_FUNCTION_DEF (rsa_key, create);
+LUA_FUNCTION_DEF (rsa_key, gc);
+LUA_FUNCTION_DEF (rsa_signature, create);
+LUA_FUNCTION_DEF (rsa_signature, load);
+LUA_FUNCTION_DEF (rsa_signature, gc);
+LUA_FUNCTION_DEF (rsa, check_memory);
+LUA_FUNCTION_DEF (rsa, check_file);
+
+static const struct luaL_reg rsalib_f[] = {
+ LUA_INTERFACE_DEF (rsa, check_memory),
+ LUA_INTERFACE_DEF (rsa, check_file),
+ {NULL, NULL}
+};
+
+static const struct luaL_reg rsakeylib_f[] = {
+ LUA_INTERFACE_DEF (rsa_key, load),
+ LUA_INTERFACE_DEF (rsa_key, create),
+ {NULL, NULL}
+};
+
+static const struct luaL_reg rsakeylib_m[] = {
+ {"__tostring", lua_class_tostring},
+ {"__gc", lua_rsa_key_gc},
+ {NULL, NULL}
+};
+
+static const struct luaL_reg rsasignlib_f[] = {
+ LUA_INTERFACE_DEF (rsa_signature, load),
+ LUA_INTERFACE_DEF (rsa_signature, create),
+ {NULL, NULL}
+};
+
+static const struct luaL_reg rsasignlib_m[] = {
+ {"__tostring", lua_class_tostring},
+ {"__gc", lua_rsa_signature_gc},
+ {NULL, NULL}
+};
+
+static RSA *
+lua_check_rsa_key (lua_State * L, int pos)
+{
+ void *ud = luaL_checkudata (L, pos, "rspamd{rsa_key}");
+
+ luaL_argcheck (L, ud != NULL, 1, "'rsa_key' expected");
+ return ud ? *((RSA **)ud) : NULL;
+}
+
+static gpointer
+lua_check_rsa_sign (lua_State * L, int pos)
+{
+ void *ud = luaL_checkudata (L, pos, "rspamd{rsa_signature}");
+
+ luaL_argcheck (L, ud != NULL, 1, "'rsa_signature' expected");
+ return ud ? *((gpointer *)ud) : NULL;
+}
+
+static gint
+lua_rsa_key_load (lua_State *L)
+{
+ RSA *rsa = NULL, **prsa;
+ const gchar *filename;
+ FILE *f;
+
+ filename = luaL_checkstring (L, 1);
+ if (filename != NULL) {
+ f = fopen (filename, "r");
+ if (f == NULL) {
+ msg_err ("cannot open pubkey from file: %s, %s", filename, strerror (errno));
+ lua_pushnil (L);
+ }
+ else {
+ if (! PEM_read_RSA_PUBKEY (f, &rsa, NULL, NULL)) {
+ msg_err ("cannot open pubkey from file: %s, %s", filename,
+ ERR_error_string (ERR_get_error (), NULL));
+ lua_pushnil (L);
+ }
+ else {
+ prsa = lua_newuserdata (L, sizeof (RSA *));
+ lua_setclass (L, "rspamd{rsa_key}", -1);
+ *prsa = rsa;
+ }
+ fclose (f);
+ }
+ }
+ else {
+ lua_pushnil (L);
+ }
+ return 1;
+}
+
+static gint
+lua_rsa_key_create (lua_State *L)
+{
+ RSA *rsa = NULL, **prsa;
+ const gchar *buf;
+ BIO *bp;
+
+ buf = luaL_checkstring (L, 1);
+ if (buf != NULL) {
+ bp = BIO_new_mem_buf ((void *)buf, -1);
+
+ if (! PEM_read_bio_RSA_PUBKEY (bp, &rsa, NULL, NULL)) {
+ msg_err ("cannot parse pubkey: %s",
+ ERR_error_string (ERR_get_error (), NULL));
+ lua_pushnil (L);
+ }
+ else {
+ prsa = lua_newuserdata (L, sizeof (RSA *));
+ lua_setclass (L, "rspamd{rsa_key}", -1);
+ *prsa = rsa;
+ }
+ BIO_free (bp);
+ }
+ else {
+ lua_pushnil (L);
+ }
+ return 1;
+}
+
+static gint
+lua_rsa_key_gc (lua_State *L)
+{
+ RSA *rsa = lua_check_rsa_key (L, 1);
+
+ if (rsa != NULL) {
+ RSA_free (rsa);
+ }
+
+ return 0;
+}
+
+static gint
+lua_rsa_signature_load (lua_State *L)
+{
+ gchar *sig, **psig;
+ const gchar *filename;
+ FILE *f;
+ gint siglen;
+
+ siglen = g_checksum_type_get_length (G_CHECKSUM_SHA256);
+ filename = luaL_checkstring (L, 1);
+ if (filename != NULL) {
+ f = fopen (filename, "r");
+ if (f == NULL) {
+ msg_err ("cannot open signature file: %s, %s", filename, strerror (errno));
+ lua_pushnil (L);
+ }
+ else {
+ sig = g_malloc (siglen * 2 + 1);
+ if (fread (sig, siglen * 2, 1, f) == 1) {
+ sig[siglen * 2] = '\0';
+ psig = lua_newuserdata (L, sizeof (gchar *));
+ lua_setclass (L, "rspamd{rsa_signature}", -1);
+ *psig = sig;
+ }
+ else {
+ msg_err ("cannot read signature file: %s, %s", filename, strerror (errno));
+ g_free (sig);
+ lua_pushnil (L);
+ }
+ fclose (f);
+ }
+ }
+ else {
+ lua_pushnil (L);
+ }
+ return 1;
+}
+
+static gint
+lua_rsa_signature_create (lua_State *L)
+{
+ gchar *sig, **psig;
+ const gchar *data;
+ guint siglen;
+
+ siglen = g_checksum_type_get_length (G_CHECKSUM_SHA256);
+ data = luaL_checkstring (L, 1);
+ if (data != NULL) {
+ sig = g_malloc (siglen * 2 + 1);
+ if (strlen (data) == siglen * 2) {
+ memcpy (sig, data, siglen * 2);
+ sig[siglen * 2] = '\0';
+ psig = lua_newuserdata (L, sizeof (gchar *));
+ lua_setclass (L, "rspamd{rsa_signature}", -1);
+ *psig = sig;
+ }
+ else {
+ msg_err ("cannot read signature string: %s", data);
+ g_free (sig);
+ lua_pushnil (L);
+ }
+ }
+
+ return 1;
+}
+
+static gint
+lua_rsa_signature_gc (lua_State *L)
+{
+ gpointer sig = lua_check_rsa_sign (L, 1);
+
+ if (sig != NULL) {
+ g_free (sig);
+ }
+
+ return 0;
+}
+
+/**
+ * Check memory using specified rsa key and signature
+ *
+ * arguments:
+ * (rsa_key, rsa_signature, string)
+ *
+ * returns:
+ * true - if string match rsa signature
+ * false - otherwise
+ */
+static gint
+lua_rsa_check_memory (lua_State *L)
+{
+ RSA *rsa;
+ gpointer signature;
+ const gchar *data;
+ gchar *data_sig;
+ gint ret, siglen;
+
+ siglen = g_checksum_type_get_length (G_CHECKSUM_SHA256);
+
+ rsa = lua_check_rsa_key (L, 1);
+ signature = lua_check_rsa_sign (L, 2);
+ data = luaL_checkstring (L, 3);
+
+ if (rsa != NULL && signature != NULL && data != NULL) {
+ data_sig = g_compute_checksum_for_string (G_CHECKSUM_SHA256, data, -1);
+ ret = RSA_verify (NID_sha1, signature, siglen * 2, data_sig, strlen (data_sig), rsa);
+ if (ret == 0) {
+ lua_pushboolean (L, FALSE);
+ }
+ else {
+ lua_pushboolean (L, TRUE);
+ }
+ }
+ else {
+ lua_pushnil (L);
+ }
+
+ return 1;
+}
+
+/**
+ * Check memory using specified rsa key and signature
+ *
+ * arguments:
+ * (rsa_key, rsa_signature, string)
+ *
+ * returns:
+ * true - if string match rsa signature
+ * false - otherwise
+ */
+static gint
+lua_rsa_check_file (lua_State *L)
+{
+ RSA *rsa;
+ gpointer signature;
+ const gchar *filename;
+ gchar *data = NULL, *data_sig;
+ gint ret, siglen;
+ gint fd;
+ struct stat st;
+
+ siglen = g_checksum_type_get_length (G_CHECKSUM_SHA256);
+
+ rsa = lua_check_rsa_key (L, 1);
+ signature = lua_check_rsa_sign (L, 2);
+ filename = luaL_checkstring (L, 3);
+
+ if (rsa != NULL && signature != NULL && data != NULL) {
+ fd = open (filename, O_RDONLY);
+ if (fd == -1) {
+ msg_err ("cannot open file %s: %s", filename, strerror (errno));
+ lua_pushnil (L);
+ }
+ else {
+ if (fstat (fd, &st) == -1 ||
+ (data = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+ msg_err ("cannot mmap file %s: %s", filename, strerror (errno));
+ lua_pushnil (L);
+ }
+ else {
+ data_sig = g_compute_checksum_for_data (G_CHECKSUM_SHA256, data, st.st_size);
+ ret = RSA_verify (NID_sha1, signature, siglen * 2, data_sig, strlen (data_sig), rsa);
+ if (ret == 0) {
+ lua_pushboolean (L, FALSE);
+ }
+ else {
+ lua_pushboolean (L, TRUE);
+ }
+ munmap (data, st.st_size);
+ }
+ close (fd);
+ }
+ }
+ else {
+ lua_pushnil (L);
+ }
+
+ return 1;
+}
+
+gint
+luaopen_rsa (lua_State * L)
+{
+ luaL_newmetatable (L, "rspamd{rsa_key}");
+ lua_pushstring (L, "__index");
+ lua_pushvalue (L, -2);
+ lua_settable (L, -3);
+
+ lua_pushstring (L, "class");
+ lua_pushstring (L, "rspamd{rsa_key}");
+ lua_rawset (L, -3);
+
+ luaL_register (L, NULL, rsakeylib_m);
+ luaL_register (L, "rsa_key", rsakeylib_f);
+
+ luaL_newmetatable (L, "rspamd{rsa_signature}");
+ lua_pushstring (L, "__index");
+ lua_pushvalue (L, -2);
+ lua_settable (L, -3);
+
+ lua_pushstring (L, "class");
+ lua_pushstring (L, "rspamd{rsa_signature}");
+ lua_rawset (L, -3);
+
+ luaL_register (L, NULL, rsasignlib_m);
+ luaL_register (L, "rsa_signature", rsasignlib_f);
+
+ luaL_register (L, "rsa", rsalib_f);
+
+ return 1;
+}
+
+#else
+gint
+luaopen_rsa (lua_State * L)
+{
+ msg_info ("this rspamd version is not linked against openssl, therefore no "
+ "RSA support is available");
+
+ return 1;
+
+}
+#endif
diff --git a/src/main.c b/src/main.c
index 8630bb6bf..7dd381a6b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -37,6 +37,7 @@
#ifdef HAVE_OPENSSL
#include <openssl/rand.h>
#include <openssl/err.h>
+#include <openssl/evp.h>
#endif
/* 2 seconds to fork new process in place of dead one */
@@ -893,8 +894,10 @@ main (gint argc, gchar **argv, gchar **env)
setlocale (LC_TIME, "C");
#endif
- /* Init random generator */
#ifdef HAVE_OPENSSL
+ ERR_load_crypto_strings ();
+
+ /* Init random generator */
if (RAND_bytes (rand_bytes, sizeof (rand_bytes)) != 1) {
msg_err ("cannot seed random generator using openssl: %s, using time", ERR_error_string (ERR_get_error (), NULL));
g_random_set_seed (time (NULL));
@@ -903,6 +906,9 @@ main (gint argc, gchar **argv, gchar **env)
memcpy (&rand_seed, rand_bytes, sizeof (guint32));
g_random_set_seed (rand_seed);
}
+
+ OpenSSL_add_all_algorithms ();
+ OpenSSL_add_all_ciphers ();
#endif
/* First set logger to console logger */
@@ -1174,6 +1180,11 @@ main (gint argc, gchar **argv, gchar **env)
g_free (rspamd_main->cfg);
g_free (rspamd_main);
+#ifdef HAVE_OPENSSL
+ EVP_cleanup ();
+ ERR_free_strings ();
+#endif
+
return (res);
}