Browse Source

Added Sign_admin to allow signing and checking of signatures from RPC

Caleb James DeLisle 3 years ago
parent
commit
cbc2d8c51d
3 changed files with 160 additions and 0 deletions
  1. 2 0
      admin/angel/Core.c
  2. 129 0
      crypto/Sign_admin.c
  3. 29 0
      crypto/Sign_admin.h

+ 2 - 0
admin/angel/Core.c

@@ -23,6 +23,7 @@
 #include "crypto/AddressCalc.h"
 #include "crypto/random/Random.h"
 #include "crypto/random/libuv/LibuvEntropyProvider.h"
+#include "crypto/Sign_admin.h"
 #include "subnode/SubnodePathfinder.h"
 #include "subnode/SupernodeHunter_admin.h"
 #include "subnode/ReachabilityCollector_admin.h"
@@ -391,6 +392,7 @@ void Core_init(struct Allocator* alloc,
     IpTunnel_admin_register(ipTunnel, admin, alloc);
     SessionManager_admin_register(nc->sm, admin, alloc);
     Allocator_admin_register(alloc, admin);
+    Sign_admin_register(privateKey, admin, rand, alloc);
 
     struct Context* ctx = Allocator_calloc(alloc, sizeof(struct Context), 1);
     Identity_set(ctx);

+ 129 - 0
crypto/Sign_admin.c

@@ -0,0 +1,129 @@
+/* vim: set expandtab ts=4 sw=4: */
+/*
+ * You may redistribute this program and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+#include "crypto/Sign_admin.h"
+
+#include "admin/Admin.h"
+#include "benc/String.h"
+#include "crypto/Key.h"
+#include "crypto/Sign.h"
+#include "dht/Address.h"
+#include "exception/Er.h"
+#include "memory/Allocator.h"
+#include "util/Base32.h"
+#include "util/Identity.h"
+#include "wire/Message.h"
+
+struct Context {
+    uint8_t signingKeypair[64];
+    uint8_t pubSigningKey[64];
+    struct Random* rand;
+    struct Allocator* alloc;
+    struct Admin* admin;
+    Identity
+};
+
+static void checkSig(Dict* args, void* vctx, String* txid, struct Allocator* requestAlloc)
+{
+    struct Context* ctx = Identity_check((struct Context*) vctx);
+    String* msgHash = Dict_getStringC(args, "msgHash");
+    String* signature = Dict_getStringC(args, "signature");
+    Dict* out = Dict_new(requestAlloc);
+    uint8_t publicSigningKey[32];
+    uint8_t sigBytes[64];
+    char* underscore = CString_strchr(signature->bytes, '_');
+    if (msgHash->len > 64) {
+        Dict_putStringCC(out, "error", "msgHash too long, max 64 bytes", requestAlloc);
+    } else if (underscore == NULL) {
+        Dict_putStringCC(out, "error",
+            "malformed signature, missing separator", requestAlloc);
+    } else if (Base32_decode(
+        publicSigningKey, 32, signature->bytes, (int)(underscore - signature->bytes)) != 32)
+    {
+        Dict_putStringCC(out, "error",
+            "malformed signature, failed to decode pubkey", requestAlloc);
+    } else if (Base32_decode(
+        sigBytes, 64, &underscore[1], CString_strlen(&underscore[1])) != 64)
+    {
+        Dict_putStringCC(out, "error",
+            "malformed signature, failed to decode signature", requestAlloc);
+    } else {
+        struct Message* msg = Message_new(0, msgHash->len + 64, requestAlloc);
+        Er_assert(Message_epush(msg, msgHash->bytes, msgHash->len));
+        Er_assert(Message_epush(msg, sigBytes, 64));
+        uint8_t curve25519key[32];
+        if (Sign_verifyMsg(publicSigningKey, msg)) {
+            Dict_putStringCC(out, "error", "invalid signature", requestAlloc);
+        } else if (Sign_publicSigningKeyToCurve25519(curve25519key, publicSigningKey)) {
+            Dict_putStringCC(out, "error", "not a valid curve25519 key", requestAlloc);
+        } else {
+            struct Address addr;
+            Address_forKey(&addr, curve25519key);
+            uint8_t ipv6[40];
+            Address_printIp(ipv6, &addr);
+            String* k = Key_stringify(curve25519key, requestAlloc);
+            Dict_putStringC(out, "pubkey", k, requestAlloc);
+            Dict_putStringCC(out, "ipv6", ipv6, requestAlloc);
+            Dict_putStringCC(out, "error", "none", requestAlloc);
+        }
+    }
+    Admin_sendMessage(out, txid, ctx->admin);
+}
+
+static void sign(Dict* args, void* vctx, String* txid, struct Allocator* requestAlloc)
+{
+    struct Context* ctx = Identity_check((struct Context*) vctx);
+    String* msgHash = Dict_getStringC(args, "msgHash");
+    Dict* out = Dict_new(requestAlloc);
+    if (msgHash->len > 64) {
+        Dict_putStringCC(out, "error", "msgHash too long, max 64 bytes", requestAlloc);
+    } else {
+        struct Message* msg = Message_new(0, msgHash->len + 64, requestAlloc);
+        Er_assert(Message_epush(msg, msgHash->bytes, msgHash->len));
+        Sign_signMsg(ctx->signingKeypair, msg, ctx->rand);
+        uint8_t signB64[128];
+        Assert_true(Base32_encode(signB64, 128, msg->bytes, 64) > 0);
+        String* sig = String_printf(requestAlloc, "%s_%s", ctx->pubSigningKey, signB64);
+        Dict_putStringC(out, "signature", sig, requestAlloc);
+        Dict_putStringCC(out, "error", "none", requestAlloc);
+    }
+    Admin_sendMessage(out, txid, ctx->admin);
+}
+
+void Sign_admin_register(uint8_t* privateKey,
+                         struct Admin* admin,
+                         struct Random* rand,
+                         struct Allocator* alloc)
+{
+    struct Context* ctx = Allocator_calloc(alloc, sizeof(struct Context), 1);
+    Sign_signingKeyPairFromCurve25519(ctx->signingKeypair, privateKey);
+    uint8_t sPubKey[32];
+    Sign_publicKeyFromKeyPair(sPubKey, ctx->signingKeypair);
+    Assert_true(Base32_encode(ctx->pubSigningKey, 64, sPubKey, 32) > 0);
+
+    ctx->alloc = alloc;
+    ctx->rand = rand;
+    ctx->admin = admin;
+    Identity_set(ctx);
+
+    Admin_registerFunction("Sign_checkSig", checkSig, ctx, false,
+        ((struct Admin_FunctionArg[]) {
+            { .name = "msgHash", .required = true, .type = "String" },
+            { .name = "signature", .required = true, .type = "String" },
+        }), admin);
+    Admin_registerFunction("Sign_sign", sign, ctx, true,
+        ((struct Admin_FunctionArg[]) {
+            { .name = "msgHash", .required = true, .type = "String" },
+        }), admin);
+}

+ 29 - 0
crypto/Sign_admin.h

@@ -0,0 +1,29 @@
+/* vim: set expandtab ts=4 sw=4: */
+/*
+ * You may redistribute this program and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+#ifndef Sign_admin_H
+#define Sign_admin_H
+
+#include "admin/Admin.h"
+#include "memory/Allocator.h"
+#include "crypto/random/Random.h"
+#include "util/Linker.h"
+Linker_require("crypto/Sign_admin.c");
+
+void Sign_admin_register(uint8_t* privateKey,
+                         struct Admin* admin,
+                         struct Random* rand,
+                         struct Allocator* alloc);
+
+#endif