/* * px5g - Embedded x509 key and certificate generator based on PolarSSL * * Copyright (C) 2009 Steven Barth <steven@midlink.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License, version 2.1 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #include "px5g.h" #include <time.h> #include <string.h> #define VERSION 0.1 static char *xfields[] = {"CN", "O", "C", "OU", "ST", "L", "R"}; static int px5g_genkey(lua_State *L) { int keysize = luaL_checkint(L, 1), pexp = luaL_optint(L, 2, 65537), ret; px5g_rsa *px5g = lua_newuserdata(L, sizeof(px5g_rsa)); if (!px5g) { return luaL_error(L, "out of memory"); } px5g->stat = 1; havege_init(&px5g->hs); rsa_init(&px5g->rsa, RSA_PKCS_V15, 0, havege_rand, &px5g->hs); if ((ret = rsa_gen_key(&px5g->rsa, keysize, pexp))) { lua_pushnil(L); lua_pushinteger(L, ret); return 2; } luaL_getmetatable(L, PX5G_KEY_META); lua_setmetatable(L, -2); return 1; } static int px5g_rsa_asn1(lua_State *L) { int ret; px5g_rsa *px5g = luaL_checkudata(L, 1, PX5G_KEY_META); x509_node node; x509write_init_node(&node); if ((ret = x509write_serialize_key(&px5g->rsa, &node))) { x509write_free_node(&node); lua_pushnil(L); lua_pushinteger(L, ret); return 2; } lua_pushlstring(L, (char*)node.data, node.len); x509write_free_node(&node); return 1; } static int px5g_rsa_create_selfsigned(lua_State *L) { px5g_rsa *px5g = luaL_checkudata(L, 1, PX5G_KEY_META); luaL_checktype(L, 2, LUA_TTABLE); time_t from = (time_t)luaL_checknumber(L, 3); time_t to = (time_t)luaL_checknumber(L, 4); char fstr[20], tstr[20]; lua_pushliteral(L, "CN"); lua_rawget(L, 2); luaL_argcheck(L, lua_isstring(L, -1), 2, "CN missing"); lua_pop(L, 1); luaL_argcheck(L, strftime(fstr, sizeof(fstr), "%F %H:%M:%S", gmtime(&from)), 3, "Invalid Time"); luaL_argcheck(L, strftime(tstr, sizeof(tstr), "%F %H:%M:%S", gmtime(&to)), 4, "Invalid Time"); size_t join = 1; lua_pushliteral(L, ""); for (int i = 0; i < (sizeof(xfields) / sizeof(*xfields)); i++) { lua_pushstring(L, xfields[i]); lua_rawget(L, 2); if (lua_isstring(L, -1)) { const char *val = lua_tostring(L, -1); luaL_argcheck(L, !strchr(val, ';'), 2, "Invalid Value"); lua_pushfstring(L, "%s=%s;", xfields[i], val); lua_remove(L, -2); join++; } else { lua_pop(L, 1); } } lua_concat(L, join); x509_raw cert; x509write_init_raw(&cert); x509write_add_pubkey(&cert, &px5g->rsa); x509write_add_subject(&cert, (unsigned char*)lua_tostring(L, -1)); x509write_add_validity(&cert, (unsigned char*)fstr, (unsigned char*)tstr); x509write_create_selfsign(&cert, &px5g->rsa); lua_pushlstring(L, (char*)cert.raw.data, cert.raw.len); x509write_free_raw(&cert); return 1; } static int px5g_rsa__gc(lua_State *L) { px5g_rsa *px5g = luaL_checkudata(L, 1, PX5G_KEY_META); if (px5g->stat) { rsa_free(&px5g->rsa); px5g->stat = 0; } return 0; } static int px5g_rsa__tostring(lua_State *L) { px5g_rsa *px5g = luaL_checkudata(L, 1, PX5G_KEY_META); lua_pushfstring(L, "px5g context %p", px5g); return 1; } /* method table */ static const luaL_reg M[] = { {"asn1", px5g_rsa_asn1}, {"create_selfsigned", px5g_rsa_create_selfsigned}, {"__gc", px5g_rsa__gc}, {"__tostring", px5g_rsa__tostring}, {NULL, NULL} }; /* module table */ static const luaL_reg R[] = { {"genkey", px5g_genkey}, {NULL, NULL} }; int luaopen_px5g(lua_State *L) { /* register module */ luaL_register(L, "px5g", R); /* Meta Table */ luaL_newmetatable(L, PX5G_KEY_META); luaL_register(L, NULL, M); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "meta_key"); return 1; }