commit cb03022e9287060b9495fe9c45844e271f4c9df8
parent deca2e241bc1d924cc914e6c8e995f42f7e31bd7
Author: William Casarin <jb55@jb55.com>
Date: Mon, 15 Feb 2021 18:40:06 -0800
sigcheck rsa verification working
Diffstat:
4 files changed, 168 insertions(+), 82 deletions(-)
diff --git a/src/ap_json.c b/src/ap_json.c
@@ -197,6 +197,8 @@ static int handle_wssigbuf(struct ap_json *a)
return 0;
}
+ fprintf(stderr, "headers: %s\n", a->sig->headers);
+
if (!split_headers((unsigned char*)a->sig->headers,
strlen(a->sig->headers), strs,
sizeof(strs)/sizeof(strs[0]), &n_headers)) {
@@ -230,6 +232,10 @@ static int handle_wssigbuf(struct ap_json *a)
str->size, str->text);
return 0;
}
+
+ if (i != n_headers-1) {
+ push_str(c, "\\n");
+ }
}
if (!push_str(c, "\",")) {
diff --git a/src/chibipub.c b/src/chibipub.c
@@ -178,12 +178,6 @@ static int handle_inbox_request(struct http_req *req, struct cursor *arena)
apjson.sig = &sig;
apjson.req = req;
- // TODO: defer this check
- if (!verify_signature_header(&sig)) {
- note_error(&req->errs, "verify");
- return 0;
- }
-
start = arena->p;
init_json_pusher_with(&push, arena);
diff --git a/src/io.c b/src/io.c
@@ -29,8 +29,10 @@ int write_file(const char *filename, unsigned char *out, size_t len)
size_t written;
file = fopen(filename, "wb");
- if (file == NULL)
+ if (file == NULL) {
+ fprintf(stderr, "fopen wb '%s' failed\n", filename);
return 0;
+ }
written = fwrite(out, 1, len, file);
diff --git a/src/sigcheck.c b/src/sigcheck.c
@@ -8,19 +8,26 @@
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
#include "json.h"
#include "ubjson.h"
#include "hash.h"
+#include "base64.h"
#include "io.h"
#include "sigcheck.h"
#include "util.h"
#include "inbox.h"
#include "errors.h"
+#include "sha256/sha256.h"
+
#include <ctype.h>
#include <curl/curl.h>
+#define debug_info(...)
+
struct keyid_pubkey {
unsigned char *data;
int len;
@@ -41,21 +48,132 @@ struct key_writer {
int flags;
};
-static int verify_signature(struct cursor cur, struct cursor *arena)
+static int hex_bytes(unsigned char *bytes, int n_bytes, char *buf,
+ int buf_size)
+{
+ static const char *hex = "0123456789abcdef";
+ int b;
+
+ if (n_bytes * 2 < buf_size)
+ return 0;
+
+ for (int i = 0; i < buf_size; i++) {
+ b = bytes[i/2];
+ b = i % 2 ? b & 0x0F : (b & 0xF0) >> 4;
+ buf[i] = hex[b];
+ }
+
+ return 1;
+}
+
+
+static int get_cached_pubkey(const char *keyid, int keyid_len,
+ struct cursor *arena, unsigned char **pubkey, int *pubkey_size)
+{
+ unsigned char hash[32];
+ char hash_str[64];
+ char path[2048] = {0};
+ int ok;
+
+ // no objects dir, definitely don't have any cached pubkeys
+ if (!dir_exists(".chibipub/objects")) {
+ return 0;
+ }
+
+ blake3_hash((unsigned char *)keyid, keyid_len, hash);
+ if (!hex_bytes(hash, 32, hash_str, 64)) {
+ assert(0);
+ }
+
+ sprintf(path, ".chibipub/objects/%c%c/%.*s",
+ hash_str[0], hash_str[1], 64, hash_str);
+
+ debug_info(stderr, "key cache exists? '%s' ", path);
+ if (access(path, F_OK)) {
+ debug_info(stderr, "no.\n");
+ return 0;
+ }
+ debug_info(stderr, "yes!\n");
+
+ *pubkey = arena->p;
+ ok = read_file(path, arena->p, arena->end - arena->p, pubkey_size);
+
+ arena->p += *pubkey_size;
+ return ok;
+}
+
+static int verify_signature_rsa(unsigned char *pubkey, int pubkey_len,
+ unsigned char *sig, int sig_len,
+ unsigned char *sigbuf, int sigbuf_len)
+{
+ unsigned char hash[32];
+
+ RSA *rsa = NULL;
+ BIO *keybio;
+
+ keybio = BIO_new_mem_buf((void*)pubkey, pubkey_len);
+ if (!keybio) {
+ return 0;
+ }
+
+ rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, 0, 0);
+
+ if (!rsa) {
+ fprintf(stderr, "verify_signature_rsa: PEM read failed\n");
+ return 0;
+ }
+
+ sha256_hash(hash, sigbuf, sigbuf_len);
+
+ return RSA_verify(NID_sha256, hash, 32, sig, sig_len, rsa);
+}
+
+static int verify_signature(struct cursor cur, struct cursor arena)
{
struct ubjson ubjson;
- struct json val;
+ struct json sigbuf, keyid, sig;
+ unsigned char *pubkey, *sig_data;
+ int pubkey_size;
+ size_t sig_len;
init_ubjson(&ubjson, cur.start, cur.p - cur.start);
ubjson.data_end = cur.p;
- static const char *path[] = {"@wssigbuf"};
- if (!ubjson_lookup(&ubjson, path, ARRAY_SIZE(path), &val)) {
- note_error(&ubjson.errs, "Signature header not found");
+ static const char *sig_path[] = {"@wssig"};
+ if (!ubjson_lookup(&ubjson, sig_path, ARRAY_SIZE(sig_path), &sig)) {
+ note_error(&ubjson.errs, "@wssig field not found");
return 0;
}
- return 1;
+ static const char *sb_path[] = {"@wssigbuf"};
+ if (!ubjson_lookup(&ubjson, sb_path, ARRAY_SIZE(sb_path), &sigbuf)) {
+ note_error(&ubjson.errs, "@wssigbuf field not found");
+ return 0;
+ }
+
+ static const char *keyid_path[] = {"@wskeyid"};
+ if (!ubjson_lookup(&ubjson, keyid_path, ARRAY_SIZE(keyid_path), &keyid)) {
+ note_error(&ubjson.errs, "keyid not fond");
+ return 0;
+ }
+
+ if (!get_cached_pubkey(keyid.string, keyid.len, &arena, &pubkey, &pubkey_size)) {
+ note_error(&ubjson.errs, "no cached pubkey for '%s'", keyid.string);
+ return 0;
+ }
+
+ sig_data = arena.p;
+ if (!base64_decode((const unsigned char*)sig.string,
+ sig.len, arena.p, arena.end - arena.p,
+ &sig_len)) {
+ note_error(&ubjson.errs, "base64 decode signature");
+ return 0;
+ }
+
+ return verify_signature_rsa(
+ pubkey, pubkey_size,
+ sig_data, sig_len,
+ (unsigned char*)sigbuf.string, sigbuf.len);
}
static inline int push_keyid(struct cursor *c, const char *keyid, int keyid_len)
@@ -108,6 +226,7 @@ static int has_keyid(struct cursor *keyids, const char *keyid, int keyid_len)
return 0;
}
+/*
static int print_keyids(struct cursor keyids)
{
int size;
@@ -126,6 +245,7 @@ static int print_keyids(struct cursor keyids)
return 1;
}
+*/
static int gather_keyids(unsigned char *json, int json_len,
struct cursor *arena, struct cursor *keyids_cur)
@@ -168,58 +288,9 @@ static int gather_keyids(unsigned char *json, int json_len,
keyids_cur->p = keyids_cur->start;
arena->p = keyids_cur->end;
- print_keyids(*keyids_cur);
-
- return 1;
-}
-
-static int hex_bytes(unsigned char *bytes, int n_bytes, char *buf,
- int buf_size)
-{
- static const char *hex = "0123456789abcdef";
- int b;
-
- if (n_bytes * 2 < buf_size)
- return 0;
-
- for (int i = 0; i < buf_size; i++) {
- b = bytes[i/2];
- b = i % 2 ? b & 0x0F : (b & 0xF0) >> 4;
- buf[i] = hex[b];
- }
-
return 1;
}
-static int get_cached_pubkey(const char *keyid, unsigned char *buf, int buflen, int *pubkey_size)
-{
- unsigned char hash[32];
- char hash_str[64];
- char path[2048] = {0};
-
- // no objects dir, definitely don't have any cached pubkeys
- if (!dir_exists(".chibipub/objects")) {
- return 0;
- }
-
- blake3_hash((unsigned char *)keyid, strlen(keyid), hash);
- if (!hex_bytes(hash, 32, hash_str, 64)) {
- assert(0);
- }
-
- sprintf(path, ".chibipub/objects/%c%c/%.*s",
- hash_str[0], hash_str[1], 64, hash_str);
-
- fprintf(stderr, "key cache exists? '%s' ", path);
- if (access(path, F_OK)) {
- fprintf(stderr, "no.\n");
- return 0;
- }
- fprintf(stderr, "yes!\n");
-
- return read_file(path, buf, buflen, pubkey_size);
-}
-
static size_t write_cb(char *data, size_t n, size_t l, void *userp)
{
double dcl;
@@ -294,25 +365,36 @@ static void prepare_transfers(CURLM **cm)
curl_multi_setopt(*cm, CURLMOPT_MAXCONNECTS, (long)10);
}
-static int write_pubkey_cache(struct key_writer *writer, struct cursor arena)
+static int get_keyid_hash(const char *keyid, struct cursor *arena,
+ char **hash_str)
{
unsigned char *hash;
- char *hash_str;
- char *path;
- if (!(hash = cursor_alloc(&arena, 32))) {
+ if (!(*hash_str = cursor_alloc(arena, 65))) {
return 0;
}
- blake3_hash((unsigned char*)writer->keyid, strlen(writer->keyid), hash);
+ if (!(hash = cursor_alloc(arena, 32))) {
+ return 0;
+ }
- if (!(hash_str = cursor_alloc(&arena, 64))) {
- note_error(&writer->errs, "alloc hash_str");
+ blake3_hash((unsigned char*)keyid, strlen(keyid), hash);
+ if (!hex_bytes(hash, 32, *hash_str, 64)) {
return 0;
}
- if (!hex_bytes(hash, 32, hash_str, 64)) {
- note_error(&writer->errs, "hex_bytes");
+ arena->p -= 32;
+
+ return 1;
+}
+
+static int write_pubkey_cache(struct key_writer *writer, struct cursor arena)
+{
+ char *hash_str;
+ char *path;
+
+ if (!get_keyid_hash(writer->keyid, &arena, &hash_str)) {
+ note_error(&writer->errs, "get_keyid_hash");
return 0;
}
@@ -338,7 +420,8 @@ static int write_pubkey_cache(struct key_writer *writer, struct cursor arena)
return 0;
}
- if (!write_file(path, writer->pubkey->data, writer->pubkey->len)) {
+ if (!write_file(path, (unsigned char*)writer->pubkey->data,
+ writer->pubkey->len)) {
note_error(&writer->errs, "write_file '%s' pubkey failed", path);
return 0;
}
@@ -503,14 +586,12 @@ static int fetch_signatures(unsigned char *json, int json_len,
return 0;
}
- if (get_cached_pubkey(keyid_str, arena->p,
- arena->end - arena->p,
- &pubkey->len)) {
- pubkey->data = arena->p;
- arena->p += pubkey->len;
+ if (get_cached_pubkey(keyid_str, strlen(keyid_str), arena,
+ &pubkey->data, &pubkey->len)) {
+ /*
printf("got cached pubkey of size %d... do something\n",
pubkey->len);
-
+ */
continue;
}
@@ -542,13 +623,12 @@ int sigcheck(struct sigcheck *check)
size_t flen;
struct json_parser jsonp;
struct json_handlers handlers;
- struct cursor in_cur, out_cur;
+ struct cursor out_cur;
scratch = malloc(SCRATCH_SIZE);
map_file(check->activity_file, &p, &flen);
init_json_handlers(&handlers);
- make_cursor(p, p + flen, &in_cur);
make_cursor(scratch, scratch + SCRATCH_SIZE, &out_cur);
make_ubjson_handlers(&handlers, &out_cur);
init_json_parser(&jsonp, p, flen, &handlers);
@@ -558,12 +638,16 @@ int sigcheck(struct sigcheck *check)
return 0;
}
+ make_cursor(scratch, scratch + SCRATCH_SIZE, &out_cur);
+ make_ubjson_handlers(&handlers, &out_cur);
+ init_json_parser(&jsonp, p, flen, &handlers);
+
start = out_cur.p;
while (parse_json(&jsonp)) {
count++;
- printf("[%d] parse success\n", count);
+ debug_info("[%d] parse success\n", count);
- if (!verify_signature(out_cur, &out_cur)) {
+ if (!verify_signature(out_cur, out_cur)) {
printf("bad signature #%d\n", count);
}