From 26605b51971d2f899ce55214a86d799a310fd010 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 18 Mar 2022 15:21:25 +0000 Subject: util.table: Backport table.move() from Lua 5.4 One difference is that 5.4 accepts "table-like" values (for this and other table.*() functions), but that would require additional backporting work. --- util-src/table.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'util-src') diff --git a/util-src/table.c b/util-src/table.c index 9a9553fc..0756a256 100644 --- a/util-src/table.c +++ b/util-src/table.c @@ -1,11 +1,17 @@ #include #include +#ifndef LUA_MAXINTEGER +#include +#define LUA_MAXINTEGER PTRDIFF_MAX +#endif + static int Lcreate_table(lua_State *L) { lua_createtable(L, luaL_checkinteger(L, 1), luaL_checkinteger(L, 2)); return 1; } +/* COMPAT: w/ Lua pre-5.4 */ static int Lpack(lua_State *L) { unsigned int n_args = lua_gettop(L); lua_createtable(L, n_args, 1); @@ -20,6 +26,40 @@ static int Lpack(lua_State *L) { return 1; } +/* COMPAT: w/ Lua pre-5.4 */ +static int Lmove (lua_State *L) { + lua_Integer f = luaL_checkinteger(L, 2); + lua_Integer e = luaL_checkinteger(L, 3); + lua_Integer t = luaL_checkinteger(L, 4); + + int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checktype(L, tt, LUA_TTABLE); + + if (e >= f) { /* otherwise, nothing to move */ + lua_Integer n, i; + luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, + "too many elements to move"); + n = e - f + 1; /* number of elements to move */ + luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, + "destination wrap around"); + if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { + for (i = 0; i < n; i++) { + lua_rawgeti(L, 1, f + i); + lua_rawseti(L, tt, t + i); + } + } else { + for (i = n - 1; i >= 0; i--) { + lua_rawgeti(L, 1, f + i); + lua_rawseti(L, tt, t + i); + } + } + } + + lua_pushvalue(L, tt); /* return destination table */ + return 1; +} + int luaopen_util_table(lua_State *L) { #if (LUA_VERSION_NUM > 501) luaL_checkversion(L); @@ -29,5 +69,7 @@ int luaopen_util_table(lua_State *L) { lua_setfield(L, -2, "create"); lua_pushcfunction(L, Lpack); lua_setfield(L, -2, "pack"); + lua_pushcfunction(L, Lmove); + lua_setfield(L, -2, "move"); return 1; } -- cgit v1.2.3 From ca3d1e1958ed89da5147eee42096baae35c744da Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 18 Mar 2022 15:29:05 +0000 Subject: util.table: Compatibility with Lua 5.1 lua_equals --- util-src/table.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'util-src') diff --git a/util-src/table.c b/util-src/table.c index 0756a256..4bbceedb 100644 --- a/util-src/table.c +++ b/util-src/table.c @@ -6,6 +6,10 @@ #define LUA_MAXINTEGER PTRDIFF_MAX #endif +#if (LUA_VERSION_NUM > 501) +#define lua_equal(L, A, B) lua_compare(L, A, B, LUA_OPEQ) +#endif + static int Lcreate_table(lua_State *L) { lua_createtable(L, luaL_checkinteger(L, 1), luaL_checkinteger(L, 2)); return 1; @@ -43,7 +47,7 @@ static int Lmove (lua_State *L) { n = e - f + 1; /* number of elements to move */ luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, "destination wrap around"); - if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { + if (t > e || t <= f || (tt != 1 && !lua_equal(L, 1, tt))) { for (i = 0; i < n; i++) { lua_rawgeti(L, 1, f + i); lua_rawseti(L, tt, t + i); -- cgit v1.2.3 From 787835d693df993e8dbf4164d85b7939856e1aea Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 23 Apr 2022 14:29:43 +0200 Subject: util.strbitop: Reduce scope of functions Equivalent to 'local' in Lua, these functions are exported via the luaopen_ function, which is the only one needing to be visible outside of the file. Pointed out by Link Mauve at some point, but there wasn't really any rush here. --- util-src/strbitop.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'util-src') diff --git a/util-src/strbitop.c b/util-src/strbitop.c index 89fce661..fda8917a 100644 --- a/util-src/strbitop.c +++ b/util-src/strbitop.c @@ -14,7 +14,7 @@ /* TODO Deduplicate code somehow */ -int strop_and(lua_State *L) { +static int strop_and(lua_State *L) { luaL_Buffer buf; size_t a, b, i; const char *str_a = luaL_checklstring(L, 1, &a); @@ -35,7 +35,7 @@ int strop_and(lua_State *L) { return 1; } -int strop_or(lua_State *L) { +static int strop_or(lua_State *L) { luaL_Buffer buf; size_t a, b, i; const char *str_a = luaL_checklstring(L, 1, &a); @@ -56,7 +56,7 @@ int strop_or(lua_State *L) { return 1; } -int strop_xor(lua_State *L) { +static int strop_xor(lua_State *L) { luaL_Buffer buf; size_t a, b, i; const char *str_a = luaL_checklstring(L, 1, &a); -- cgit v1.2.3 From 300813b68b95bd897585cd8728b862c849e1a78d Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 23 Apr 2022 14:37:43 +0200 Subject: util.crand: Reduce scope here too Same as previous commit --- util-src/crand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'util-src') diff --git a/util-src/crand.c b/util-src/crand.c index 160ac1f6..e4104787 100644 --- a/util-src/crand.c +++ b/util-src/crand.c @@ -45,7 +45,7 @@ #endif /* This wasn't present before glibc 2.25 */ -int getrandom(void *buf, size_t buflen, unsigned int flags) { +static int getrandom(void *buf, size_t buflen, unsigned int flags) { return syscall(SYS_getrandom, buf, buflen, flags); } #else @@ -66,7 +66,7 @@ int getrandom(void *buf, size_t buflen, unsigned int flags) { #define SMALLBUFSIZ 32 #endif -int Lrandom(lua_State *L) { +static int Lrandom(lua_State *L) { char smallbuf[SMALLBUFSIZ]; char *buf = &smallbuf[0]; const lua_Integer l = luaL_checkinteger(L, 1); -- cgit v1.2.3 From d690f1502aafe5fbbe66114239e70b389315938e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 10 Sep 2020 21:58:23 +0200 Subject: util.hashes: Refactor hash functions to use OpenSSL EVP methods (fix #1698) MD5() is deprecated, but EVP_md5() is not. Functions in macros like this make it awkward to apply static analysis and code formatting. --- util-src/hashes.c | 83 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 20 deletions(-) (limited to 'util-src') diff --git a/util-src/hashes.c b/util-src/hashes.c index 8eefcd6b..44194905 100644 --- a/util-src/hashes.c +++ b/util-src/hashes.c @@ -46,28 +46,71 @@ static void toHex(const unsigned char *in, int length, unsigned char *out) { } } -#define MAKE_HASH_FUNCTION(myFunc, func, size) \ -static int myFunc(lua_State *L) { \ - size_t len; \ - const char *s = luaL_checklstring(L, 1, &len); \ - int hex_out = lua_toboolean(L, 2); \ - unsigned char hash[size], result[size*2]; \ - func((const unsigned char*)s, len, hash); \ - if (hex_out) { \ - toHex(hash, size, result); \ - lua_pushlstring(L, (char*)result, size*2); \ - } else { \ - lua_pushlstring(L, (char*)hash, size);\ - } \ - return 1; \ +static int Levp_hash(lua_State *L, const EVP_MD *evp) { + size_t len; + unsigned int size = EVP_MAX_MD_SIZE; + const char *s = luaL_checklstring(L, 1, &len); + int hex_out = lua_toboolean(L, 2); + + unsigned char hash[EVP_MAX_MD_SIZE], result[EVP_MAX_MD_SIZE * 2]; + + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + + if(ctx == NULL) { + goto fail; + } + + if(!EVP_DigestInit_ex(ctx, evp, NULL)) { + goto fail; + } + + if(!EVP_DigestUpdate(ctx, s, len)) { + goto fail; + } + + if(!EVP_DigestFinal_ex(ctx, hash, &size)) { + goto fail; + } + + EVP_MD_CTX_free(ctx); + + if(hex_out) { + toHex(hash, size, result); + lua_pushlstring(L, (char *)result, size * 2); + } else { + lua_pushlstring(L, (char *)hash, size); + } + + return 1; + +fail: + EVP_MD_CTX_free(ctx); + return luaL_error(L, "hash function failed"); +} + +static int Lsha1(lua_State *L) { + return Levp_hash(L, EVP_sha1()); +} + +static int Lsha224(lua_State *L) { + return Levp_hash(L, EVP_sha224()); +} + +static int Lsha256(lua_State *L) { + return Levp_hash(L, EVP_sha256()); +} + +static int Lsha384(lua_State *L) { + return Levp_hash(L, EVP_sha384()); +} + +static int Lsha512(lua_State *L) { + return Levp_hash(L, EVP_sha512()); } -MAKE_HASH_FUNCTION(Lsha1, SHA1, SHA_DIGEST_LENGTH) -MAKE_HASH_FUNCTION(Lsha224, SHA224, SHA224_DIGEST_LENGTH) -MAKE_HASH_FUNCTION(Lsha256, SHA256, SHA256_DIGEST_LENGTH) -MAKE_HASH_FUNCTION(Lsha384, SHA384, SHA384_DIGEST_LENGTH) -MAKE_HASH_FUNCTION(Lsha512, SHA512, SHA512_DIGEST_LENGTH) -MAKE_HASH_FUNCTION(Lmd5, MD5, MD5_DIGEST_LENGTH) +static int Lmd5(lua_State *L) { + return Levp_hash(L, EVP_md5()); +} struct hash_desc { int (*Init)(void *); -- cgit v1.2.3 From 54f8ca81f427db3ae9624f9ab5ebd0a566f63013 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 29 Nov 2020 17:58:30 +0100 Subject: util.hashes: Refactor HMAC bindings (fixes #1589) HMAC() is deprecated As with the regular hash functions, macros like this make it awkward to apply static analysis and code formatting. --- util-src/hashes.c | 83 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 61 insertions(+), 22 deletions(-) (limited to 'util-src') diff --git a/util-src/hashes.c b/util-src/hashes.c index 44194905..6b7a28d8 100644 --- a/util-src/hashes.c +++ b/util-src/hashes.c @@ -120,28 +120,67 @@ struct hash_desc { void *ctx, *ctxo; }; -#define MAKE_HMAC_FUNCTION(myFunc, evp, size, type) \ -static int myFunc(lua_State *L) { \ - unsigned char hash[size], result[2*size]; \ - size_t key_len, msg_len; \ - unsigned int out_len; \ - const char *key = luaL_checklstring(L, 1, &key_len); \ - const char *msg = luaL_checklstring(L, 2, &msg_len); \ - const int hex_out = lua_toboolean(L, 3); \ - HMAC(evp(), key, key_len, (const unsigned char*)msg, msg_len, (unsigned char*)hash, &out_len); \ - if (hex_out) { \ - toHex(hash, out_len, result); \ - lua_pushlstring(L, (char*)result, out_len*2); \ - } else { \ - lua_pushlstring(L, (char*)hash, out_len); \ - } \ - return 1; \ -} - -MAKE_HMAC_FUNCTION(Lhmac_sha1, EVP_sha1, SHA_DIGEST_LENGTH, SHA_CTX) -MAKE_HMAC_FUNCTION(Lhmac_sha256, EVP_sha256, SHA256_DIGEST_LENGTH, SHA256_CTX) -MAKE_HMAC_FUNCTION(Lhmac_sha512, EVP_sha512, SHA512_DIGEST_LENGTH, SHA512_CTX) -MAKE_HMAC_FUNCTION(Lhmac_md5, EVP_md5, MD5_DIGEST_LENGTH, MD5_CTX) +static int Levp_hmac(lua_State *L, const EVP_MD *evp) { + unsigned char hash[EVP_MAX_MD_SIZE], result[EVP_MAX_MD_SIZE * 2]; + size_t key_len, msg_len; + size_t out_len = EVP_MAX_MD_SIZE; + const char *key = luaL_checklstring(L, 1, &key_len); + const char *msg = luaL_checklstring(L, 2, &msg_len); + const int hex_out = lua_toboolean(L, 3); + + EVP_PKEY *pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, (unsigned char *)key, key_len); + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + + if(ctx == NULL || pkey == NULL) { + goto fail; + } + + if(!EVP_DigestSignInit(ctx, NULL, evp, NULL, pkey)) { + goto fail; + } + + if(!EVP_DigestSignUpdate(ctx, msg, msg_len)) { + goto fail; + } + + if(!EVP_DigestSignFinal(ctx, hash, &out_len)) { + goto fail; + } + + EVP_MD_CTX_free(ctx); + EVP_PKEY_free(pkey); + + if(hex_out) { + toHex(hash, out_len, result); + lua_pushlstring(L, (char *)result, out_len * 2); + } else { + lua_pushlstring(L, (char *)hash, out_len); + } + + return 1; + +fail: + EVP_MD_CTX_free(ctx); + EVP_PKEY_free(pkey); + return luaL_error(L, "hash function failed"); +} + +static int Lhmac_sha1(lua_State *L) { + return Levp_hmac(L, EVP_sha1()); +} + +static int Lhmac_sha256(lua_State *L) { + return Levp_hmac(L, EVP_sha256()); +} + +static int Lhmac_sha512(lua_State *L) { + return Levp_hmac(L, EVP_sha512()); +} + +static int Lhmac_md5(lua_State *L) { + return Levp_hmac(L, EVP_md5()); +} + static int Lpbkdf2_sha1(lua_State *L) { unsigned char out[SHA_DIGEST_LENGTH]; -- cgit v1.2.3 From ae14dc12208406f54c3ac260dc1dfe701e77f3a3 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 29 Nov 2020 17:58:45 +0100 Subject: util.hashes: Expose sha224 and sha384 HMAC functions For completeness and consistency with set of plain hash functions --- util-src/hashes.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'util-src') diff --git a/util-src/hashes.c b/util-src/hashes.c index 6b7a28d8..00661531 100644 --- a/util-src/hashes.c +++ b/util-src/hashes.c @@ -169,10 +169,18 @@ static int Lhmac_sha1(lua_State *L) { return Levp_hmac(L, EVP_sha1()); } +static int Lhmac_sha224(lua_State *L) { + return Levp_hmac(L, EVP_sha224()); +} + static int Lhmac_sha256(lua_State *L) { return Levp_hmac(L, EVP_sha256()); } +static int Lhmac_sha384(lua_State *L) { + return Levp_hmac(L, EVP_sha384()); +} + static int Lhmac_sha512(lua_State *L) { return Levp_hmac(L, EVP_sha512()); } @@ -236,7 +244,9 @@ static const luaL_Reg Reg[] = { { "sha512", Lsha512 }, { "md5", Lmd5 }, { "hmac_sha1", Lhmac_sha1 }, + { "hmac_sha224", Lhmac_sha224 }, { "hmac_sha256", Lhmac_sha256 }, + { "hmac_sha384", Lhmac_sha384 }, { "hmac_sha512", Lhmac_sha512 }, { "hmac_md5", Lhmac_md5 }, { "scram_Hi_sha1", Lpbkdf2_sha1 }, /* COMPAT */ -- cgit v1.2.3 From 9f932f75595640510f3d36ab6bfe10e673235d9f Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 10 Sep 2020 21:58:25 +0200 Subject: util.hashes: Refactor PBKDF2 to deduplicate code --- util-src/hashes.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) (limited to 'util-src') diff --git a/util-src/hashes.c b/util-src/hashes.c index 00661531..80740866 100644 --- a/util-src/hashes.c +++ b/util-src/hashes.c @@ -190,38 +190,29 @@ static int Lhmac_md5(lua_State *L) { } -static int Lpbkdf2_sha1(lua_State *L) { - unsigned char out[SHA_DIGEST_LENGTH]; +static int Levp_pbkdf2(lua_State *L, const EVP_MD *evp, size_t out_len) { + unsigned char out[EVP_MAX_MD_SIZE]; size_t pass_len, salt_len; const char *pass = luaL_checklstring(L, 1, &pass_len); const unsigned char *salt = (unsigned char *)luaL_checklstring(L, 2, &salt_len); const int iter = luaL_checkinteger(L, 3); - if(PKCS5_PBKDF2_HMAC(pass, pass_len, salt, salt_len, iter, EVP_sha1(), SHA_DIGEST_LENGTH, out) == 0) { + if(PKCS5_PBKDF2_HMAC(pass, pass_len, salt, salt_len, iter, evp, out_len, out) == 0) { return luaL_error(L, "PKCS5_PBKDF2_HMAC() failed"); } - lua_pushlstring(L, (char *)out, SHA_DIGEST_LENGTH); + lua_pushlstring(L, (char *)out, out_len); return 1; } +static int Lpbkdf2_sha1(lua_State *L) { + return Levp_pbkdf2(L, EVP_sha1(), SHA_DIGEST_LENGTH); +} static int Lpbkdf2_sha256(lua_State *L) { - unsigned char out[SHA256_DIGEST_LENGTH]; - - size_t pass_len, salt_len; - const char *pass = luaL_checklstring(L, 1, &pass_len); - const unsigned char *salt = (unsigned char *)luaL_checklstring(L, 2, &salt_len); - const int iter = luaL_checkinteger(L, 3); - - if(PKCS5_PBKDF2_HMAC(pass, pass_len, salt, salt_len, iter, EVP_sha256(), SHA256_DIGEST_LENGTH, out) == 0) { - return luaL_error(L, "PKCS5_PBKDF2_HMAC() failed"); - } - - lua_pushlstring(L, (char *)out, SHA256_DIGEST_LENGTH); - return 1; + return Levp_pbkdf2(L, EVP_sha256(), SHA256_DIGEST_LENGTH); } static int Lhash_equals(lua_State *L) { -- cgit v1.2.3 From f3d61e394501472062f359e02ce5d3bb10bc4bc8 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 10 Sep 2020 21:58:24 +0200 Subject: util.hashes: Bind BLAKE2 algoritms supported by OpenSSL --- util-src/hashes.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'util-src') diff --git a/util-src/hashes.c b/util-src/hashes.c index 80740866..2696f177 100644 --- a/util-src/hashes.c +++ b/util-src/hashes.c @@ -112,6 +112,15 @@ static int Lmd5(lua_State *L) { return Levp_hash(L, EVP_md5()); } +static int Lblake2s256(lua_State *L) { + return Levp_hash(L, EVP_blake2s256()); +} + +static int Lblake2b512(lua_State *L) { + return Levp_hash(L, EVP_blake2b512()); +} + + struct hash_desc { int (*Init)(void *); int (*Update)(void *, const void *, size_t); @@ -189,6 +198,14 @@ static int Lhmac_md5(lua_State *L) { return Levp_hmac(L, EVP_md5()); } +static int Lhmac_blake2s256(lua_State *L) { + return Levp_hmac(L, EVP_blake2s256()); +} + +static int Lhmac_blake2b512(lua_State *L) { + return Levp_hmac(L, EVP_blake2b512()); +} + static int Levp_pbkdf2(lua_State *L, const EVP_MD *evp, size_t out_len) { unsigned char out[EVP_MAX_MD_SIZE]; @@ -234,12 +251,16 @@ static const luaL_Reg Reg[] = { { "sha384", Lsha384 }, { "sha512", Lsha512 }, { "md5", Lmd5 }, + { "blake2s256", Lblake2s256 }, + { "blake2b512", Lblake2b512 }, { "hmac_sha1", Lhmac_sha1 }, { "hmac_sha224", Lhmac_sha224 }, { "hmac_sha256", Lhmac_sha256 }, { "hmac_sha384", Lhmac_sha384 }, { "hmac_sha512", Lhmac_sha512 }, { "hmac_md5", Lhmac_md5 }, + { "hmac_blake2s256", Lhmac_blake2s256 }, + { "hmac_blake2b512", Lhmac_blake2b512 }, { "scram_Hi_sha1", Lpbkdf2_sha1 }, /* COMPAT */ { "pbkdf2_hmac_sha1", Lpbkdf2_sha1 }, { "pbkdf2_hmac_sha256", Lpbkdf2_sha256 }, -- cgit v1.2.3 From a7567a9055c959c89d00424cc9c14f64365a8a35 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 10 Sep 2020 21:58:24 +0200 Subject: util.hashes: Add SHA3 bindings --- util-src/hashes.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'util-src') diff --git a/util-src/hashes.c b/util-src/hashes.c index 2696f177..1b3e157d 100644 --- a/util-src/hashes.c +++ b/util-src/hashes.c @@ -120,6 +120,13 @@ static int Lblake2b512(lua_State *L) { return Levp_hash(L, EVP_blake2b512()); } +static int Lsha3_256(lua_State *L) { + return Levp_hash(L, EVP_sha3_256()); +} + +static int Lsha3_512(lua_State *L) { + return Levp_hash(L, EVP_sha3_512()); +} struct hash_desc { int (*Init)(void *); @@ -198,6 +205,14 @@ static int Lhmac_md5(lua_State *L) { return Levp_hmac(L, EVP_md5()); } +static int Lhmac_sha3_256(lua_State *L) { + return Levp_hmac(L, EVP_sha3_256()); +} + +static int Lhmac_sha3_512(lua_State *L) { + return Levp_hmac(L, EVP_sha3_512()); +} + static int Lhmac_blake2s256(lua_State *L) { return Levp_hmac(L, EVP_blake2s256()); } @@ -251,6 +266,8 @@ static const luaL_Reg Reg[] = { { "sha384", Lsha384 }, { "sha512", Lsha512 }, { "md5", Lmd5 }, + { "sha3_256", Lsha3_256 }, + { "sha3_512", Lsha3_512 }, { "blake2s256", Lblake2s256 }, { "blake2b512", Lblake2b512 }, { "hmac_sha1", Lhmac_sha1 }, @@ -259,6 +276,8 @@ static const luaL_Reg Reg[] = { { "hmac_sha384", Lhmac_sha384 }, { "hmac_sha512", Lhmac_sha512 }, { "hmac_md5", Lhmac_md5 }, + { "hmac_sha3_256", Lhmac_sha3_256 }, + { "hmac_sha3_512", Lhmac_sha3_512 }, { "hmac_blake2s256", Lhmac_blake2s256 }, { "hmac_blake2b512", Lhmac_blake2b512 }, { "scram_Hi_sha1", Lpbkdf2_sha1 }, /* COMPAT */ -- cgit v1.2.3 From 9a960217066e2659bf9473220c977c9246bcf6fa Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 24 Jun 2022 15:33:04 +0200 Subject: util.hashes: Return OpenSSL error messages on failure With luck, might contain more details than just "failed" --- util-src/hashes.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'util-src') diff --git a/util-src/hashes.c b/util-src/hashes.c index 1b3e157d..de802db0 100644 --- a/util-src/hashes.c +++ b/util-src/hashes.c @@ -28,6 +28,7 @@ typedef unsigned __int32 uint32_t; #include #include #include +#include #if (LUA_VERSION_NUM == 501) #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) @@ -85,7 +86,7 @@ static int Levp_hash(lua_State *L, const EVP_MD *evp) { fail: EVP_MD_CTX_free(ctx); - return luaL_error(L, "hash function failed"); + return luaL_error(L, ERR_error_string(ERR_get_error(), NULL)); } static int Lsha1(lua_State *L) { @@ -178,7 +179,7 @@ static int Levp_hmac(lua_State *L, const EVP_MD *evp) { fail: EVP_MD_CTX_free(ctx); EVP_PKEY_free(pkey); - return luaL_error(L, "hash function failed"); + return luaL_error(L, ERR_error_string(ERR_get_error(), NULL)); } static int Lhmac_sha1(lua_State *L) { @@ -231,7 +232,7 @@ static int Levp_pbkdf2(lua_State *L, const EVP_MD *evp, size_t out_len) { const int iter = luaL_checkinteger(L, 3); if(PKCS5_PBKDF2_HMAC(pass, pass_len, salt, salt_len, iter, evp, out_len, out) == 0) { - return luaL_error(L, "PKCS5_PBKDF2_HMAC() failed"); + return luaL_error(L, ERR_error_string(ERR_get_error(), NULL)); } lua_pushlstring(L, (char *)out, out_len); -- cgit v1.2.3 From 452f9e4e2b04982a5222312602f710e28e8f41fb Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 24 Jun 2022 16:12:11 +0200 Subject: util.hashes: Remove unused struct Unused since 9f1c5ae8d70b --- util-src/hashes.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'util-src') diff --git a/util-src/hashes.c b/util-src/hashes.c index de802db0..b302d8eb 100644 --- a/util-src/hashes.c +++ b/util-src/hashes.c @@ -129,14 +129,6 @@ static int Lsha3_512(lua_State *L) { return Levp_hash(L, EVP_sha3_512()); } -struct hash_desc { - int (*Init)(void *); - int (*Update)(void *, const void *, size_t); - int (*Final)(unsigned char *, void *); - size_t digestLength; - void *ctx, *ctxo; -}; - static int Levp_hmac(lua_State *L, const EVP_MD *evp) { unsigned char hash[EVP_MAX_MD_SIZE], result[EVP_MAX_MD_SIZE * 2]; size_t key_len, msg_len; -- cgit v1.2.3 From 8f3d837cd253a226a30fd05529ff7b8bf0d535fa Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 24 Jun 2022 16:49:03 +0200 Subject: util.hashes: Remove unused constants --- util-src/hashes.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'util-src') diff --git a/util-src/hashes.c b/util-src/hashes.c index b302d8eb..4ad786ae 100644 --- a/util-src/hashes.c +++ b/util-src/hashes.c @@ -34,9 +34,6 @@ typedef unsigned __int32 uint32_t; #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) #endif -#define HMAC_IPAD 0x36363636 -#define HMAC_OPAD 0x5c5c5c5c - static const char *hex_tab = "0123456789abcdef"; static void toHex(const unsigned char *in, int length, unsigned char *out) { int i; -- cgit v1.2.3 From b1c7b93139f52acd11ac22494b06a3678135ffdc Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 24 Jun 2022 16:59:54 +0200 Subject: util.hashes: Revert to HMAC() convenience function Reverts some of 1e41dd0f8353 Seems HMAC() isn't deprecated after all? Must have been at some point according to #1589 Twice as fast for some reason. --- util-src/hashes.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) (limited to 'util-src') diff --git a/util-src/hashes.c b/util-src/hashes.c index 4ad786ae..fbc86081 100644 --- a/util-src/hashes.c +++ b/util-src/hashes.c @@ -129,33 +129,15 @@ static int Lsha3_512(lua_State *L) { static int Levp_hmac(lua_State *L, const EVP_MD *evp) { unsigned char hash[EVP_MAX_MD_SIZE], result[EVP_MAX_MD_SIZE * 2]; size_t key_len, msg_len; - size_t out_len = EVP_MAX_MD_SIZE; + unsigned int out_len = EVP_MAX_MD_SIZE; const char *key = luaL_checklstring(L, 1, &key_len); const char *msg = luaL_checklstring(L, 2, &msg_len); const int hex_out = lua_toboolean(L, 3); - EVP_PKEY *pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, (unsigned char *)key, key_len); - EVP_MD_CTX *ctx = EVP_MD_CTX_new(); - - if(ctx == NULL || pkey == NULL) { - goto fail; - } - - if(!EVP_DigestSignInit(ctx, NULL, evp, NULL, pkey)) { - goto fail; - } - - if(!EVP_DigestSignUpdate(ctx, msg, msg_len)) { - goto fail; - } - - if(!EVP_DigestSignFinal(ctx, hash, &out_len)) { + if(HMAC(evp, key, key_len, (const unsigned char*)msg, msg_len, (unsigned char*)hash, &out_len) == NULL) { goto fail; } - EVP_MD_CTX_free(ctx); - EVP_PKEY_free(pkey); - if(hex_out) { toHex(hash, out_len, result); lua_pushlstring(L, (char *)result, out_len * 2); @@ -166,8 +148,6 @@ static int Levp_hmac(lua_State *L, const EVP_MD *evp) { return 1; fail: - EVP_MD_CTX_free(ctx); - EVP_PKEY_free(pkey); return luaL_error(L, ERR_error_string(ERR_get_error(), NULL)); } -- cgit v1.2.3 From dff4beae0278ae5b98c52b7e1162ceb318236256 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 1 Jul 2022 21:21:21 +0200 Subject: util-src: Remove Lua 5.1 compat macros Part of #1600 --- util-src/crand.c | 2 -- util-src/encodings.c | 5 ----- util-src/hashes.c | 5 ----- util-src/net.c | 5 ----- util-src/poll.c | 5 ----- util-src/pposix.c | 5 ----- util-src/ringbuffer.c | 2 -- util-src/signal.c | 5 ----- util-src/strbitop.c | 3 --- util-src/struct.c | 8 +------- util-src/table.c | 8 +------- util-src/windows.c | 5 ----- 12 files changed, 2 insertions(+), 56 deletions(-) (limited to 'util-src') diff --git a/util-src/crand.c b/util-src/crand.c index e4104787..c6f0a3ba 100644 --- a/util-src/crand.c +++ b/util-src/crand.c @@ -124,9 +124,7 @@ static int Lrandom(lua_State *L) { } int luaopen_util_crand(lua_State *L) { -#if (LUA_VERSION_NUM > 501) luaL_checkversion(L); -#endif lua_createtable(L, 0, 2); lua_pushcfunction(L, Lrandom); diff --git a/util-src/encodings.c b/util-src/encodings.c index 72264da8..157d8526 100644 --- a/util-src/encodings.c +++ b/util-src/encodings.c @@ -21,9 +21,6 @@ #include "lua.h" #include "lauxlib.h" -#if (LUA_VERSION_NUM == 501) -#define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) -#endif #if (LUA_VERSION_NUM < 504) #define luaL_pushfail lua_pushnil #endif @@ -616,9 +613,7 @@ static const luaL_Reg Reg_idna[] = { /***************** end *****************/ LUALIB_API int luaopen_util_encodings(lua_State *L) { -#if (LUA_VERSION_NUM > 501) luaL_checkversion(L); -#endif #ifdef USE_STRINGPREP_ICU init_icu(); #endif diff --git a/util-src/hashes.c b/util-src/hashes.c index fbc86081..5d67ca63 100644 --- a/util-src/hashes.c +++ b/util-src/hashes.c @@ -30,9 +30,6 @@ typedef unsigned __int32 uint32_t; #include #include -#if (LUA_VERSION_NUM == 501) -#define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) -#endif static const char *hex_tab = "0123456789abcdef"; static void toHex(const unsigned char *in, int length, unsigned char *out) { @@ -258,9 +255,7 @@ static const luaL_Reg Reg[] = { }; LUALIB_API int luaopen_util_hashes(lua_State *L) { -#if (LUA_VERSION_NUM > 501) luaL_checkversion(L); -#endif lua_newtable(L); luaL_setfuncs(L, Reg, 0); lua_pushliteral(L, "-3.14"); diff --git a/util-src/net.c b/util-src/net.c index d786e885..96b50e7b 100644 --- a/util-src/net.c +++ b/util-src/net.c @@ -30,9 +30,6 @@ #include #include -#if (LUA_VERSION_NUM == 501) -#define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) -#endif #if (LUA_VERSION_NUM < 504) #define luaL_pushfail lua_pushnil #endif @@ -193,9 +190,7 @@ static int lc_ntop(lua_State *L) { } int luaopen_util_net(lua_State *L) { -#if (LUA_VERSION_NUM > 501) luaL_checkversion(L); -#endif luaL_Reg exports[] = { { "local_addresses", lc_local_addresses }, { "pton", lc_pton }, diff --git a/util-src/poll.c b/util-src/poll.c index 81caa953..d7c1f9e1 100644 --- a/util-src/poll.c +++ b/util-src/poll.c @@ -44,9 +44,6 @@ #define STATE_MT "util.poll<" POLL_BACKEND ">" -#if (LUA_VERSION_NUM == 501) -#define luaL_setmetatable(L, tname) luaL_getmetatable(L, tname); lua_setmetatable(L, -2) -#endif #if (LUA_VERSION_NUM < 504) #define luaL_pushfail lua_pushnil #endif @@ -564,9 +561,7 @@ static int Lnew(lua_State *L) { * Open library */ int luaopen_util_poll(lua_State *L) { -#if (LUA_VERSION_NUM > 501) luaL_checkversion(L); -#endif luaL_newmetatable(L, STATE_MT); { diff --git a/util-src/pposix.c b/util-src/pposix.c index a8e0720f..aac27d35 100644 --- a/util-src/pposix.c +++ b/util-src/pposix.c @@ -58,9 +58,6 @@ #include "lualib.h" #include "lauxlib.h" -#if (LUA_VERSION_NUM == 501) -#define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) -#endif #if (LUA_VERSION_NUM < 503) #define lua_isinteger(L, n) lua_isnumber(L, n) #endif @@ -829,9 +826,7 @@ static int lc_isatty(lua_State *L) { /* Register functions */ int luaopen_util_pposix(lua_State *L) { -#if (LUA_VERSION_NUM > 501) luaL_checkversion(L); -#endif luaL_Reg exports[] = { { "abort", lc_abort }, diff --git a/util-src/ringbuffer.c b/util-src/ringbuffer.c index 0f250c12..95c62de9 100644 --- a/util-src/ringbuffer.c +++ b/util-src/ringbuffer.c @@ -314,9 +314,7 @@ static int rb_new(lua_State *L) { } int luaopen_util_ringbuffer(lua_State *L) { -#if (LUA_VERSION_NUM > 501) luaL_checkversion(L); -#endif if(luaL_newmetatable(L, "ringbuffer_mt")) { lua_pushcfunction(L, rb_tostring); diff --git a/util-src/signal.c b/util-src/signal.c index 1a398fa0..b5ba16a9 100644 --- a/util-src/signal.c +++ b/util-src/signal.c @@ -36,9 +36,6 @@ #include "lua.h" #include "lauxlib.h" -#if (LUA_VERSION_NUM == 501) -#define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) -#endif #if (LUA_VERSION_NUM < 503) #define lua_isinteger(L, n) lua_isnumber(L, n) #endif @@ -381,9 +378,7 @@ static const struct luaL_Reg lsignal_lib[] = { }; int luaopen_util_signal(lua_State *L) { -#if (LUA_VERSION_NUM > 501) luaL_checkversion(L); -#endif int i = 0; /* add the library */ diff --git a/util-src/strbitop.c b/util-src/strbitop.c index fda8917a..722f5a2d 100644 --- a/util-src/strbitop.c +++ b/util-src/strbitop.c @@ -8,9 +8,6 @@ #include #include -#if (LUA_VERSION_NUM == 501) -#define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) -#endif /* TODO Deduplicate code somehow */ diff --git a/util-src/struct.c b/util-src/struct.c index e80df4e6..6267358c 100644 --- a/util-src/struct.c +++ b/util-src/struct.c @@ -36,12 +36,6 @@ #include "lauxlib.h" -#if (LUA_VERSION_NUM >= 502) - -#define luaL_register(L,n,f) luaL_newlib(L,f) - -#endif - /* basic integer type */ #if !defined(STRUCT_INT) @@ -392,7 +386,7 @@ static const struct luaL_Reg thislib[] = { LUALIB_API int luaopen_util_struct (lua_State *L); LUALIB_API int luaopen_util_struct (lua_State *L) { - luaL_register(L, "struct", thislib); + luaL_newlib(L, thislib); return 1; } diff --git a/util-src/table.c b/util-src/table.c index 4bbceedb..ade019c4 100644 --- a/util-src/table.c +++ b/util-src/table.c @@ -6,10 +6,6 @@ #define LUA_MAXINTEGER PTRDIFF_MAX #endif -#if (LUA_VERSION_NUM > 501) -#define lua_equal(L, A, B) lua_compare(L, A, B, LUA_OPEQ) -#endif - static int Lcreate_table(lua_State *L) { lua_createtable(L, luaL_checkinteger(L, 1), luaL_checkinteger(L, 2)); return 1; @@ -47,7 +43,7 @@ static int Lmove (lua_State *L) { n = e - f + 1; /* number of elements to move */ luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, "destination wrap around"); - if (t > e || t <= f || (tt != 1 && !lua_equal(L, 1, tt))) { + if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) { for (i = 0; i < n; i++) { lua_rawgeti(L, 1, f + i); lua_rawseti(L, tt, t + i); @@ -65,9 +61,7 @@ static int Lmove (lua_State *L) { } int luaopen_util_table(lua_State *L) { -#if (LUA_VERSION_NUM > 501) luaL_checkversion(L); -#endif lua_createtable(L, 0, 2); lua_pushcfunction(L, Lcreate_table); lua_setfield(L, -2, "create"); diff --git a/util-src/windows.c b/util-src/windows.c index 57af79d5..2adb85f5 100644 --- a/util-src/windows.c +++ b/util-src/windows.c @@ -19,9 +19,6 @@ #include "lua.h" #include "lauxlib.h" -#if (LUA_VERSION_NUM == 501) -#define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) -#endif #if (LUA_VERSION_NUM < 504) #define luaL_pushfail lua_pushnil #endif @@ -106,9 +103,7 @@ static const luaL_Reg Reg[] = { }; LUALIB_API int luaopen_util_windows(lua_State *L) { -#if (LUA_VERSION_NUM > 501) luaL_checkversion(L); -#endif lua_newtable(L); luaL_setfuncs(L, Reg, 0); lua_pushliteral(L, "-3.14"); -- cgit v1.2.3 From dabdfc91be04257db5a5aae48cb03bcbfb274425 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 11 Jul 2022 20:02:10 +0200 Subject: util.table: Fix inaccurate comment Probably a duplicate of the comment next to Lmove, recorded by mistake Lpack can probably be removed at some point in the near future once we are confident it is not used anywhere. --- util-src/table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'util-src') diff --git a/util-src/table.c b/util-src/table.c index ade019c4..1cbb276d 100644 --- a/util-src/table.c +++ b/util-src/table.c @@ -11,7 +11,7 @@ static int Lcreate_table(lua_State *L) { return 1; } -/* COMPAT: w/ Lua pre-5.4 */ +/* COMPAT: w/ Lua pre-5.2 */ static int Lpack(lua_State *L) { unsigned int n_args = lua_gettop(L); lua_createtable(L, n_args, 1); -- cgit v1.2.3 From 6a64363e782305d17f17bbd22bf940af00108ad2 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 1 Jul 2022 15:11:08 +0100 Subject: util-src: Add new utility header managed_pointer.h The macros in this header allow creation of GC-managed objects from manually- managed C alloc/free APIs. --- util-src/managed_pointer.h | 61 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 util-src/managed_pointer.h (limited to 'util-src') diff --git a/util-src/managed_pointer.h b/util-src/managed_pointer.h new file mode 100644 index 00000000..213b5fd7 --- /dev/null +++ b/util-src/managed_pointer.h @@ -0,0 +1,61 @@ +/* managed_pointer.h + +These macros allow wrapping an allocator/deallocator into an object that is +owned and managed by the Lua garbage collector. + +Why? It is too easy to leak objects that need to be manually released, especially +when dealing with the Lua API which can throw errors from many operations. + +USAGE +----- + +For example, given an object that can be created or released with the following +functions: + + fancy_buffer* new_buffer(); + void free_buffer(fancy_buffer* p_buffer) + +You could declare a managed version like so: + + MANAGED_POINTER_ALLOCATOR(new_managed_buffer, fancy_buffer*, new_buffer, free_buffer) + +And then, when you need to create a new fancy_buffer in your code: + + fancy_buffer *my_buffer = new_managed_buffer(L); + +NOTES +----- + +Managed objects MUST NOT be freed manually. They will automatically be +freed during the next GC sweep after your function exits (even if via an error). + +The managed object is pushed onto the stack, but should generally be ignored, +but you'll need to bear this in mind when creating managed pointers in the +middle of a sequence of stack operations. +*/ + +#define MANAGED_POINTER_MT(wrapped_type) #wrapped_type "_managedptr_mt" + +#define MANAGED_POINTER_ALLOCATOR(name, wrapped_type, wrapped_alloc, wrapped_free) \ + static int _release_ ## name(lua_State *L) { \ + wrapped_type *p = (wrapped_type*)lua_topointer(L, 1); \ + if(*p != NULL) { \ + wrapped_free(*p); \ + } \ + return 0; \ + } \ + static wrapped_type name(lua_State *L) { \ + wrapped_type *p = (wrapped_type*)lua_newuserdata(L, sizeof(wrapped_type)); \ + if(luaL_newmetatable(L, MANAGED_POINTER_MT(wrapped_type)) != 0) { \ + lua_pushcfunction(L, _release_ ## name); \ + lua_setfield(L, -2, "__gc"); \ + } \ + lua_setmetatable(L, -2); \ + *p = wrapped_alloc(); \ + if(*p == NULL) { \ + lua_pushliteral(L, "not enough memory"); \ + lua_error(L); \ + } \ + return *p; \ + } + -- cgit v1.2.3 From b357cf1be1572ae4298f5ef3b43134dd00bc5895 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 24 Jun 2022 16:56:16 +0100 Subject: util.crypto: New wrapper for some operations in OpenSSL's libcrypto Specifically, ED25519 key generation/import/export, sign/verify operations, and AES encrypt/decrypt. --- util-src/GNUmakefile | 4 +- util-src/crypto.c | 555 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 557 insertions(+), 2 deletions(-) create mode 100644 util-src/crypto.c (limited to 'util-src') diff --git a/util-src/GNUmakefile b/util-src/GNUmakefile index 810f39f7..3f539387 100644 --- a/util-src/GNUmakefile +++ b/util-src/GNUmakefile @@ -8,7 +8,7 @@ TARGET?=../util/ ALL=encodings.so hashes.so net.so pposix.so signal.so table.so \ ringbuffer.so time.so poll.so compat.so strbitop.so \ - struct.so + struct.so crypto.so ifdef RANDOM ALL+=crand.so @@ -28,7 +28,7 @@ clean: encodings.o: CFLAGS+=$(IDNA_FLAGS) encodings.so: LDLIBS+=$(IDNA_LIBS) -hashes.so: LDLIBS+=$(OPENSSL_LIBS) +crypto.so hashes.so: LDLIBS+=$(OPENSSL_LIBS) crand.o: CFLAGS+=-DWITH_$(RANDOM) crand.so: LDLIBS+=$(RANDOM_LIBS) diff --git a/util-src/crypto.c b/util-src/crypto.c new file mode 100644 index 00000000..33c175a9 --- /dev/null +++ b/util-src/crypto.c @@ -0,0 +1,555 @@ +/* Prosody IM +-- Copyright (C) 2022 Matthew Wild +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- +*/ + +/* +* crypto.c +* Lua library for cryptographic operations using OpenSSL +*/ + +#include +#include + +#ifdef _MSC_VER +typedef unsigned __int32 uint32_t; +#else +#include +#endif + +#include "lua.h" +#include "lauxlib.h" +#include +#include +#include +#include +#include +#include + +#if (LUA_VERSION_NUM == 501) +#define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) +#endif + +#include "managed_pointer.h" + +#define PKEY_MT_TAG "util.crypto key" + +static BIO* new_memory_BIO() { + return BIO_new(BIO_s_mem()); +} + +MANAGED_POINTER_ALLOCATOR(new_managed_EVP_MD_CTX, EVP_MD_CTX*, EVP_MD_CTX_new, EVP_MD_CTX_free) +MANAGED_POINTER_ALLOCATOR(new_managed_BIO_s_mem, BIO*, new_memory_BIO, BIO_free) +MANAGED_POINTER_ALLOCATOR(new_managed_EVP_CIPHER_CTX, EVP_CIPHER_CTX*, EVP_CIPHER_CTX_new, EVP_CIPHER_CTX_free) + +static EVP_PKEY* pkey_from_arg(lua_State *L, int idx, const int type, const int require_private) { + EVP_PKEY *pkey = *(EVP_PKEY**)luaL_checkudata(L, idx, PKEY_MT_TAG); + if(type || require_private) { + lua_getuservalue(L, idx); + if(type != 0) { + lua_getfield(L, -1, "type"); + if(lua_tointeger(L, -1) != type) { + luaL_argerror(L, idx, "unexpected key type"); + } + lua_pop(L, 1); + } + if(require_private != 0) { + lua_getfield(L, -1, "private"); + if(lua_toboolean(L, -1) != 1) { + luaL_argerror(L, idx, "private key expected, got public key only"); + } + lua_pop(L, 1); + } + lua_pop(L, 1); + } + return pkey; +} + +static int Lpkey_finalizer(lua_State *L) { + EVP_PKEY *pkey = pkey_from_arg(L, 1, 0, 0); + EVP_PKEY_free(pkey); + return 0; +} + +static int Lpkey_meth_get_type(lua_State *L) { + EVP_PKEY *pkey = pkey_from_arg(L, 1, 0, 0); + + int key_type = EVP_PKEY_id(pkey); + lua_pushstring(L, OBJ_nid2sn(key_type)); + return 1; +} + +static int base_evp_sign(lua_State *L, const int key_type, const EVP_MD *digest_type) { + EVP_PKEY *pkey = pkey_from_arg(L, 1, key_type, 1); + luaL_Buffer sigbuf; + + size_t msg_len; + const unsigned char* msg = (unsigned char*)lua_tolstring(L, 2, &msg_len); + + size_t sig_len; + unsigned char *sig = NULL; + EVP_MD_CTX *md_ctx = new_managed_EVP_MD_CTX(L); + + if(EVP_DigestSignInit(md_ctx, NULL, digest_type, NULL, pkey) != 1) { + lua_pushnil(L); + return 1; + } + if(EVP_DigestSign(md_ctx, NULL, &sig_len, msg, msg_len) != 1) { + lua_pushnil(L); + return 1; + } + + // COMPAT w/ Lua 5.1 + luaL_buffinit(L, &sigbuf); + sig = memset(luaL_prepbuffer(&sigbuf), 0, sig_len); + + if(EVP_DigestSign(md_ctx, sig, &sig_len, msg, msg_len) != 1) { + lua_pushnil(L); + } + else { + luaL_addsize(&sigbuf, sig_len); + luaL_pushresult(&sigbuf); + return 1; + } + + return 1; +} + +static int base_evp_verify(lua_State *L, const int key_type, const EVP_MD *digest_type) { + EVP_PKEY *pkey = pkey_from_arg(L, 1, key_type, 0); + + size_t msg_len; + const unsigned char *msg = (unsigned char*)luaL_checklstring(L, 2, &msg_len); + + size_t sig_len; + const unsigned char *sig = (unsigned char*)luaL_checklstring(L, 3, &sig_len); + + EVP_MD_CTX *md_ctx = EVP_MD_CTX_new(); + + if(EVP_DigestVerifyInit(md_ctx, NULL, digest_type, NULL, pkey) != 1) { + lua_pushnil(L); + goto cleanup; + } + int result = EVP_DigestVerify(md_ctx, sig, sig_len, msg, msg_len); + if(result == 0) { + lua_pushboolean(L, 0); + } else if(result != 1) { + lua_pushnil(L); + } + else { + lua_pushboolean(L, 1); + } +cleanup: + EVP_MD_CTX_free(md_ctx); + return 1; +} + +static int Lpkey_meth_public_pem(lua_State *L) { + char *data; + size_t bytes; + EVP_PKEY *pkey = pkey_from_arg(L, 1, 0, 0); + BIO *bio = new_managed_BIO_s_mem(L); + if(PEM_write_bio_PUBKEY(bio, pkey)) { + bytes = BIO_get_mem_data(bio, &data); + if (bytes > 0) { + lua_pushlstring(L, data, bytes); + } + else { + lua_pushnil(L); + } + } + else { + lua_pushnil(L); + } + return 1; +} + +static int Lpkey_meth_private_pem(lua_State *L) { + char *data; + size_t bytes; + EVP_PKEY *pkey = pkey_from_arg(L, 1, 0, 1); + BIO *bio = new_managed_BIO_s_mem(L); + + if(PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL)) { + bytes = BIO_get_mem_data(bio, &data); + if (bytes > 0) { + lua_pushlstring(L, data, bytes); + } + else { + lua_pushnil(L); + } + } + else { + lua_pushnil(L); + } + return 1; +} + +/* ecdsa_sha256_sign(key, data) */ +static int Lecdsa_sha256_sign(lua_State *L) { + return base_evp_sign(L, NID_X9_62_id_ecPublicKey, EVP_sha256()); +} + +/* ecdsa_sha256_verify(key, data, sig) */ +static int Lecdsa_sha256_verify(lua_State *L) { + return base_evp_verify(L, NID_X9_62_id_ecPublicKey, EVP_sha256()); +} + +static int push_pkey(lua_State *L, EVP_PKEY *pkey, const int type, const int privkey) { + EVP_PKEY **ud = lua_newuserdata(L, sizeof(EVP_PKEY*)); + *ud = pkey; + luaL_newmetatable(L, PKEY_MT_TAG); + lua_setmetatable(L, -2); + + /* Set some info about the key and attach it as a user value */ + lua_newtable(L); + if(type != 0) { + lua_pushinteger(L, type); + lua_setfield(L, -2, "type"); + } + if(privkey != 0) { + lua_pushboolean(L, 1); + lua_setfield(L, -2, "private"); + } + lua_setuservalue(L, -2); + return 1; +} + +static int Lgenerate_ed25519_keypair(lua_State *L) { + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, NULL); + + /* Generate key */ + EVP_PKEY_keygen_init(pctx); + EVP_PKEY_keygen(pctx, &pkey); + EVP_PKEY_CTX_free(pctx); + + push_pkey(L, pkey, NID_ED25519, 1); + return 1; +} + +static int Limport_private_pem(lua_State *L) { + EVP_PKEY *pkey = NULL; + + size_t privkey_bytes; + const char* privkey_data; + BIO *bio = new_managed_BIO_s_mem(L); + + privkey_data = luaL_checklstring(L, 1, &privkey_bytes); + BIO_write(bio, privkey_data, privkey_bytes); + pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + if (pkey) { + push_pkey(L, pkey, EVP_PKEY_id(pkey), 1); + } + else { + lua_pushnil(L); + } + + return 1; +} + +static int Limport_public_pem(lua_State *L) { + EVP_PKEY *pkey = NULL; + + size_t pubkey_bytes; + const char* pubkey_data; + BIO *bio = new_managed_BIO_s_mem(L); + + pubkey_data = luaL_checklstring(L, 1, &pubkey_bytes); + BIO_write(bio, pubkey_data, pubkey_bytes); + pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + if (pkey) { + push_pkey(L, pkey, EVP_PKEY_id(pkey), 0); + } + else { + lua_pushnil(L); + } + + return 1; +} + +static int Led25519_sign(lua_State *L) { + return base_evp_sign(L, NID_ED25519, NULL); +} + +static int Led25519_verify(lua_State *L) { + return base_evp_verify(L, NID_ED25519, NULL); +} + +/* gcm_encrypt(key, iv, plaintext) */ +static int Laes_gcm_encrypt(lua_State *L, const EVP_CIPHER *cipher, const unsigned char expected_key_len) { + EVP_CIPHER_CTX *ctx; + luaL_Buffer ciphertext_buffer; + + size_t key_len, iv_len, plaintext_len; + int ciphertext_len, final_len; + + const unsigned char *key = (unsigned char*)luaL_checklstring(L, 1, &key_len); + const unsigned char *iv = (unsigned char*)luaL_checklstring(L, 2, &iv_len); + const unsigned char *plaintext = (unsigned char*)luaL_checklstring(L, 3, &plaintext_len); + + if(key_len != expected_key_len) { + return luaL_error(L, "key must be %d bytes", expected_key_len); + } + luaL_argcheck(L, iv_len == 12, 2, "iv must be 12 bytes"); + if(lua_gettop(L) > 3) { + return luaL_error(L, "Expected 3 arguments, got %d", lua_gettop(L)); + } + + // Create and initialise the context + ctx = new_managed_EVP_CIPHER_CTX(L); + + // Initialise the encryption operation + if(1 != EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL)) { + return luaL_error(L, "Error while initializing encryption engine"); + } + + // Initialise key and IV + if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) { + return luaL_error(L, "Error while initializing key/iv"); + } + + luaL_buffinit(L, &ciphertext_buffer); + unsigned char *ciphertext = (unsigned char*)luaL_prepbuffsize(&ciphertext_buffer, plaintext_len+16); + + if(1 != EVP_EncryptUpdate(ctx, ciphertext, &ciphertext_len, plaintext, plaintext_len)) { + return luaL_error(L, "Error while encrypting data"); + } + + /* + * Finalise the encryption. Normally ciphertext bytes may be written at + * this stage, but this does not occur in GCM mode + */ + if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + ciphertext_len, &final_len)) { + return luaL_error(L, "Error while encrypting final data"); + } + if(final_len != 0) { + return luaL_error(L, "Non-zero final data"); + } + + /* Get the tag */ + if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, ciphertext + ciphertext_len)) { + return luaL_error(L, "Unable to read AEAD tag of encrypted data"); + } + + luaL_addsize(&ciphertext_buffer, ciphertext_len + 16); + luaL_pushresult(&ciphertext_buffer); + + return 1; +} + +static int Laes_128_gcm_encrypt(lua_State *L) { + return Laes_gcm_encrypt(L, EVP_aes_128_gcm(), 16); +} + +static int Laes_256_gcm_encrypt(lua_State *L) { + return Laes_gcm_encrypt(L, EVP_aes_256_gcm(), 32); +} + +/* gcm_decrypt(key, iv, ciphertext) */ +static int Laes_gcm_decrypt(lua_State *L, const EVP_CIPHER *cipher, const unsigned char expected_key_len) { + EVP_CIPHER_CTX *ctx; + luaL_Buffer plaintext_buffer; + + size_t key_len, iv_len, ciphertext_len; + int plaintext_len, final_len; + + const unsigned char *key = (unsigned char*)luaL_checklstring(L, 1, &key_len); + const unsigned char *iv = (unsigned char*)luaL_checklstring(L, 2, &iv_len); + const unsigned char *ciphertext = (unsigned char*)luaL_checklstring(L, 3, &ciphertext_len); + + if(key_len != expected_key_len) { + return luaL_error(L, "key must be %d bytes", expected_key_len); + } + luaL_argcheck(L, iv_len == 12, 2, "iv must be 12 bytes"); + luaL_argcheck(L, ciphertext_len > 16, 3, "ciphertext must be at least 16 bytes (including tag)"); + if(lua_gettop(L) > 3) { + return luaL_error(L, "Expected 3 arguments, got %d", lua_gettop(L)); + } + + /* Create and initialise the context */ + ctx = new_managed_EVP_CIPHER_CTX(L); + + /* Initialise the decryption operation. */ + if(!EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL)) { + return luaL_error(L, "Error while initializing decryption engine"); + } + + /* Initialise key and IV */ + if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) { + return luaL_error(L, "Error while initializing key/iv"); + } + + luaL_buffinit(L, &plaintext_buffer); + unsigned char *plaintext = (unsigned char*)luaL_prepbuffsize(&plaintext_buffer, ciphertext_len); + + /* + * Provide the message to be decrypted, and obtain the plaintext output. + * EVP_DecryptUpdate can be called multiple times if necessary + */ + if(!EVP_DecryptUpdate(ctx, plaintext, &plaintext_len, ciphertext, ciphertext_len-16)) { + return luaL_error(L, "Error while decrypting data"); + } + + /* Set expected tag value. Works in OpenSSL 1.0.1d and later */ + if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, (unsigned char*)ciphertext + (ciphertext_len-16))) { + return luaL_error(L, "Error while processing authentication tag"); + } + + /* + * Finalise the decryption. A positive return value indicates success, + * anything else is a failure - the plaintext is not trustworthy. + */ + int ret = EVP_DecryptFinal_ex(ctx, plaintext + plaintext_len, &final_len); + + if(ret <= 0) { + /* Verify failed */ + lua_pushnil(L); + lua_pushliteral(L, "verify-failed"); + return 2; + } + + luaL_addsize(&plaintext_buffer, plaintext_len + final_len); + luaL_pushresult(&plaintext_buffer); + return 1; +} + +static int Laes_128_gcm_decrypt(lua_State *L) { + return Laes_gcm_decrypt(L, EVP_aes_128_gcm(), 16); +} + +static int Laes_256_gcm_decrypt(lua_State *L) { + return Laes_gcm_decrypt(L, EVP_aes_256_gcm(), 32); +} + +/* r, s = parse_ecdsa_sig(sig_der) */ +static int Lparse_ecdsa_signature(lua_State *L) { + ECDSA_SIG *sig; + size_t sig_der_len; + const unsigned char *sig_der = (unsigned char*)luaL_checklstring(L, 1, &sig_der_len); + const BIGNUM *r, *s; + luaL_Buffer rb, sb; + int rlen, slen; + + sig = d2i_ECDSA_SIG(NULL, &sig_der, sig_der_len); + + if(sig == NULL) { + lua_pushnil(L); + return 1; + } + + ECDSA_SIG_get0(sig, &r, &s); + + rlen = BN_num_bytes(r); + slen = BN_num_bytes(s); + + // COMPAT w/ Lua 5.1 + #if LUAL_BUFFERSIZE < 32 + #error Configured LUAL_BUFFERSIZE is too small for this operation + #endif + + luaL_buffinit(L, &rb); + BN_bn2bin(r, (unsigned char*)luaL_prepbuffer(&rb)); + luaL_addsize(&rb, rlen); + luaL_pushresult(&rb); + + luaL_buffinit(L, &sb); + BN_bn2bin(s, (unsigned char*)luaL_prepbuffer(&sb)); + luaL_addsize(&sb, slen); + luaL_pushresult(&sb); + + ECDSA_SIG_free(sig); + + return 2; +} + +/* sig_der = build_ecdsa_signature(r, s) */ +static int Lbuild_ecdsa_signature(lua_State *L) { + ECDSA_SIG *sig = ECDSA_SIG_new(); + BIGNUM *r, *s; + luaL_Buffer sigbuf; + + size_t rlen, slen; + const unsigned char *rbin, *sbin; + + rbin = (unsigned char*)luaL_checklstring(L, 1, &rlen); + sbin = (unsigned char*)luaL_checklstring(L, 2, &slen); + + r = BN_bin2bn(rbin, (int)rlen, NULL); + s = BN_bin2bn(sbin, (int)slen, NULL); + + ECDSA_SIG_set0(sig, r, s); + + luaL_buffinit(L, &sigbuf); + + // COMPAT w/ Lua 5.1 + #if LUAL_BUFFERSIZE < 128 + #error Configured LUAL_BUFFERSIZE is too small for this operation + #endif + + unsigned char *buffer = (unsigned char*)luaL_prepbuffer(&sigbuf); + int len = i2d_ECDSA_SIG(sig, &buffer); + luaL_addsize(&sigbuf, len); + luaL_pushresult(&sigbuf); + + ECDSA_SIG_free(sig); + + return 1; +} + +static const luaL_Reg Reg[] = { + { "ed25519_sign", Led25519_sign }, + { "ed25519_verify", Led25519_verify }, + { "aes_128_gcm_encrypt", Laes_128_gcm_encrypt }, + { "aes_128_gcm_decrypt", Laes_128_gcm_decrypt }, + { "aes_256_gcm_encrypt", Laes_256_gcm_encrypt }, + { "aes_256_gcm_decrypt", Laes_256_gcm_decrypt }, + { "ecdsa_sha256_sign", Lecdsa_sha256_sign }, + { "ecdsa_sha256_verify", Lecdsa_sha256_verify }, + { "generate_ed25519_keypair", Lgenerate_ed25519_keypair }, + { "import_private_pem", Limport_private_pem }, + { "import_public_pem", Limport_public_pem }, + { "parse_ecdsa_signature", Lparse_ecdsa_signature }, + { "build_ecdsa_signature", Lbuild_ecdsa_signature }, + { NULL, NULL } +}; + +static const luaL_Reg KeyMethods[] = { + { "private_pem", Lpkey_meth_private_pem }, + { "public_pem", Lpkey_meth_public_pem }, + { "get_type", Lpkey_meth_get_type }, + { NULL, NULL } +}; + +static const luaL_Reg KeyMetatable[] = { + { "__gc", Lpkey_finalizer }, + { NULL, NULL } +}; + +LUALIB_API int luaopen_util_crypto(lua_State *L) { +#if (LUA_VERSION_NUM > 501) + luaL_checkversion(L); +#endif + + /* Initialize pkey metatable */ + luaL_newmetatable(L, PKEY_MT_TAG); + luaL_setfuncs(L, KeyMetatable, 0); + lua_newtable(L); + luaL_setfuncs(L, KeyMethods, 0); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); + + /* Initialize lib table */ + lua_newtable(L); + luaL_setfuncs(L, Reg, 0); + lua_pushliteral(L, "-3.14"); + lua_setfield(L, -2, "version"); +#ifdef OPENSSL_VERSION + lua_pushstring(L, OpenSSL_version(OPENSSL_VERSION)); + lua_setfield(L, -2, "_LIBCRYPTO_VERSION"); +#endif + return 1; +} -- cgit v1.2.3 From ba282f10702985ba67b97930ea946524fcce701e Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 2 Jul 2022 11:50:56 +0100 Subject: util.crypto: Add support for RSA signatures (PKCS1-v1.5 + PSS) These are used by the RS*** and PS*** family of JOSE algorithms (e.g. in JWTs) --- util-src/crypto.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) (limited to 'util-src') diff --git a/util-src/crypto.c b/util-src/crypto.c index 33c175a9..49461a7e 100644 --- a/util-src/crypto.c +++ b/util-src/crypto.c @@ -47,11 +47,13 @@ MANAGED_POINTER_ALLOCATOR(new_managed_EVP_CIPHER_CTX, EVP_CIPHER_CTX*, EVP_CIPHE static EVP_PKEY* pkey_from_arg(lua_State *L, int idx, const int type, const int require_private) { EVP_PKEY *pkey = *(EVP_PKEY**)luaL_checkudata(L, idx, PKEY_MT_TAG); + int got_type; if(type || require_private) { lua_getuservalue(L, idx); if(type != 0) { lua_getfield(L, -1, "type"); - if(lua_tointeger(L, -1) != type) { + got_type = lua_tointeger(L, -1); + if(got_type != type) { luaL_argerror(L, idx, "unexpected key type"); } lua_pop(L, 1); @@ -83,7 +85,7 @@ static int Lpkey_meth_get_type(lua_State *L) { } static int base_evp_sign(lua_State *L, const int key_type, const EVP_MD *digest_type) { - EVP_PKEY *pkey = pkey_from_arg(L, 1, key_type, 1); + EVP_PKEY *pkey = pkey_from_arg(L, 1, (key_type!=NID_rsassaPss)?key_type:NID_rsaEncryption, 1); luaL_Buffer sigbuf; size_t msg_len; @@ -97,6 +99,9 @@ static int base_evp_sign(lua_State *L, const int key_type, const EVP_MD *digest_ lua_pushnil(L); return 1; } + if(key_type == NID_rsassaPss) { + EVP_PKEY_CTX_set_rsa_padding(EVP_MD_CTX_pkey_ctx(md_ctx), RSA_PKCS1_PSS_PADDING); + } if(EVP_DigestSign(md_ctx, NULL, &sig_len, msg, msg_len) != 1) { lua_pushnil(L); return 1; @@ -119,7 +124,7 @@ static int base_evp_sign(lua_State *L, const int key_type, const EVP_MD *digest_ } static int base_evp_verify(lua_State *L, const int key_type, const EVP_MD *digest_type) { - EVP_PKEY *pkey = pkey_from_arg(L, 1, key_type, 0); + EVP_PKEY *pkey = pkey_from_arg(L, 1, (key_type!=NID_rsassaPss)?key_type:NID_rsaEncryption, 0); size_t msg_len; const unsigned char *msg = (unsigned char*)luaL_checklstring(L, 2, &msg_len); @@ -133,6 +138,9 @@ static int base_evp_verify(lua_State *L, const int key_type, const EVP_MD *diges lua_pushnil(L); goto cleanup; } + if(key_type == NID_rsassaPss) { + EVP_PKEY_CTX_set_rsa_padding(EVP_MD_CTX_pkey_ctx(md_ctx), RSA_PKCS1_PSS_PADDING); + } int result = EVP_DigestVerify(md_ctx, sig, sig_len, msg, msg_len); if(result == 0) { lua_pushboolean(L, 0); @@ -279,6 +287,22 @@ static int Led25519_verify(lua_State *L) { return base_evp_verify(L, NID_ED25519, NULL); } +static int Lrsassa_pkcs1_256_sign(lua_State *L) { + return base_evp_sign(L, NID_rsaEncryption, EVP_sha256()); +} + +static int Lrsassa_pkcs1_256_verify(lua_State *L) { + return base_evp_verify(L, NID_rsaEncryption, EVP_sha256()); +} + +static int Lrsassa_pss_256_sign(lua_State *L) { + return base_evp_sign(L, NID_rsassaPss, EVP_sha256()); +} + +static int Lrsassa_pss_256_verify(lua_State *L) { + return base_evp_verify(L, NID_rsassaPss, EVP_sha256()); +} + /* gcm_encrypt(key, iv, plaintext) */ static int Laes_gcm_encrypt(lua_State *L, const EVP_CIPHER *cipher, const unsigned char expected_key_len) { EVP_CIPHER_CTX *ctx; @@ -503,6 +527,10 @@ static int Lbuild_ecdsa_signature(lua_State *L) { static const luaL_Reg Reg[] = { { "ed25519_sign", Led25519_sign }, { "ed25519_verify", Led25519_verify }, + { "rsassa_pkcs1_256_sign", Lrsassa_pkcs1_256_sign }, + { "rsassa_pkcs1_256_verify", Lrsassa_pkcs1_256_verify }, + { "rsassa_pss_256_sign", Lrsassa_pss_256_sign }, + { "rsassa_pss_256_verify", Lrsassa_pss_256_verify }, { "aes_128_gcm_encrypt", Laes_128_gcm_encrypt }, { "aes_128_gcm_decrypt", Laes_128_gcm_decrypt }, { "aes_256_gcm_encrypt", Laes_256_gcm_encrypt }, -- cgit v1.2.3 From d7b32f1b71f4806081a99c37296f316942fc03ac Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 2 Jul 2022 11:51:24 +0100 Subject: util.crypto: Friendlier error message on incorrect key types --- util-src/crypto.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'util-src') diff --git a/util-src/crypto.c b/util-src/crypto.c index 49461a7e..f2192ce2 100644 --- a/util-src/crypto.c +++ b/util-src/crypto.c @@ -45,6 +45,8 @@ MANAGED_POINTER_ALLOCATOR(new_managed_EVP_MD_CTX, EVP_MD_CTX*, EVP_MD_CTX_new, E MANAGED_POINTER_ALLOCATOR(new_managed_BIO_s_mem, BIO*, new_memory_BIO, BIO_free) MANAGED_POINTER_ALLOCATOR(new_managed_EVP_CIPHER_CTX, EVP_CIPHER_CTX*, EVP_CIPHER_CTX_new, EVP_CIPHER_CTX_free) +#define CRYPTO_KEY_TYPE_ERR "unexpected key type: got '%s', expected '%s'" + static EVP_PKEY* pkey_from_arg(lua_State *L, int idx, const int type, const int require_private) { EVP_PKEY *pkey = *(EVP_PKEY**)luaL_checkudata(L, idx, PKEY_MT_TAG); int got_type; @@ -54,7 +56,10 @@ static EVP_PKEY* pkey_from_arg(lua_State *L, int idx, const int type, const int lua_getfield(L, -1, "type"); got_type = lua_tointeger(L, -1); if(got_type != type) { - luaL_argerror(L, idx, "unexpected key type"); + const char *got_key_type_name = OBJ_nid2sn(got_type); + const char *want_key_type_name = OBJ_nid2sn(type); + lua_pushfstring(L, CRYPTO_KEY_TYPE_ERR, got_key_type_name, want_key_type_name); + luaL_argerror(L, idx, lua_tostring(L, -1)); } lua_pop(L, 1); } -- cgit v1.2.3 From 5316b0005e042f1abeb1ac5fed8715ab65e6752c Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 2 Jul 2022 14:59:52 +0100 Subject: util.crypto: More digests for sign/verify, use macros for clarity/consistency --- util-src/crypto.c | 72 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 32 deletions(-) (limited to 'util-src') diff --git a/util-src/crypto.c b/util-src/crypto.c index f2192ce2..6822b9bf 100644 --- a/util-src/crypto.c +++ b/util-src/crypto.c @@ -201,16 +201,6 @@ static int Lpkey_meth_private_pem(lua_State *L) { return 1; } -/* ecdsa_sha256_sign(key, data) */ -static int Lecdsa_sha256_sign(lua_State *L) { - return base_evp_sign(L, NID_X9_62_id_ecPublicKey, EVP_sha256()); -} - -/* ecdsa_sha256_verify(key, data, sig) */ -static int Lecdsa_sha256_verify(lua_State *L) { - return base_evp_verify(L, NID_X9_62_id_ecPublicKey, EVP_sha256()); -} - static int push_pkey(lua_State *L, EVP_PKEY *pkey, const int type, const int privkey) { EVP_PKEY **ud = lua_newuserdata(L, sizeof(EVP_PKEY*)); *ud = pkey; @@ -292,22 +282,6 @@ static int Led25519_verify(lua_State *L) { return base_evp_verify(L, NID_ED25519, NULL); } -static int Lrsassa_pkcs1_256_sign(lua_State *L) { - return base_evp_sign(L, NID_rsaEncryption, EVP_sha256()); -} - -static int Lrsassa_pkcs1_256_verify(lua_State *L) { - return base_evp_verify(L, NID_rsaEncryption, EVP_sha256()); -} - -static int Lrsassa_pss_256_sign(lua_State *L) { - return base_evp_sign(L, NID_rsassaPss, EVP_sha256()); -} - -static int Lrsassa_pss_256_verify(lua_State *L) { - return base_evp_verify(L, NID_rsassaPss, EVP_sha256()); -} - /* gcm_encrypt(key, iv, plaintext) */ static int Laes_gcm_encrypt(lua_State *L, const EVP_CIPHER *cipher, const unsigned char expected_key_len) { EVP_CIPHER_CTX *ctx; @@ -529,22 +503,56 @@ static int Lbuild_ecdsa_signature(lua_State *L) { return 1; } +#define REG_SIGN_VERIFY(algorithm, digest) \ + { #algorithm "_" #digest "_sign", L ## algorithm ## _ ## digest ## _sign },\ + { #algorithm "_" #digest "_verify", L ## algorithm ## _ ## digest ## _verify }, + +#define IMPL_SIGN_VERIFY(algorithm, key_type, digest) \ + static int L ## algorithm ## _ ## digest ## _sign(lua_State *L) { \ + return base_evp_sign(L, key_type, EVP_ ## digest()); \ + } \ + static int L ## algorithm ## _ ## digest ## _verify(lua_State *L) { \ + return base_evp_verify(L, key_type, EVP_ ## digest()); \ + } + +IMPL_SIGN_VERIFY(ecdsa, NID_X9_62_id_ecPublicKey, sha256) +IMPL_SIGN_VERIFY(ecdsa, NID_X9_62_id_ecPublicKey, sha384) +IMPL_SIGN_VERIFY(ecdsa, NID_X9_62_id_ecPublicKey, sha512) + +IMPL_SIGN_VERIFY(rsassa_pkcs1, NID_rsaEncryption, sha256) +IMPL_SIGN_VERIFY(rsassa_pkcs1, NID_rsaEncryption, sha384) +IMPL_SIGN_VERIFY(rsassa_pkcs1, NID_rsaEncryption, sha512) + +IMPL_SIGN_VERIFY(rsassa_pss, NID_rsassaPss, sha256) +IMPL_SIGN_VERIFY(rsassa_pss, NID_rsassaPss, sha384) +IMPL_SIGN_VERIFY(rsassa_pss, NID_rsassaPss, sha512) + static const luaL_Reg Reg[] = { { "ed25519_sign", Led25519_sign }, { "ed25519_verify", Led25519_verify }, - { "rsassa_pkcs1_256_sign", Lrsassa_pkcs1_256_sign }, - { "rsassa_pkcs1_256_verify", Lrsassa_pkcs1_256_verify }, - { "rsassa_pss_256_sign", Lrsassa_pss_256_sign }, - { "rsassa_pss_256_verify", Lrsassa_pss_256_verify }, + + REG_SIGN_VERIFY(ecdsa, sha256) + REG_SIGN_VERIFY(ecdsa, sha384) + REG_SIGN_VERIFY(ecdsa, sha512) + + REG_SIGN_VERIFY(rsassa_pkcs1, sha256) + REG_SIGN_VERIFY(rsassa_pkcs1, sha384) + REG_SIGN_VERIFY(rsassa_pkcs1, sha512) + + REG_SIGN_VERIFY(rsassa_pss, sha256) + REG_SIGN_VERIFY(rsassa_pss, sha384) + REG_SIGN_VERIFY(rsassa_pss, sha512) + { "aes_128_gcm_encrypt", Laes_128_gcm_encrypt }, { "aes_128_gcm_decrypt", Laes_128_gcm_decrypt }, { "aes_256_gcm_encrypt", Laes_256_gcm_encrypt }, { "aes_256_gcm_decrypt", Laes_256_gcm_decrypt }, - { "ecdsa_sha256_sign", Lecdsa_sha256_sign }, - { "ecdsa_sha256_verify", Lecdsa_sha256_verify }, + { "generate_ed25519_keypair", Lgenerate_ed25519_keypair }, + { "import_private_pem", Limport_private_pem }, { "import_public_pem", Limport_public_pem }, + { "parse_ecdsa_signature", Lparse_ecdsa_signature }, { "build_ecdsa_signature", Lbuild_ecdsa_signature }, { NULL, NULL } -- cgit v1.2.3 From e893bbf6817ff4193d9639afc40143fd792c9a4b Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 11 Jul 2022 17:01:55 +0200 Subject: util.crypto: Use stack space buffers Removes assumption that LUAL_BUFFERSIZE is known at pre-processing time, which it is not in Lua 5.3 and 5.4, where it is a computed macro based on sizeof. Allocation of stack space is safer and faster, no need to worry about luaL_prepbuffer failing to allocate memory and skipping free() --- util-src/crypto.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'util-src') diff --git a/util-src/crypto.c b/util-src/crypto.c index 6822b9bf..0f4edb51 100644 --- a/util-src/crypto.c +++ b/util-src/crypto.c @@ -434,7 +434,8 @@ static int Lparse_ecdsa_signature(lua_State *L) { size_t sig_der_len; const unsigned char *sig_der = (unsigned char*)luaL_checklstring(L, 1, &sig_der_len); const BIGNUM *r, *s; - luaL_Buffer rb, sb; + unsigned char rb[32]; + unsigned char sb[32]; int rlen, slen; sig = d2i_ECDSA_SIG(NULL, &sig_der, sig_der_len); @@ -449,23 +450,19 @@ static int Lparse_ecdsa_signature(lua_State *L) { rlen = BN_num_bytes(r); slen = BN_num_bytes(s); - // COMPAT w/ Lua 5.1 - #if LUAL_BUFFERSIZE < 32 - #error Configured LUAL_BUFFERSIZE is too small for this operation - #endif - - luaL_buffinit(L, &rb); - BN_bn2bin(r, (unsigned char*)luaL_prepbuffer(&rb)); - luaL_addsize(&rb, rlen); - luaL_pushresult(&rb); + if (rlen > 32 || slen > 32) { + ECDSA_SIG_free(sig); + luaL_error(L, "unexpectedly large signature integers"); + } - luaL_buffinit(L, &sb); - BN_bn2bin(s, (unsigned char*)luaL_prepbuffer(&sb)); - luaL_addsize(&sb, slen); - luaL_pushresult(&sb); + BN_bn2bin(r, rb); + BN_bn2bin(s, sb); ECDSA_SIG_free(sig); + lua_pushlstring(L, (const char*)rb, rlen); + lua_pushlstring(L, (const char*)sb, slen); + return 2; } -- cgit v1.2.3 From 62438f482ed8cf1c361dc4904baefcd893998403 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 11 Jul 2022 17:11:38 +0200 Subject: util.crypto: Use Lua 5.2 API for predictable buffer size In Lua 5.3 LUAL_BUFFERSIZE is a macro computed from sizeof and is thus not known at pre-processing time, so this does not work. Since Lua 5.1 is no longer supported, we can use luaL_prepbuffsize() which is available from Lua 5.2 --- util-src/crypto.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'util-src') diff --git a/util-src/crypto.c b/util-src/crypto.c index 0f4edb51..c5ecf9ab 100644 --- a/util-src/crypto.c +++ b/util-src/crypto.c @@ -485,12 +485,7 @@ static int Lbuild_ecdsa_signature(lua_State *L) { luaL_buffinit(L, &sigbuf); - // COMPAT w/ Lua 5.1 - #if LUAL_BUFFERSIZE < 128 - #error Configured LUAL_BUFFERSIZE is too small for this operation - #endif - - unsigned char *buffer = (unsigned char*)luaL_prepbuffer(&sigbuf); + unsigned char *buffer = (unsigned char*)luaL_prepbuffsize(&sigbuf, rlen+slen+32); int len = i2d_ECDSA_SIG(sig, &buffer); luaL_addsize(&sigbuf, len); luaL_pushresult(&sigbuf); -- cgit v1.2.3 From 8695a72a668fa38f1df64653508c360534e5e3db Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 29 Sep 2022 23:15:39 +0100 Subject: util.crypto, util.jwt: Generate consistent signature sizes (via padding) This fixes the signature parsing and building to work correctly. Sometimes a signature was one or two bytes too short, and needed to be padded. OpenSSL can do this for us. --- util-src/crypto.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'util-src') diff --git a/util-src/crypto.c b/util-src/crypto.c index c5ecf9ab..dce1a740 100644 --- a/util-src/crypto.c +++ b/util-src/crypto.c @@ -33,6 +33,9 @@ typedef unsigned __int32 uint32_t; #define luaL_setfuncs(L, R, N) luaL_register(L, NULL, R) #endif +/* The max size of an encoded 'R' or 'S' value. P-521 = 521 bits = 66 bytes */ +#define MAX_ECDSA_SIG_INT_BYTES 66 + #include "managed_pointer.h" #define PKEY_MT_TAG "util.crypto key" @@ -433,10 +436,15 @@ static int Lparse_ecdsa_signature(lua_State *L) { ECDSA_SIG *sig; size_t sig_der_len; const unsigned char *sig_der = (unsigned char*)luaL_checklstring(L, 1, &sig_der_len); + const size_t sig_int_bytes = luaL_checkinteger(L, 2); const BIGNUM *r, *s; - unsigned char rb[32]; - unsigned char sb[32]; int rlen, slen; + unsigned char rb[MAX_ECDSA_SIG_INT_BYTES]; + unsigned char sb[MAX_ECDSA_SIG_INT_BYTES]; + + if(sig_int_bytes > MAX_ECDSA_SIG_INT_BYTES) { + luaL_error(L, "requested signature size exceeds supported limit"); + } sig = d2i_ECDSA_SIG(NULL, &sig_der, sig_der_len); @@ -447,17 +455,14 @@ static int Lparse_ecdsa_signature(lua_State *L) { ECDSA_SIG_get0(sig, &r, &s); - rlen = BN_num_bytes(r); - slen = BN_num_bytes(s); + rlen = BN_bn2binpad(r, rb, sig_int_bytes); + slen = BN_bn2binpad(s, sb, sig_int_bytes); - if (rlen > 32 || slen > 32) { + if (rlen == -1 || slen == -1) { ECDSA_SIG_free(sig); - luaL_error(L, "unexpectedly large signature integers"); + luaL_error(L, "encoded integers exceed requested size"); } - BN_bn2bin(r, rb); - BN_bn2bin(s, sb); - ECDSA_SIG_free(sig); lua_pushlstring(L, (const char*)rb, rlen); @@ -485,7 +490,9 @@ static int Lbuild_ecdsa_signature(lua_State *L) { luaL_buffinit(L, &sigbuf); - unsigned char *buffer = (unsigned char*)luaL_prepbuffsize(&sigbuf, rlen+slen+32); + /* DER structure of an ECDSA signature has 7 bytes plus the integers themselves, + which may gain an extra byte once encoded */ + unsigned char *buffer = (unsigned char*)luaL_prepbuffsize(&sigbuf, (rlen+1)+(slen+1)+7); int len = i2d_ECDSA_SIG(sig, &buffer); luaL_addsize(&sigbuf, len); luaL_pushresult(&sigbuf); -- cgit v1.2.3