From 6a8ec191a5c99100ebd9c6cddce62c3b4a098b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kr=C3=BCger?= Date: Tue, 21 Dec 2021 09:51:42 +0100 Subject: [PATCH] gluon-lib-ecdsa: init --- package/gluon-lib-ecdsa/Makefile | 20 ++++ package/gluon-lib-ecdsa/src/Makefile | 22 ++++ package/gluon-lib-ecdsa/src/ecdsa.c | 68 +++++++++++++ package/gluon-lib-ecdsa/src/ecdsa_util.c | 93 +++++++++++++++++ package/gluon-lib-ecdsa/src/ecdsa_util.h | 18 ++++ package/gluon-lib-ecdsa/src/hexutil.c | 58 +++++++++++ package/gluon-lib-ecdsa/src/hexutil.h | 38 +++++++ package/gluon-lib-ecdsa/src/util.c | 122 +++++++++++++++++++++++ package/gluon-lib-ecdsa/src/util.h | 35 +++++++ 9 files changed, 474 insertions(+) create mode 100644 package/gluon-lib-ecdsa/Makefile create mode 100644 package/gluon-lib-ecdsa/src/Makefile create mode 100644 package/gluon-lib-ecdsa/src/ecdsa.c create mode 100644 package/gluon-lib-ecdsa/src/ecdsa_util.c create mode 100644 package/gluon-lib-ecdsa/src/ecdsa_util.h create mode 100644 package/gluon-lib-ecdsa/src/hexutil.c create mode 100644 package/gluon-lib-ecdsa/src/hexutil.h create mode 100644 package/gluon-lib-ecdsa/src/util.c create mode 100644 package/gluon-lib-ecdsa/src/util.h diff --git a/package/gluon-lib-ecdsa/Makefile b/package/gluon-lib-ecdsa/Makefile new file mode 100644 index 00000000..f084ebd6 --- /dev/null +++ b/package/gluon-lib-ecdsa/Makefile @@ -0,0 +1,20 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-lib-ecdsa +PKG_VERSION=1 + +include ../gluon.mk + +define Package/gluon-lib-ecdsa + TITLE:=Lua bindings for ecdsautil + DEPENDS:=+liblua +libecdsautil +endef + +define Package/gluon-lib-ecdsa/install + $(Gluon/Build/Install) + + $(INSTALL_DIR) $(1)/usr/lib/lua/gluon + $(INSTALL_BIN) $(PKG_BUILD_DIR)/ecdsa.so $(1)/usr/lib/lua/gluon/ +endef + +$(eval $(call BuildPackageGluon,gluon-lib-ecdsa)) diff --git a/package/gluon-lib-ecdsa/src/Makefile b/package/gluon-lib-ecdsa/src/Makefile new file mode 100644 index 00000000..9e09bf10 --- /dev/null +++ b/package/gluon-lib-ecdsa/src/Makefile @@ -0,0 +1,22 @@ +CFLAGS += -Wall -fPIC +LDFLAGS += -llua -lm +OBJ = hexutil.o ecdsa_util.o util.c ecdsa.o +LIB = ecdsa.so + +CFLAGS += $(shell pkg-config --cflags ecdsautil) +LDFLAGS += $(shell pkg-config --libs ecdsautil) + +%.o: %.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LUA_CFLAGS) $(CFLAGS) $(FPIC) -c -o $@ $< + +all: compile + +compile: $(OBJ) + $(CC) $(LDFLAGS) -fPIC -shared -o $(LIB) $(OBJ) $(LDFLAGS) + +install: compile + mkdir -p $(DESTDIR)/usr/lib/lua/gluon + cp $(LIB) $(DESTDIR)/usr/lib/lua/gluon/$(LIB) + +clean: + rm -f *.o *.so diff --git a/package/gluon-lib-ecdsa/src/ecdsa.c b/package/gluon-lib-ecdsa/src/ecdsa.c new file mode 100644 index 00000000..252d489d --- /dev/null +++ b/package/gluon-lib-ecdsa/src/ecdsa.c @@ -0,0 +1,68 @@ +/* +Copyright 2021 Maciej Krüger + +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. +*/ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ecdsa_util.h" + +#define ECDSA "gluon.ecdsa" + +static bool verify(lua_State *L, const char *data, const char *sig, const char *key) { + struct verify_params params = { + .good_signatures = 1, + .data = data + }; + + if (!load_signatures(¶ms, 1, &sig, false)) { + return luaL_error(L, "failed loading signature"); + } + + if (!load_pubkeys(¶ms, 1, &key, false)) { + return luaL_error(L, "failed loading keys"); + } + + return do_verify(¶ms); +} + +static int lua_verify(lua_State *L) { + lua_pushboolean(L, verify(L, luaL_checkstring(L, 1), luaL_checkstring(L, 2), luaL_checkstring(L, 3))); + return 1; +} + +static const luaL_reg ecdsa_methods[] = { + { "verify", lua_verify }, + + { } +}; + +int luaopen_gluon_ecdsa(lua_State *L) +{ + luaL_register(L, ECDSA, ecdsa_methods); + + return 1; +} diff --git a/package/gluon-lib-ecdsa/src/ecdsa_util.c b/package/gluon-lib-ecdsa/src/ecdsa_util.c new file mode 100644 index 00000000..856a987f --- /dev/null +++ b/package/gluon-lib-ecdsa/src/ecdsa_util.c @@ -0,0 +1,93 @@ +#include "ecdsa_util.h" +#include "hexutil.h" +#include "util.h" + +#include +#include +#include +#include +#include +#include +#include + +bool do_verify(struct verify_params* params) { + ecdsa_sha256_context_t hash_ctx; + ecdsa_sha256_init(&hash_ctx); + ecdsa_sha256_update(&hash_ctx, params->data, strlen(params->data)); + + ecc_int256_t hash; + ecdsa_sha256_final(&hash_ctx, hash.p); + + ecdsa_verify_context_t ctxs[params->n_signatures]; + for (size_t i = 0; i < params->n_signatures; i++) + ecdsa_verify_prepare_legacy(&ctxs[i], &hash, params->signatures[i]); + + long unsigned int good_signatures = ecdsa_verify_list_legacy(ctxs, params->n_signatures, params->pubkeys, params->n_pubkeys); + + if (good_signatures < params->good_signatures) { + return false; + } + + return true; +} + +int load_pubkeys(struct verify_params* params, const size_t n_pubkeys, const char **pubkeys_str, const bool ignore_pubkeys) { + params->n_pubkeys = n_pubkeys; + params->pubkeys = safe_malloc(n_pubkeys * sizeof(ecc_25519_work_t)); + + size_t ignored_keys = 0; + + for (size_t i = 0; i < params->n_pubkeys; i++) { + ecc_int256_t pubkey_packed; + if (!pubkeys_str[i]) + goto pubkey_fail; + if (!parsehex(pubkey_packed.p, pubkeys_str[i], 32)) + goto pubkey_fail; + if (!ecc_25519_load_packed_legacy(¶ms->pubkeys[i-ignored_keys], &pubkey_packed)) + goto pubkey_fail; + if (!ecdsa_is_valid_pubkey(¶ms->pubkeys[i-ignored_keys])) + goto pubkey_fail; + continue; + +pubkey_fail: + if (ignore_pubkeys) { + fprintf(stderr, "warning: ignoring invalid public key %s\n", pubkeys_str[i]); + ignored_keys++; + } else { + return 0; + } + } + + params->n_pubkeys -= ignored_keys; + + return 1; +} + +int load_signatures(struct verify_params* params, const size_t n_signatures, const char **signatures_str, const bool ignore_signatures) { + params->n_signatures = n_signatures; + params->signatures = safe_malloc(n_signatures * sizeof(ecdsa_signature_t)); + + size_t ignored_signatures = 0; + + for (size_t i = 0; i < params->n_pubkeys; i++) { + ecdsa_signature_t* signature; + if (!signatures_str[i]) + goto signature_fail; + if (!parsehex(signature, signatures_str[i], 64)) + goto signature_fail; + params->signatures[i-ignored_signatures] = &signature; + continue; + +signature_fail: + if (ignore_signatures) { + fprintf(stderr, "warning: ignoring invalid signature %s\n", signatures_str[i]); + ignored_signatures++; + } else { + return 0; + } + } + + params->n_signatures -= ignored_signatures; + + return 1; +} diff --git a/package/gluon-lib-ecdsa/src/ecdsa_util.h b/package/gluon-lib-ecdsa/src/ecdsa_util.h new file mode 100644 index 00000000..34576d1f --- /dev/null +++ b/package/gluon-lib-ecdsa/src/ecdsa_util.h @@ -0,0 +1,18 @@ +#include +#include + +struct verify_params { + const char* data; + + size_t n_signatures; + ecdsa_signature_t **signatures; + + size_t n_pubkeys; + ecc_25519_work_t *pubkeys; + + unsigned long good_signatures; +}; + +bool do_verify(struct verify_params* params); +int load_pubkeys(struct verify_params* params, const size_t n_pubkeys, const char **pubkeys_str, const bool ignore_pubkeys); +int load_signatures(struct verify_params* params, const size_t n_signatures, const char **signatures_str, const bool ignore_signatures); diff --git a/package/gluon-lib-ecdsa/src/hexutil.c b/package/gluon-lib-ecdsa/src/hexutil.c new file mode 100644 index 00000000..7a3eb6ed --- /dev/null +++ b/package/gluon-lib-ecdsa/src/hexutil.c @@ -0,0 +1,58 @@ +/* + Copyright (c) 2012, Nils Schneider + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "hexutil.h" + +#include +#include + +int parsehex(void *buffer, const char *string, size_t len) { + // number of digits must be even + if ((strlen(string) & 1) == 1) + return 0; + + // number of digits must be 2 * len + if (strlen(string) != 2 * len) + return 0; + + while (len--) { + int ret; + ret = sscanf(string, "%02hhx", (char*)(buffer++)); + string += 2; + + if (ret != 1) + break; + } + + if (len != -1) + return 0; + + return 1; +} + +void hexdump(FILE *stream, unsigned char *buffer, size_t len) { + while (len--) + fprintf(stream, "%02hhx", *(buffer++)); +} diff --git a/package/gluon-lib-ecdsa/src/hexutil.h b/package/gluon-lib-ecdsa/src/hexutil.h new file mode 100644 index 00000000..6d905f91 --- /dev/null +++ b/package/gluon-lib-ecdsa/src/hexutil.h @@ -0,0 +1,38 @@ +/* + Copyright (c) 2012, Nils Schneider + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#pragma once + +#include + + +/* Converts a string of hexadecimal digits and stores it in a given buffer. + * In order for this function to return successfully the decoded string + * must fit exactly into the buffer. + */ +int parsehex(void *buffer, const char *string, size_t len); + +/* Converts a byte array to a hexadecimal string. + */ +void hexdump(FILE *stream, unsigned char *buffer, size_t len); diff --git a/package/gluon-lib-ecdsa/src/util.c b/package/gluon-lib-ecdsa/src/util.c new file mode 100644 index 00000000..ff21d4ff --- /dev/null +++ b/package/gluon-lib-ecdsa/src/util.c @@ -0,0 +1,122 @@ +/* + Copyright (c) 2017, Jan-Philipp Litza + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "util.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + + +void run_dir(const char *dir) { + char pat[strlen(dir) + 3]; + sprintf(pat, "%s/*", dir); + glob_t globbuf; + if (glob(pat, 0, NULL, &globbuf)) + return; + + for (size_t i = 0; i < globbuf.gl_pathc; i++) { + char *path = globbuf.gl_pathv[i]; + if (access(path, X_OK) < 0) + continue; + + pid_t pid = fork(); + if (pid < 0) { + fputs("autoupdater: warning: failed to fork: %m", stderr); + continue; + } + + if (pid == 0) { + execl(path, path, (char *)NULL); + exit(EXIT_FAILURE); + } + + int wstatus; + if (waitpid(pid, &wstatus, 0) != pid) { + fprintf(stderr, "autoupdater: warning: failed waiting for child %d corresponding to %s: ", pid, path); + perror(NULL); + } else if (!WIFEXITED(wstatus)) { + fprintf(stderr, "autoupdater: warning: execution of %s exited abnormally\n", path); + } else if (WEXITSTATUS(wstatus)) { + fprintf(stderr, "autoupdater: warning: execution of %s exited with status code %d\n", path, WEXITSTATUS(wstatus)); + } + } + + globfree(&globbuf); +} + + +void randomize(void) { + struct timespec tv; + if (clock_gettime(CLOCK_MONOTONIC, &tv)) { + perror("autoupdater: error: clock_gettime"); + exit(1); + } + + srandom(tv.tv_nsec); +} + + +float get_uptime(void) { + FILE *f = fopen("/proc/uptime", "r"); + if (f) { + float uptime; + int match = fscanf(f, "%f", &uptime); + fclose(f); + + if (match == 1) + return uptime; + } + + fputs("autoupdater: error: unable to determine uptime\n", stderr); + exit(1); +} + +void * safe_malloc(size_t size) { + void *ret = malloc(size); + if (!ret) { + fprintf(stderr, "autoupdater: error: failed to allocate memory\n"); + abort(); + } + + return ret; +} + +void * safe_realloc(void *ptr, size_t size) { + void *ret = realloc(ptr, size); + if (!ret) { + fprintf(stderr, "autoupdater: error: failed to allocate memory\n"); + abort(); + } + + return ret; +} diff --git a/package/gluon-lib-ecdsa/src/util.h b/package/gluon-lib-ecdsa/src/util.h new file mode 100644 index 00000000..305cc3a4 --- /dev/null +++ b/package/gluon-lib-ecdsa/src/util.h @@ -0,0 +1,35 @@ +/* + Copyright (c) 2017, Jan-Philipp Litza + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#pragma once + +#include + + +void run_dir(const char *dir); +void randomize(void); +float get_uptime(void); + +void * safe_malloc(size_t size); +void * safe_realloc(void *ptr, size_t size);