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.
*
* @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.
* @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.
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) {
extern "C" {
#endif
+#define MESHLINK_SIGLEN 64
+
/// A handle for an instance of MeshLink.
typedef struct meshlink_handle meshlink_handle_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.
* @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.
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);
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];
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
invite_join_SOURCES = invite-join.c
invite_join_LDADD = ../src/libmeshlink.la
+
+sign_verify_SOURCES = sign-verify.c
+sign_verify_LDADD = ../src/libmeshlink.la
--- /dev/null
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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;
+}
--- /dev/null
+#!/bin/sh
+
+rm -Rf sign_verify_conf*
+./sign-verify