Compare commits

...

7 Commits

Author SHA1 Message Date
lemoer 827569aaeb
Merge 0b263bc766 into 3d08b0fee8 2024-01-22 23:26:18 +01:00
Florian Maurer 3d08b0fee8 wgpeerselector: fix undefined variable peer
Signed-off-by: Florian Maurer <f.maurer@outlook.de>
2024-01-22 23:22:23 +01:00
Matthias Schiffer 53ea3b8977 libplatforminfo: update bcm27xx target name
The RPi targets were renamed in OpenWrt 21.02 (Gluon 2022.1). As
libplatforminfo was not adjusted, image names were using autodetected
model names including a revision number again, requiring additional
manifest aliases.
2023-12-19 18:40:02 +01:00
Matthias Schiffer 28a35ea2c9 libplatforminfo: drop obsolete ar71xx-mikrotik target
The obsolete ar71xx-mikrotik.c was symlinked to template/nosysupgrade.c.
As all new mikrotik targets have sysupgrade support, we can just remove
the symlink and use the default handling of libplatforminfo.

nosysupgrade.c becomes unused, but it left in the repository for future
experimental targets without sysupgrade support.
2023-12-19 18:40:02 +01:00
Leonardo Mörlein 0b263bc766 respondd: rename pubkey to secure_nodeid 2021-02-13 22:18:12 +01:00
Leonardo Mörlein 84a7ab8074 respondd: generate ed25519 key if not existing 2021-02-13 21:35:24 +01:00
Leonardo Mörlein df328249e2 respondd: implement ed25519 signature
As of now, the private key is hardcoded into respondd. This will be
changed later.
2021-02-13 21:35:24 +01:00
7 changed files with 212 additions and 5 deletions

View File

@ -1 +0,0 @@
template/nosysupgrade.c

View File

@ -11,11 +11,16 @@ include $(INCLUDE_DIR)/cmake.mk
define Package/respondd
SECTION:=net
CATEGORY:=Network
DEPENDS:=@IPV6 +libjson-c
DEPENDS:=@IPV6 +libjson-c +libecdsautil +libuci
TITLE:=Responds to multicast queries with answers generated by Lua code
endef
define Package/respondd/conffiles
/etc/config/respondd
endef
define Package/respondd/install
$(CP) ./files/* $(1)/
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/respondd $(1)/usr/bin/
endef

View File

@ -0,0 +1,2 @@
config respondd settings

View File

@ -8,11 +8,25 @@ find_package(JSON_C REQUIRED)
set_property(DIRECTORY PROPERTY COMPILE_DEFINITIONS _GNU_SOURCE)
# libuci
find_library(UCI_LIBRARY NAMES uci)
include_directories(${UCI_INCLUDE_DIRS})
# libecdsautil
find_package(PkgConfig REQUIRED QUIET)
pkg_check_modules(ECDSAUTIL REQUIRED ecdsautil)
include_directories(${ECDSAUTIL_INCLUDE_DIRS})
add_executable(respondd respondd.c)
set_property(TARGET respondd PROPERTY COMPILE_FLAGS "-Wall -std=c99 -fno-strict-aliasing ${JSON_C_CFLAGS_OTHER}")
set_property(TARGET respondd PROPERTY LINK_FLAGS "${JSON_C_LDFLAGS_OTHER}")
set_property(TARGET respondd APPEND PROPERTY INCLUDE_DIRECTORIES ${JSON_C_INCLUDE_DIR})
target_link_libraries(respondd ${JSON_C_LIBRARIES} dl)
target_link_libraries(
respondd
${JSON_C_LIBRARIES}
${ECDSAUTIL_LIBRARIES}
${UCI_LIBRARY}
dl)
install(TARGETS respondd RUNTIME DESTINATION bin)

View File

@ -53,10 +53,17 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <ecdsautil/ecdsa.h>
#include <ecdsautil/sha256.h>
#include <uci.h>
#define SCHEDULE_LEN 8
#define REQUEST_MAXLEN 256
#define MAX_MULTICAST_DELAY_DEFAULT 0
ecc_int256_t ed25519_secret;
ecc_int256_t ed25519_public;
struct interface_info {
struct interface_info *next;
@ -359,6 +366,180 @@ static struct json_object * eval_providers(struct provider_list *providers) {
return ret;
}
int random_bytes(unsigned char *buffer, size_t len) {
int fd;
size_t read_bytes = 0;
fd = open("/dev/random", O_RDONLY);
if (fd < 0) {
fprintf(stderr, "Can't open /dev/random: %s\n", strerror(errno));
goto out_error;
}
while (read_bytes < len) {
ssize_t ret = read(fd, buffer + read_bytes, len - read_bytes);
if (ret < 0) {
if (errno == EINTR)
continue;
fprintf(stderr, "Unable to read random bytes: %s\n", strerror(errno));
goto out_error;
}
read_bytes += ret;
}
close(fd);
return 1;
out_error:
close(fd);
return 0;
}
// str must be a char[2*(offset+len)+1]
static void sprintf_hex(char *str_buf, const uint8_t *buf, size_t len, size_t offset) {
str_buf += 2*offset;
for (size_t i = 0; i < len; i++) {
snprintf(str_buf, 3, "%02hhx", buf[i]);
str_buf += 2;
}
}
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;
}
ecc_int256_t read_or_generate_key() {
struct uci_context *ctx = uci_alloc_context();
if (!ctx) {
fprintf(stderr, "respondd: error: failed to allocate UCI context\n");
abort();
}
ctx->flags &= ~UCI_FLAG_STRICT;
struct uci_package *p;
struct uci_section *s;
if (uci_load(ctx, "respondd", &p) != UCI_OK) {
fputs("respondd: error: unable to load UCI package\n", stderr);
exit(1);
}
s = uci_lookup_section(ctx, p, "settings");
if (!s || strcmp(s->type, "respondd")) {
fputs("respondd: error: could not load UCI section respondd.settings\n", stderr);
exit(1);
}
const char *secret_str = uci_lookup_option_string(ctx, s, "secret");
ecc_int256_t secret;
if (!secret_str || !parsehex(&secret, secret_str, 32)) {
fputs("respondd: no valid key found. generating new key.\n", stderr);
// generate it
if (!random_bytes(secret.p, 32)) {
fputs("respondd: unable to read random bytes.\n", stderr);
exit(1);
}
ecc_25519_gf_sanitize_secret(&secret, &secret);
// save it to uci
char secret_str_new[64+1];
sprintf_hex(secret_str_new, secret.p, 32, 0);
struct uci_ptr ptr ={
.package = "respondd",
.section = "settings",
.option = "secret",
.value = secret_str_new,
};
uci_set(ctx, &ptr);
uci_commit(ctx, &ptr.p, false);
uci_unload(ctx, ptr.p);
fputs("respondd: key generated and saved.\n", stderr);
}
uci_free_context(ctx);
return secret;
}
static void public_from_secret(ecc_int256_t *pub, const ecc_int256_t *secret) {
ecc_25519_work_t work;
ecc_25519_scalarmult_base(&work, secret);
ecc_25519_store_packed_legacy(pub, &work);
}
// The string representation of obj is signed using the secret. After signing,
// a structure containing the public key and the signature is added into obj.
// The obj looks like this after calling sign_json(obj, ...):
//
// {
// ...,
// "auth": {
// "secure_nodeid": "25077b1914533e94a60853678b8484531a5f63463de87786f042e3d88d0bbc27",
// "sig": "eca0455a99a6b79edc719c18aa46c7d8f960e041f77f836326e6eae08064606320daff6f11cb0d0a2fb51a346725e3dc01e9a85f7c064ec857200c302937409"
// }
// }
//
// To verify the signature, the substructure "auth" has to be removed before.
// The string representation of obj has to be densely packed. No whitespace and
// tabs " " between keys, no newlines and the order of keys must not be changed.
static void sign_json(struct json_object * obj, const ecc_int256_t *secret, const ecc_int256_t *pub) {
// TODO: This currently enables replay attacks, as the json does not contain
// any time value or so... However, we do not care much, as
// this is probably not an effective attack vector.
const char *str = json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN);
// hash
ecc_int256_t hash;
ecdsa_sha256_context_t hash_ctx;
ecdsa_sha256_init(&hash_ctx);
ecdsa_sha256_update(&hash_ctx, str, strlen(str));
ecdsa_sha256_final(&hash_ctx, hash.p);
struct json_object *auth = json_object_new_object();
// generate signature
ecdsa_signature_t signature;
char signature_str[128+1];
ecdsa_sign_legacy(&signature, &hash, secret);
sprintf_hex(signature_str, signature.r.p, 32, 0);
sprintf_hex(signature_str, signature.s.p, 32, 32);
json_object_object_add(auth, "signature", json_object_new_string(signature_str));
// append pubkey
char pub_str[64+1];
sprintf_hex(pub_str, pub->p, 32, 0);
json_object_object_add(auth, "secure_nodeid", json_object_new_string(pub_str));
json_object_object_add(obj, "auth", auth);
}
/**
* Find all providers for the type and return the (eventually cached) result
*
@ -385,6 +566,8 @@ static struct json_object * single_request(char *type) {
struct json_object *ret = eval_providers(r->providers);
sign_json(ret, &ed25519_secret, &ed25519_public);
if (r->cache_time) {
if (r->cache)
json_object_put(r->cache);
@ -746,6 +929,10 @@ int main(int argc, char **argv) {
}
}
// load keys for ed25519 signatures
ed25519_secret = read_or_generate_key();
public_from_secret(&ed25519_public, &ed25519_secret);
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);

View File

@ -380,7 +380,7 @@ function WGPeerSelector:main()
if self:try_connect_to_peer(peer, timeout) then
connected_peer = peer
log(syslog.LOG_INFO, 'Connection established with '..peer.name..'.')
log(syslog.LOG_INFO, 'Connection established with '..connected_peer.name..'.')
end
elseif state == 'established' then
@ -388,8 +388,8 @@ function WGPeerSelector:main()
if not connected_peer:has_recent_handshake() then
connected_peer:uninstall_from_kernel()
log(syslog.LOG_INFO, 'Connection to '..connected_peer.name..' lost.')
connected_peer = nil
log(syslog.LOG_INFO, 'Connection to '..peer.name..' lost.')
else
-- check connections every 5 seconds
sleep(5)