aboutsummaryrefslogtreecommitdiffstats
path: root/src/lua/lua_cryptobox.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2016-02-19 22:54:08 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2016-02-19 22:54:08 +0000
commit10e385ec78211ed42eb19fb413a59dfa09e8d5d8 (patch)
treed97c7a6f315687797800a0d480334ae47e193834 /src/lua/lua_cryptobox.c
parent86627da2920b0fccfef60df00131e74bc5a2c57f (diff)
downloadrspamd-10e385ec78211ed42eb19fb413a59dfa09e8d5d8.tar.gz
rspamd-10e385ec78211ed42eb19fb413a59dfa09e8d5d8.zip
Add preliminary lua API for libcryptobox
Diffstat (limited to 'src/lua/lua_cryptobox.c')
-rw-r--r--src/lua/lua_cryptobox.c673
1 files changed, 673 insertions, 0 deletions
diff --git a/src/lua/lua_cryptobox.c b/src/lua/lua_cryptobox.c
new file mode 100644
index 000000000..0f4c4ea5f
--- /dev/null
+++ b/src/lua/lua_cryptobox.c
@@ -0,0 +1,673 @@
+/*-
+ * Copyright 2016 Vsevolod Stakhov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*-
+ * Copyright 2016 Vsevolod Stakhov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file lua_cryptobox.c
+ * This module exports routines to load cryptobox keys, check inline or external
+ * crypto signatures or encrypting/decrypting data.
+ */
+
+#include "lua_common.h"
+#include "cryptobox.h"
+#include "keypair.h"
+#include "unix-std.h"
+
+LUA_FUNCTION_DEF (cryptobox_pubkey, load);
+LUA_FUNCTION_DEF (cryptobox_pubkey, create);
+LUA_FUNCTION_DEF (cryptobox_pubkey, gc);
+LUA_FUNCTION_DEF (cryptobox_keypair, load);
+LUA_FUNCTION_DEF (cryptobox_keypair, create);
+LUA_FUNCTION_DEF (cryptobox_keypair, gc);
+LUA_FUNCTION_DEF (cryptobox_signature, create);
+LUA_FUNCTION_DEF (cryptobox_signature, load);
+LUA_FUNCTION_DEF (cryptobox_signature, save);
+LUA_FUNCTION_DEF (cryptobox_signature, gc);
+LUA_FUNCTION_DEF (cryptobox, verify_memory);
+LUA_FUNCTION_DEF (cryptobox, verify_file);
+LUA_FUNCTION_DEF (cryptobox, sign_file);
+LUA_FUNCTION_DEF (cryptobox, sign_memory);
+
+static const struct luaL_reg cryptoboxlib_f[] = {
+ LUA_INTERFACE_DEF (cryptobox, verify_memory),
+ LUA_INTERFACE_DEF (cryptobox, verify_file),
+ LUA_INTERFACE_DEF (cryptobox, sign_memory),
+ LUA_INTERFACE_DEF (cryptobox, sign_file),
+ {NULL, NULL}
+};
+
+static const struct luaL_reg cryptoboxpubkeylib_f[] = {
+ LUA_INTERFACE_DEF (cryptobox_pubkey, load),
+ LUA_INTERFACE_DEF (cryptobox_pubkey, create),
+ {NULL, NULL}
+};
+
+static const struct luaL_reg cryptoboxpubkeylib_m[] = {
+ {"__tostring", rspamd_lua_class_tostring},
+ {"__gc", lua_cryptobox_pubkey_gc},
+ {NULL, NULL}
+};
+
+static const struct luaL_reg cryptoboxkeypairlib_f[] = {
+ LUA_INTERFACE_DEF (cryptobox_keypair, load),
+ LUA_INTERFACE_DEF (cryptobox_keypair, create),
+ {NULL, NULL}
+};
+
+static const struct luaL_reg cryptoboxkeypairlib_m[] = {
+ {"__tostring", rspamd_lua_class_tostring},
+ {"__gc", lua_cryptobox_keypair_gc},
+ {NULL, NULL}
+};
+
+static const struct luaL_reg cryptoboxsignlib_f[] = {
+ LUA_INTERFACE_DEF (cryptobox_signature, load),
+ LUA_INTERFACE_DEF (cryptobox_signature, create),
+ {NULL, NULL}
+};
+
+static const struct luaL_reg cryptoboxsignlib_m[] = {
+ LUA_INTERFACE_DEF (cryptobox_signature, save),
+ {"__tostring", rspamd_lua_class_tostring},
+ {"__gc", lua_cryptobox_signature_gc},
+ {NULL, NULL}
+};
+
+static struct rspamd_cryptobox_pubkey *
+lua_check_cryptobox_pubkey (lua_State * L, int pos)
+{
+ void *ud = luaL_checkudata (L, pos, "rspamd{cryptobox_pubkey}");
+
+ luaL_argcheck (L, ud != NULL, 1, "'cryptobox_pubkey' expected");
+ return ud ? *((struct rspamd_cryptobox_pubkey **)ud) : NULL;
+}
+
+static struct rspamd_cryptobox_keypair *
+lua_check_cryptobox_keypair (lua_State * L, int pos)
+{
+ void *ud = luaL_checkudata (L, pos, "rspamd{cryptobox_keypair}");
+
+ luaL_argcheck (L, ud != NULL, 1, "'cryptobox_keypair' expected");
+ return ud ? *((struct rspamd_cryptobox_keypair **)ud) : NULL;
+}
+
+static rspamd_fstring_t *
+lua_check_cryptobox_sign (lua_State * L, int pos)
+{
+ void *ud = luaL_checkudata (L, pos, "rspamd{cryptobox_signature}");
+
+ luaL_argcheck (L, ud != NULL, 1, "'cryptobox_signature' expected");
+ return ud ? *((rspamd_fstring_t **)ud) : NULL;
+}
+
+/***
+ * function pubkey.load(file[, type[, alg]])
+ * Loads public key from base32 encoded file
+ * @param {string} file filename to load
+ * @param {string} type optional 'sign' or 'kex' for signing and encryption
+ * @param {string} alg optional 'default' or 'nist' for curve25519/nistp256 keys
+ * @return {cryptobox_pubkey} new public key
+ */
+static gint
+lua_cryptobox_pubkey_load (lua_State *L)
+{
+ struct rspamd_cryptobox_pubkey *pkey = NULL, **ppkey;
+ const gchar *filename, *arg;
+ gint type = RSPAMD_KEYPAIR_SIGN;
+ gint alg = RSPAMD_CRYPTOBOX_MODE_25519;
+ guchar *map;
+ gsize len;
+
+ filename = luaL_checkstring (L, 1);
+ if (filename != NULL) {
+ map = rspamd_file_xmap (filename, PROT_READ, &len);
+
+ if (map == NULL) {
+ msg_err ("cannot open pubkey from file: %s, %s",
+ filename,
+ strerror (errno));
+ lua_pushnil (L);
+ }
+ else {
+ if (lua_type (L, 2) == LUA_TSTRING) {
+ /* keypair type */
+ arg = lua_tostring (L, 2);
+
+ if (strcmp (arg, "sign") == 0) {
+ type = RSPAMD_KEYPAIR_SIGN;
+ }
+ else if (strcmp (arg, "kex") == 0) {
+ type = RSPAMD_KEYPAIR_KEX;
+ }
+ }
+ if (lua_type (L, 3) == LUA_TSTRING) {
+ /* algorithm */
+ arg = lua_tostring (L, 3);
+
+ if (strcmp (arg, "default") == 0 || strcmp (arg, "curve25519") == 0) {
+ type = RSPAMD_CRYPTOBOX_MODE_25519;
+ }
+ else if (strcmp (arg, "nist") == 0) {
+ type = RSPAMD_CRYPTOBOX_MODE_NIST;
+ }
+ }
+
+ pkey = rspamd_pubkey_from_base32 (map, len, type, alg);
+
+ if (pkey == NULL) {
+ msg_err ("cannot open pubkey from file: %s", filename);
+ munmap (map, len);
+ lua_pushnil (L);
+ }
+ else {
+ munmap (map, len);
+ ppkey = lua_newuserdata (L, sizeof (void *));
+ rspamd_lua_setclass (L, "rspamd{cryptobox_pubkey}", -1);
+ *ppkey = pkey;
+ }
+ }
+ }
+ else {
+ lua_error (L);
+ }
+ return 1;
+}
+
+
+/***
+ * function pubkey.create(data[, type[, alg]])
+ * Loads public key from base32 encoded file
+ * @param {base32 string} base32 string with the key
+ * @param {string} type optional 'sign' or 'kex' for signing and encryption
+ * @param {string} alg optional 'default' or 'nist' for curve25519/nistp256 keys
+ * @return {cryptobox_pubkey} new public key
+ */
+static gint
+lua_cryptobox_pubkey_create (lua_State *L)
+{
+ struct rspamd_cryptobox_pubkey *pkey = NULL, **ppkey;
+ const gchar *buf, *arg;
+ gsize len;
+ gint type = RSPAMD_KEYPAIR_SIGN;
+ gint alg = RSPAMD_CRYPTOBOX_MODE_25519;
+
+ buf = luaL_checklstring (L, 1, &len);
+ if (buf != NULL) {
+ if (lua_type (L, 2) == LUA_TSTRING) {
+ /* keypair type */
+ arg = lua_tostring (L, 2);
+
+ if (strcmp (arg, "sign") == 0) {
+ type = RSPAMD_KEYPAIR_SIGN;
+ }
+ else if (strcmp (arg, "kex") == 0) {
+ type = RSPAMD_KEYPAIR_KEX;
+ }
+ }
+ if (lua_type (L, 3) == LUA_TSTRING) {
+ /* algorithm */
+ arg = lua_tostring (L, 3);
+
+ if (strcmp (arg, "default") == 0 || strcmp (arg, "curve25519") == 0) {
+ type = RSPAMD_CRYPTOBOX_MODE_25519;
+ }
+ else if (strcmp (arg, "nist") == 0) {
+ type = RSPAMD_CRYPTOBOX_MODE_NIST;
+ }
+ }
+
+ pkey = rspamd_pubkey_from_base32 (buf, len, type, alg);
+
+ if (pkey == NULL) {
+ msg_err ("cannot load pubkey from string");
+ lua_pushnil (L);
+ }
+ else {
+ ppkey = lua_newuserdata (L, sizeof (void *));
+ rspamd_lua_setclass (L, "rspamd{cryptobox_pubkey}", -1);
+ *ppkey = pkey;
+ }
+
+ }
+ else {
+ lua_pushnil (L);
+ }
+ return 1;
+}
+
+static gint
+lua_cryptobox_pubkey_gc (lua_State *L)
+{
+ struct rspamd_cryptobox_pubkey *pkey = lua_check_cryptobox_pubkey (L, 1);
+
+ if (pkey != NULL) {
+ rspamd_pubkey_unref (pkey);
+ }
+
+ return 0;
+}
+
+/***
+ * function keypair.load(file)
+ * Loads public key from UCL file
+ * @param {string} file filename to load
+ * @return {cryptobox_keypair} new keypair
+ */
+static gint
+lua_cryptobox_keypair_load (lua_State *L)
+{
+ struct rspamd_cryptobox_keypair *kp, **pkp;
+ const gchar *filename;
+ struct ucl_parser *parser;
+ ucl_object_t *obj;
+
+ filename = luaL_checkstring (L, 1);
+ if (filename != NULL) {
+ parser = ucl_parser_new (0);
+
+ if (!ucl_parser_add_file (parser, filename)) {
+ msg_err ("cannot open keypair from file: %s, %s",
+ filename,
+ ucl_parser_get_error (parser));
+ ucl_parser_free (parser);
+ lua_pushnil (L);
+ }
+ else {
+ obj = ucl_parser_get_object (parser);
+ kp = rspamd_keypair_from_ucl (obj);
+ ucl_parser_free (parser);
+
+ if (kp == NULL) {
+ msg_err ("cannot open keypair from file: %s",
+ filename);
+ ucl_object_unref (obj);
+ lua_pushnil (L);
+ }
+ else {
+ pkp = lua_newuserdata (L, sizeof (gpointer));
+ *pkp = kp;
+ rspamd_lua_setclass (L, "rspamd{cryptobox_keypair}", -1);
+ ucl_object_unref (obj);
+ }
+ }
+ }
+ else {
+ lua_error (L);
+ }
+
+ return 1;
+}
+
+static gint
+lua_cryptobox_keypair_create (lua_State *L)
+{
+ struct rspamd_cryptobox_keypair *kp, **pkp;
+ const gchar *buf;
+ gsize len;
+ struct ucl_parser *parser;
+ ucl_object_t *obj;
+
+ buf = luaL_checklstring (L, 1, &len);
+ if (buf != NULL) {
+ parser = ucl_parser_new (0);
+
+ if (!ucl_parser_add_chunk (parser, buf, len)) {
+ msg_err ("cannot open keypair from data: %s",
+ ucl_parser_get_error (parser));
+ ucl_parser_free (parser);
+ lua_pushnil (L);
+ }
+ else {
+ obj = ucl_parser_get_object (parser);
+ kp = rspamd_keypair_from_ucl (obj);
+ ucl_parser_free (parser);
+
+ if (kp == NULL) {
+ msg_err ("cannot load keypair from data");
+ ucl_object_unref (obj);
+ lua_pushnil (L);
+ }
+ else {
+ pkp = lua_newuserdata (L, sizeof (gpointer));
+ *pkp = kp;
+ rspamd_lua_setclass (L, "rspamd{cryptobox_keypair}", -1);
+ ucl_object_unref (obj);
+ }
+ }
+ }
+ else {
+ lua_error (L);
+ }
+
+ return 1;
+}
+
+static gint
+lua_cryptobox_keypair_gc (lua_State *L)
+{
+ struct rspamd_cryptobox_keypair *kp = lua_check_cryptobox_keypair (L, 1);
+
+ if (kp != NULL) {
+ rspamd_keypair_unref (kp);
+ }
+
+ return 0;
+}
+
+static gint
+lua_cryptobox_signature_load (lua_State *L)
+{
+ rspamd_fstring_t *sig, **psig;
+ const gchar *filename;
+ gpointer data;
+ int fd;
+ struct stat st;
+
+ filename = luaL_checkstring (L, 1);
+ if (filename != NULL) {
+ fd = open (filename, O_RDONLY);
+ if (fd == -1) {
+ msg_err ("cannot open signature file: %s, %s", filename,
+ strerror (errno));
+ lua_pushnil (L);
+ }
+ else {
+ sig = g_malloc (sizeof (rspamd_fstring_t));
+ 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 {
+ sig = rspamd_fstring_new_init (data, st.st_size);
+ psig = lua_newuserdata (L, sizeof (rspamd_fstring_t *));
+ rspamd_lua_setclass (L, "rspamd{cryptobox_signature}", -1);
+ *psig = sig;
+ munmap (data, st.st_size);
+ }
+ close (fd);
+ }
+ }
+ else {
+ lua_pushnil (L);
+ }
+ return 1;
+}
+
+static gint
+lua_cryptobox_signature_save (lua_State *L)
+{
+ rspamd_fstring_t *sig;
+ gint fd, flags;
+ const gchar *filename;
+ gboolean forced = FALSE, res = TRUE;
+
+ sig = lua_check_cryptobox_sign (L, 1);
+ filename = luaL_checkstring (L, 2);
+ if (lua_gettop (L) > 2) {
+ forced = lua_toboolean (L, 3);
+ }
+
+ if (sig != NULL && filename != NULL) {
+ flags = O_WRONLY | O_CREAT;
+ if (forced) {
+ flags |= O_TRUNC;
+ }
+ else {
+ flags |= O_EXCL;
+ }
+ fd = open (filename, flags, 00644);
+ if (fd == -1) {
+ msg_err ("cannot create a signature file: %s, %s",
+ filename,
+ strerror (errno));
+ lua_pushboolean (L, FALSE);
+ }
+ else {
+ while (write (fd, sig->str, sig->len) == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ msg_err ("cannot write to a signature file: %s, %s",
+ filename,
+ strerror (errno));
+ res = FALSE;
+ break;
+ }
+ lua_pushboolean (L, res);
+ close (fd);
+ }
+ }
+ else {
+ lua_pushboolean (L, FALSE);
+ }
+
+ return 1;
+}
+
+static gint
+lua_cryptobox_signature_create (lua_State *L)
+{
+ rspamd_fstring_t *sig, **psig;
+ const gchar *data;
+ gsize dlen;
+
+ data = luaL_checklstring (L, 1, &dlen);
+ if (data != NULL) {
+ sig = rspamd_fstring_new_init (data, dlen);
+ psig = lua_newuserdata (L, sizeof (rspamd_fstring_t *));
+ rspamd_lua_setclass (L, "rspamd{cryptobox_signature}", -1);
+ *psig = sig;
+ }
+
+ return 1;
+}
+
+static gint
+lua_cryptobox_signature_gc (lua_State *L)
+{
+ rspamd_fstring_t *sig = lua_check_cryptobox_sign (L, 1);
+
+ rspamd_fstring_free (sig);
+
+ return 0;
+}
+
+/**
+ * Check memory using specified cryptobox key and signature
+ *
+ * arguments:
+ * (cryptobox_pubkey, cryptobox_signature, string)
+ *
+ * returns:
+ * true - if string match cryptobox signature
+ * false - otherwise
+ */
+static gint
+lua_cryptobox_verify_memory (lua_State *L)
+{
+ struct rspamd_cryptobox_pubkey *pk;
+ rspamd_fstring_t *signature;
+ const gchar *data;
+ gsize len;
+ gint ret;
+
+ pk = lua_check_cryptobox_pubkey (L, 1);
+ signature = lua_check_cryptobox_sign (L, 2);
+ /* XXX: check signature length */
+ data = luaL_checklstring (L, 3, &len);
+
+ if (pk != NULL && signature != NULL && data != NULL) {
+ ret = rspamd_cryptobox_verify (signature->str, data, len,
+ rspamd_pubkey_get_pk (pk, NULL), RSPAMD_CRYPTOBOX_MODE_25519);
+
+ if (ret) {
+ lua_pushboolean (L, 1);
+ }
+ else {
+ lua_pushboolean (L, 0);
+ }
+ }
+ else {
+ lua_pushnil (L);
+ }
+
+ return 1;
+}
+
+/**
+ * Check memory using specified cryptobox key and signature
+ *
+ * arguments:
+ * (cryptobox_pubkey, cryptobox_signature, string)
+ *
+ * returns:
+ * true - if string match cryptobox signature
+ * false - otherwise
+ */
+static gint
+lua_cryptobox_verify_file (lua_State *L)
+{
+ return 0;
+}
+
+/**
+ * Sign memory using specified cryptobox key and signature
+ *
+ * arguments:
+ * (cryptobox_keypair, string)
+ *
+ * returns:
+ * rspamd_signature object
+ * nil - otherwise
+ */
+static gint
+lua_cryptobox_sign_memory (lua_State *L)
+{
+ return 0;
+}
+
+/**
+ * Sign file using specified cryptobox key and signature
+ *
+ * arguments:
+ * (cryptobox_keypair, cryptobox_signature, string)
+ *
+ * returns:
+ * true - if string match cryptobox signature
+ * false - otherwise
+ */
+static gint
+lua_cryptobox_sign_file (lua_State *L)
+{
+ return 0;
+}
+
+static gint
+lua_load_pubkey (lua_State * L)
+{
+ lua_newtable (L);
+ luaL_register (L, NULL, cryptoboxpubkeylib_f);
+
+ return 1;
+}
+
+static gint
+lua_load_keypair (lua_State * L)
+{
+ lua_newtable (L);
+ luaL_register (L, NULL, cryptoboxkeypairlib_f);
+
+ return 1;
+}
+
+static gint
+lua_load_signature (lua_State * L)
+{
+ lua_newtable (L);
+ luaL_register (L, NULL, cryptoboxsignlib_f);
+
+ return 1;
+}
+
+static gint
+lua_load_cryptobox (lua_State * L)
+{
+ lua_newtable (L);
+ luaL_register (L, NULL, cryptoboxlib_f);
+
+ return 1;
+}
+
+void
+luaopen_cryptobox (lua_State * L)
+{
+ luaL_newmetatable (L, "rspamd{cryptobox_pubkey}");
+ lua_pushstring (L, "__index");
+ lua_pushvalue (L, -2);
+ lua_settable (L, -3);
+
+ lua_pushstring (L, "class");
+ lua_pushstring (L, "rspamd{cryptobox_pubkey}");
+ lua_rawset (L, -3);
+
+ luaL_register (L, NULL, cryptoboxpubkeylib_m);
+ rspamd_lua_add_preload (L, "rspamd_cryptobox_pubkey", lua_load_pubkey);
+
+ luaL_newmetatable (L, "rspamd{cryptobox_keypair}");
+ lua_pushstring (L, "__index");
+ lua_pushvalue (L, -2);
+ lua_settable (L, -3);
+
+ lua_pushstring (L, "class");
+ lua_pushstring (L, "rspamd{cryptobox_keypair}");
+ lua_rawset (L, -3);
+
+ luaL_register (L, NULL, cryptoboxkeypairlib_m);
+ rspamd_lua_add_preload (L, "rspamd_cryptobox_keypair", lua_load_keypair);
+
+ luaL_newmetatable (L, "rspamd{cryptobox_signature}");
+ lua_pushstring (L, "__index");
+ lua_pushvalue (L, -2);
+ lua_settable (L, -3);
+
+ lua_pushstring (L, "class");
+ lua_pushstring (L, "rspamd{cryptobox_signature}");
+ lua_rawset (L, -3);
+
+ luaL_register (L, NULL, cryptoboxsignlib_m);
+ rspamd_lua_add_preload (L, "rspamd_cryptobox_signature", lua_load_signature);
+
+ rspamd_lua_add_preload (L, "rspamd_cryptobox", lua_load_cryptobox);
+
+ lua_settop (L, 0);
+}