From 82a9712857c5b640288174493905499093853997 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Fri, 25 Jul 2014 18:33:40 +0200 Subject: [PATCH] Implement meshlink_sign() and _verify(). --- TODO | 4 -- src/meshlink++.h | 14 +++--- src/meshlink.c | 19 ++++++-- src/meshlink.h | 12 +++-- src/net.h | 1 + src/net_setup.c | 2 +- test/Makefile.am | 8 +++- test/sign-verify.c | 105 ++++++++++++++++++++++++++++++++++++++++++ test/sign-verify.test | 4 ++ 9 files changed, 148 insertions(+), 21 deletions(-) create mode 100644 test/sign-verify.c create mode 100755 test/sign-verify.test diff --git a/TODO b/TODO index a7d96da6..68746e1b 100644 --- a/TODO +++ b/TODO @@ -1,10 +1,6 @@ TODO list for MeshLink ---------------------- -* Write meshlink_sign() and meshlink_verify(). These should just call - ecdsa_sign() and _verify(), with mesh->self->connection->ecdsa as the key for - _sign(), and node->ecdsa for _verify()? - * meshlink_join(): - add checks that we only join another mesh if we did not connect to any other node before. - only allow meshlink_join() when the library thread is not running. diff --git a/src/meshlink++.h b/src/meshlink++.h index 02cd01a2..a4829a45 100644 --- a/src/meshlink++.h +++ b/src/meshlink++.h @@ -168,12 +168,13 @@ namespace meshlink { * * @param data A pointer to a buffer containing the data to be signed. * @param len The length of the data to be signed. + * @param signature A pointer to a buffer where the signature will be stored. + * @param siglen The size of the signature buffer. Will be changed after the call to match the size of the signature itself. * - * @return This function returns a pointer to a string containing the signature, or NULL in case of an error. - * The application should call free() after it has finished using the signature. + * @return This function returns true if the signature is valid, false otherwise. */ - char *sign(const char *data, size_t len) { - return meshlink_sign(this, data, len); + bool sign(const void *data, size_t len, void *signature, size_t *siglen) { + return meshlink_sign(this, data, len, signature, siglen); } /// Verify the signature generated by another node of a piece of data. @@ -183,11 +184,12 @@ namespace meshlink { * @param data A pointer to a buffer containing the data to be verified. * @param len The length of the data to be verified. * @param signature A pointer to a string containing the signature. + * @param siglen The size of the signature. * * @return This function returns true if the signature is valid, false otherwise. */ - bool verify(node *source, const char *data, size_t len, const char *signature) { - return meshlink_verify(this, source, data, len, signature); + bool verify(node *source, const void *data, size_t len, const void *signature, size_t siglen) { + return meshlink_verify(this, source, data, len, signature, siglen); } /// Add an Address for the local node. diff --git a/src/meshlink.c b/src/meshlink.c index e5982721..61fe1cbe 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -927,12 +927,23 @@ size_t meshlink_get_all_nodes(meshlink_handle_t *mesh, meshlink_node_t **nodes, return i; } -char *meshlink_sign(meshlink_handle_t *mesh, const char *data, size_t len) { - return NULL; +bool meshlink_sign(meshlink_handle_t *mesh, const void *data, size_t len, void *signature, size_t *siglen) { + if(*siglen < MESHLINK_SIGLEN) + return false; + if(!ecdsa_sign(mesh->self->connection->ecdsa, data, len, signature)) + return false; + *siglen = MESHLINK_SIGLEN; + return true; } -bool meshlink_verify(meshlink_handle_t *mesh, meshlink_node_t *source, const char *data, size_t len, const char *signature) { - return false; +bool meshlink_verify(meshlink_handle_t *mesh, meshlink_node_t *source, const void *data, size_t len, const void *signature, size_t siglen) { + if(siglen != MESHLINK_SIGLEN) + return false; + struct node_t *n = (struct node_t *)source; + node_read_ecdsa_public_key(mesh, n); + if(!n->ecdsa) + return false; + return ecdsa_verify(((struct node_t *)source)->ecdsa, data, len, signature); } static bool refresh_invitation_key(meshlink_handle_t *mesh) { diff --git a/src/meshlink.h b/src/meshlink.h index 036637b0..afa6032c 100644 --- a/src/meshlink.h +++ b/src/meshlink.h @@ -27,6 +27,8 @@ extern "C" { #endif +#define MESHLINK_SIGLEN 64 + /// A handle for an instance of MeshLink. typedef struct meshlink_handle meshlink_handle_t; @@ -220,11 +222,12 @@ extern size_t meshlink_get_all_nodes(meshlink_handle_t *mesh, meshlink_node_t ** * @param mesh A handle which represents an instance of MeshLink. * @param data A pointer to a buffer containing the data to be signed. * @param len The length of the data to be signed. + * @param signature A pointer to a buffer where the signature will be stored. + * @param siglen The size of the signature buffer. Will be changed after the call to match the size of the signature itself. * - * @return This function returns a pointer to a string containing the signature, or NULL in case of an error. - * The application should call free() after it has finished using the signature. + * @return This function returns true if the signature was correctly generated, false otherwise. */ -extern char *meshlink_sign(meshlink_handle_t *mesh, const char *data, size_t len); +extern bool meshlink_sign(meshlink_handle_t *mesh, const void *data, size_t len, void *signature, size_t *siglen); /// Verify the signature generated by another node of a piece of data. /** This function verifies the signature that another node generated for a piece of data. @@ -234,10 +237,11 @@ extern char *meshlink_sign(meshlink_handle_t *mesh, const char *data, size_t len * @param data A pointer to a buffer containing the data to be verified. * @param len The length of the data to be verified. * @param signature A pointer to a string containing the signature. + * @param siglen The size of the signature. * * @return This function returns true if the signature is valid, false otherwise. */ -extern bool meshlink_verify(meshlink_handle_t *mesh, meshlink_node_t *source, const char *data, size_t len, const char *signature); +extern bool meshlink_verify(meshlink_handle_t *mesh, meshlink_node_t *source, const void *data, size_t len, const void *signature, size_t siglen); /// Add an Address for the local node. /** This function adds an Address for the local node, which will be used for invitation URLs. diff --git a/src/net.h b/src/net.h index 34f8acc4..f76e2df4 100644 --- a/src/net.h +++ b/src/net.h @@ -104,6 +104,7 @@ extern int main_loop(struct meshlink_handle *mesh); extern void terminate_connection(struct meshlink_handle *mesh, struct connection_t *, bool); extern bool node_read_ecdsa_public_key(struct meshlink_handle *mesh, struct node_t *); extern bool read_ecdsa_public_key(struct meshlink_handle *mesh, struct connection_t *); +extern bool read_ecdsa_private_key(struct meshlink_handle *mesh); extern void send_mtu_probe(struct meshlink_handle *mesh, struct node_t *); extern void handle_meta_connection_data(struct meshlink_handle *mesh, struct connection_t *); extern void retry(struct meshlink_handle *mesh); diff --git a/src/net_setup.c b/src/net_setup.c index e8ed9487..7f335816 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -80,7 +80,7 @@ bool read_ecdsa_public_key(meshlink_handle_t *mesh, connection_t *c) { return false; } -static bool read_ecdsa_private_key(meshlink_handle_t *mesh) { +bool read_ecdsa_private_key(meshlink_handle_t *mesh) { FILE *fp; char filename[PATH_MAX]; diff --git a/test/Makefile.am b/test/Makefile.am index 3862607e..ece9350b 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,13 +1,14 @@ TESTS = \ basic.test \ import-export.test \ - invite-join.test + invite-join.test \ + sign-verify.test dist_check_SCRIPTS = $(TESTS) AM_CPPFLAGS = -I../src -check_PROGRAMS = basic import-export invite-join +check_PROGRAMS = basic import-export invite-join sign-verify basic_SOURCES = basic.c basic_LDADD = ../src/libmeshlink.la @@ -17,3 +18,6 @@ import_export_LDADD = ../src/libmeshlink.la invite_join_SOURCES = invite-join.c invite_join_LDADD = ../src/libmeshlink.la + +sign_verify_SOURCES = sign-verify.c +sign_verify_LDADD = ../src/libmeshlink.la diff --git a/test/sign-verify.c b/test/sign-verify.c new file mode 100644 index 00000000..a7f9a5af --- /dev/null +++ b/test/sign-verify.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include + +#include "meshlink.h" + +int main(int argc, char *argv[]) { + // Open two new meshlink instance. + + meshlink_handle_t *mesh1 = meshlink_open("sign_verify_conf.1", "foo"); + if(!mesh1) { + fprintf(stderr, "Could not initialize configuration for foo\n"); + return 1; + } + + meshlink_handle_t *mesh2 = meshlink_open("sign_verify_conf.2", "bar"); + if(!mesh2) { + fprintf(stderr, "Could not initialize configuration for bar\n"); + return 1; + } + + // Import and export both side's data + + meshlink_add_address(mesh1, "localhost"); + meshlink_add_address(mesh2, "localhost"); + + char *data = meshlink_export(mesh1); + + if(!meshlink_import(mesh2, data)) { + fprintf(stderr, "Bar could not import data from foo\n"); + return 1; + } + + free(data); + + data = meshlink_export(mesh2); + + if(!meshlink_import(mesh1, data)) { + fprintf(stderr, "Foo could not import data from bar\n"); + return 1; + } + + free(data); + + // Verify that a signature made on one node can be verified by its peer. + + static const char testdata1[] = "Test data 1."; + static const char testdata2[] = "Test data 2."; + + char sig[MESHLINK_SIGLEN * 2]; + size_t siglen = sizeof sig * 2; + + if(!meshlink_sign(mesh1, testdata1, sizeof testdata1, sig, &siglen)) { + fprintf(stderr, "Signing failed\n"); + return 1; + } + if(siglen != MESHLINK_SIGLEN) { + fprintf(stderr, "Signature has unexpected length %zu != %zu\n", siglen, MESHLINK_SIGLEN); + return 1; + } + + meshlink_node_t *foo = meshlink_get_node(mesh2, "foo"); + if(!foo) { + fprintf(stderr, "Bar did not know about node foo\n"); + return 1; + } + + meshlink_node_t *bar = meshlink_get_node(mesh2, "bar"); + if(!bar) { + fprintf(stderr, "Bar did not know about node bar\n"); + return 1; + } + + if(!meshlink_verify(mesh2, foo, testdata1, sizeof testdata1, sig, siglen)) { + fprintf(stderr, "False negative verification\n"); + return 1; + } + + // Check that bad signatures are revoked + + if(meshlink_verify(mesh2, foo, testdata1, sizeof testdata1, sig, siglen / 2)) { + fprintf(stderr, "False positive verification with half sized signature\n"); + return 1; + } + if(meshlink_verify(mesh2, foo, testdata1, sizeof testdata1, sig, siglen * 2)) { + fprintf(stderr, "False positive verification with double sized signature\n"); + return 1; + } + if(meshlink_verify(mesh2, foo, testdata2, sizeof testdata2, sig, siglen)) { + fprintf(stderr, "False positive verification with wrong data\n"); + return 1; + } + if(meshlink_verify(mesh2, bar, testdata1, sizeof testdata1, sig, siglen)) { + fprintf(stderr, "False positive verification with wrong signer\n"); + return 1; + } + + // Clean up. + + meshlink_close(mesh2); + meshlink_close(mesh1); + + return 0; +} diff --git a/test/sign-verify.test b/test/sign-verify.test new file mode 100755 index 00000000..2ae50210 --- /dev/null +++ b/test/sign-verify.test @@ -0,0 +1,4 @@ +#!/bin/sh + +rm -Rf sign_verify_conf* +./sign-verify -- 2.39.5