/*=========================================================================*\ * openssl.c * lua-openssl binding * * This product includes PHP software, freely available from * Author: george zhao \*=========================================================================*/ #include "openssl.h" #include #include #include #include #include "private.h" static int openssl_version(lua_State*L) { int num = lua_isnoneornil(L, 1) ? 0 : auxiliar_checkboolean(L, 1); if (num) { lua_pushinteger(L, LOPENSSL_VERSION_NUM); lua_pushinteger(L, LUA_VERSION_NUM); lua_pushinteger(L, OPENSSL_VERSION_NUMBER); } else { lua_pushstring(L, LOPENSSL_VERSION); lua_pushstring(L, LUA_VERSION); lua_pushstring(L, OPENSSL_VERSION_TEXT); } return 3; } static LUA_FUNCTION(openssl_hex) { size_t l = 0; const char* s = luaL_checklstring(L, 1, &l); int encode = lua_isnoneornil(L, 2) ? 1 : lua_toboolean(L, 2); char* h = NULL; if (l == 0) { lua_pushstring(L, ""); return 1; } if (encode) { h = OPENSSL_malloc(2 * l + 1); l = bin2hex((const unsigned char *)s, h, l); } else { h = OPENSSL_malloc(l / 2 + 1); l = hex2bin(s, (unsigned char *)h, l); }; lua_pushlstring(L, (const char*)h, l); OPENSSL_free(h); return 1; } static LUA_FUNCTION(openssl_base64) { BIO *inp = load_bio_object(L, 1); int encode = lua_isnoneornil(L, 2) ? 1 : lua_toboolean(L, 2); int nonl = lua_isnoneornil(L, 3) ? BIO_FLAGS_BASE64_NO_NL : (lua_toboolean(L, 3) ? BIO_FLAGS_BASE64_NO_NL : 0); BIO *b64 = BIO_new(BIO_f_base64()); BIO *out = BIO_new(BIO_s_mem()); BUF_MEM* mem = {0}; BIO_set_flags(b64, nonl); if (encode) { BIO_push(b64, out); BIO_get_mem_ptr(inp, &mem); BIO_write(b64, mem->data, mem->length); (void)BIO_flush(b64); } else { char inbuf[512]; int inlen; BIO_push(b64, inp); while ((inlen = BIO_read(b64, inbuf, 512)) > 0) BIO_write(out, inbuf, inlen); (void)BIO_flush(out); } BIO_get_mem_ptr(out, &mem); if (mem->length > 0) lua_pushlstring(L, mem->data, mem->length); else lua_pushnil(L); BIO_free_all(b64); if (encode) BIO_free(inp); else BIO_free(out); return 1; } static void list_callback(const OBJ_NAME *obj, void *arg) { lua_State *L = (lua_State *)arg; int idx = (int)lua_rawlen(L, -1); lua_pushstring(L, obj->name); lua_rawseti(L, -2, idx + 1); } static LUA_FUNCTION(openssl_list) { static int options[] = { OBJ_NAME_TYPE_MD_METH, OBJ_NAME_TYPE_CIPHER_METH, OBJ_NAME_TYPE_PKEY_METH, OBJ_NAME_TYPE_COMP_METH }; static const char *names[] = {"digests", "ciphers", "pkeys", "comps", NULL}; int type = auxiliar_checkoption (L, 1, NULL, names, options); lua_createtable(L, 0, 0); OBJ_NAME_do_all_sorted(type, list_callback, L); return 1; } static LUA_FUNCTION(openssl_error_string) { unsigned long val; int clear, ret = 0; if (lua_isnumber(L, 1)) { val = (unsigned long)lua_tonumber(L, 1); clear = lua_toboolean(L, 2); } else { val = ERR_get_error(); clear = lua_toboolean(L, 1); } if (val) { lua_pushinteger(L, val); lua_pushstring (L, ERR_reason_error_string(val)); lua_pushstring (L, ERR_lib_error_string (val)); lua_pushstring (L, ERR_func_error_string (val)); #ifdef ERR_FATAL_ERROR lua_pushboolean(L, ERR_FATAL_ERROR (val)); ret = 5; #else ret = 4; #endif } if (clear) ERR_clear_error(); return ret; } static int openssl_random_load(lua_State*L) { const char *file = luaL_optstring(L, 1, NULL); char buffer[MAX_PATH]; int len; if (file == NULL) file = RAND_file_name(buffer, sizeof buffer); #ifndef OPENSSL_NO_EGD else if (RAND_egd(file) > 0) { /* we try if the given filename is an EGD socket. if it is, we don't write anything back to the file. */; lua_pushboolean(L, 1); return 1; } #endif len = luaL_optinteger(L, 2, 2048); if (file == NULL || !RAND_load_file(file, len)) { return openssl_pushresult(L, 0); } lua_pushboolean(L, RAND_status()); return 1; } static int openssl_random_write(lua_State *L) { const char *file = luaL_optstring(L, 1, NULL); char buffer[MAX_PATH]; if (file == NULL && (file = RAND_file_name(buffer, sizeof buffer)) == NULL) return openssl_pushresult(L, 0); RAND_write_file(file); return openssl_pushresult(L, 1); } static int openssl_random_status(lua_State *L) { lua_pushboolean(L, RAND_status()); return 1; } static int openssl_random_cleanup(lua_State *L) { (void) L; RAND_cleanup(); return 0; } static LUA_FUNCTION(openssl_random_bytes) { long length = luaL_checkint(L, 1); int strong = lua_isnil(L, 2) ? 0 : lua_toboolean(L, 2); char *buffer = NULL; int ret = 0; if (length <= 0) { luaL_argerror(L, 1, "must greater than 0"); } buffer = malloc(length + 1); if (strong) { ret = RAND_bytes((byte*)buffer, length); if (ret == 1) { lua_pushlstring(L, buffer, length); } else { lua_pushboolean(L, 0); } } else { ret = RAND_pseudo_bytes((byte*)buffer, length); if (ret == 1) { lua_pushlstring(L, buffer, length); } else { lua_pushboolean(L, 0); } } free(buffer); return 1; } #ifndef OPENSSL_NO_CRYPTO_MDEBUG static int openssl_mem_leaks(lua_State*L) { BIO *bio = BIO_new(BIO_s_mem()); BUF_MEM* mem; /* OBJ_cleanup */ CRYPTO_mem_leaks(bio); BIO_get_mem_ptr(bio, &mem); lua_pushlstring(L, mem->data, mem->length); BIO_free(bio); return 1; } #endif static const luaL_Reg eay_functions[] = { {"version", openssl_version}, {"list", openssl_list}, {"hex", openssl_hex}, {"base64", openssl_base64}, #ifndef OPENSSL_NO_CRYPTO_MDEBUG {"mem_leaks", openssl_mem_leaks}, #endif {"rand_status", openssl_random_status}, {"rand_load", openssl_random_load}, {"rand_write", openssl_random_write}, {"rand_cleanup", openssl_random_cleanup}, {"random", openssl_random_bytes}, {"error", openssl_error_string}, {"engine", openssl_engine}, {NULL, NULL} }; #if defined(OPENSSL_THREADS) void CRYPTO_thread_setup(void); void CRYPTO_thread_cleanup(void); #endif LUALIB_API int luaopen_openssl(lua_State*L) { static int init = 0; if (init == 0) { #if defined(OPENSSL_THREADS) CRYPTO_thread_setup(); #endif OpenSSL_add_all_ciphers(); OpenSSL_add_all_digests(); SSL_library_init(); ERR_load_ERR_strings(); ERR_load_EVP_strings(); ERR_load_crypto_strings(); ENGINE_load_dynamic(); ENGINE_load_openssl(); #ifdef LOAD_ENGINE_CUSTOM LOAD_ENGINE_CUSTOM #endif #ifdef OPENSSL_SYS_WINDOWS #if OPENSSL_VERSION_NUMBER < 0x10100000L RAND_screen(); #endif #endif init = 1; } lua_newtable(L); luaL_setfuncs(L, eay_functions, 0); openssl_register_lhash(L); openssl_register_engine(L); luaopen_bio(L); lua_setfield(L, -2, "bio"); luaopen_asn1(L); lua_setfield(L, -2, "asn1"); luaopen_digest(L); lua_setfield(L, -2, "digest"); luaopen_cipher(L); lua_setfield(L, -2, "cipher"); luaopen_hmac(L); lua_setfield(L, -2, "hmac"); luaopen_pkey(L); lua_setfield(L, -2, "pkey"); #ifdef EVP_PKEY_EC luaopen_ec(L); lua_setfield(L, -2, "ec"); #endif luaopen_x509(L); lua_setfield(L, -2, "x509"); luaopen_pkcs7(L); lua_setfield(L, -2, "pkcs7"); luaopen_pkcs12(L); lua_setfield(L, -2, "pkcs12"); luaopen_ocsp(L); lua_setfield(L, -2, "ocsp"); #ifdef OPENSSL_HAVE_TS /* timestamp handling */ luaopen_ts(L); lua_setfield(L, -2, "ts"); #endif luaopen_cms(L); lua_setfield(L, -2, "cms"); luaopen_ssl(L); lua_setfield(L, -2, "ssl"); /* third part */ luaopen_bn(L); lua_setfield(L, -2, "bn"); luaopen_rsa(L); lua_setfield(L, -2, "rsa"); luaopen_dsa(L); lua_setfield(L, -2, "dsa"); luaopen_dh(L); lua_setfield(L, -2, "dh"); #ifdef ENABLE_OPENSSL_GLOBAL lua_pushvalue(L, -1); lua_setglobal(L, "openssl"); #endif return 1; }