]> git.meshlink.io Git - meshlink/commitdiff
Implement meshlink_sign() and _verify().
authorGuus Sliepen <guus@meshlink.io>
Fri, 25 Jul 2014 16:33:40 +0000 (18:33 +0200)
committerGuus Sliepen <guus@meshlink.io>
Fri, 25 Jul 2014 16:33:40 +0000 (18:33 +0200)
TODO
src/meshlink++.h
src/meshlink.c
src/meshlink.h
src/net.h
src/net_setup.c
test/Makefile.am
test/sign-verify.c [new file with mode: 0644]
test/sign-verify.test [new file with mode: 0755]

diff --git a/TODO b/TODO
index a7d96da6b848bcec34fa26d0665f2bd2674c14a0..68746e1b6ac54a36317f8f81ff71ef972690d3d4 100644 (file)
--- 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.
index 02cd01a2d1ae26ad486340b028135689629c7cf9..a4829a4505204bb0c2f8b5a4494e1804cee36c45 100644 (file)
@@ -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.
index e5982721d533aadd2cafb8e775f6dcb7b1555916..61fe1cbe5fefaa797dde8db81626c0967725a189 100644 (file)
@@ -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) {
index 036637b08cadb6c3ec693cccbedd2c25bd3eda50..afa6032cf9550cd7aa08c6a28656694faba96978 100644 (file)
@@ -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.
index 34f8acc49fe383ac23267cf2fae655a261d16e60..f76e2df43b99a9ade8ebd1be189b88ccdcfa3ec9 100644 (file)
--- 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);
index e8ed948772e4bf9ec546f8a3820b9e54b3133902..7f3358168d5891abb1c515cd47d0279557f1adef 100644 (file)
@@ -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];
 
index 3862607e835e188107b06e6831f61d6a30d905ca..ece9350b91b65b9dac592f30023b734fd1eddec6 100644 (file)
@@ -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 (file)
index 0000000..a7f9a5a
--- /dev/null
@@ -0,0 +1,105 @@
+#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;
+}
diff --git a/test/sign-verify.test b/test/sign-verify.test
new file mode 100755 (executable)
index 0000000..2ae5021
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+rm -Rf sign_verify_conf*
+./sign-verify