Browse Source

Add preliminary lua API for libcryptobox

pull/532/head
Vsevolod Stakhov 10 years ago
parent
commit
10e385ec78
  1. 3
      src/lua/CMakeLists.txt
  2. 673
      src/lua/lua_cryptobox.c

3
src/lua/CMakeLists.txt

@ -25,6 +25,7 @@ SET(LUASRC ${CMAKE_CURRENT_SOURCE_DIR}/lua_common.c
${CMAKE_CURRENT_SOURCE_DIR}/lua_tcp.c
${CMAKE_CURRENT_SOURCE_DIR}/lua_html.c
${CMAKE_CURRENT_SOURCE_DIR}/lua_fann.c
${CMAKE_CURRENT_SOURCE_DIR}/lua_sqlite3.c)
${CMAKE_CURRENT_SOURCE_DIR}/lua_sqlite3.c
${CMAKE_CURRENT_SOURCE_DIR}/lua_cryptobox.c)
SET(RSPAMD_LUA ${LUASRC} PARENT_SCOPE)

673
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);
}
Loading…
Cancel
Save