chibipub

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit ee8dbd256badedc7a4392accbaa7c48d20d189a7
parent 375b6ea0483bdf3c214f2b668ef8b1f018de418f
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 14 Jan 2021 14:34:46 -0800

save headers, signature in json message

Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
MMakefile | 1+
Asrc/ap_json.c | 281+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ap_json.h | 23+++++++++++++++++++++++
Msrc/cursor.h | 6+++++-
Msrc/inbox.c | 34+++++++++++++++++++++++++---------
Msrc/inbox.h | 2++
Msrc/json.c | 74+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Msrc/json.h | 16+++++++++++++++-
Msrc/test_json.c | 2+-
Msrc/ubjson.c | 4++--
Msrc/wolfsocks.c | 15+++++++++++++--
11 files changed, 427 insertions(+), 31 deletions(-)

diff --git a/Makefile b/Makefile @@ -7,6 +7,7 @@ OBJS = src/http.o \ src/inbox.o \ src/json.o \ src/ubjson.o \ + src/ap_json.o \ deps/blake3/blake3.a BLAKE3_OBJS = deps/blake3/blake3.o \ diff --git a/src/ap_json.c b/src/ap_json.c @@ -0,0 +1,281 @@ +#include "ap_json.h" +#include "inbox.h" + +#include <time.h> + + +static int handle_ap_string(struct json_handlers *h, struct json_strtok *str) +{ + struct ap_json *apjson = (struct ap_json*)h->data; + if (str->is_key && str->size == 8 + && !memcmp(str->text, "@context", str->size)) { + apjson->flags |= AP_IS_CONTEXT; + } else if (apjson->flags & AP_IS_CONTEXT) { + apjson->flags &= ~AP_IS_CONTEXT; + } + + return handle_string(&apjson->compact_handler, str); +} + +static int handle_wssig(struct ap_json *a) +{ + struct json_strtok sig; + init_json_strtok(&sig); + unsigned int *nop; + + sig.text = (unsigned char*)"@wssig"; + sig.size = 6; + sig.is_key = 1; + if (!handle_string(&a->compact_handler, &sig)) { + note_error(&a->errs, "push @wssig key oob"); + return 0; + } + + if (!handle_token(&a->compact_handler, ':', &nop)) { + note_error(&a->errs, "push @wssig : tok oob"); + return 0; + } + + sig.text = (unsigned char*)a->sig->b64_sig; + sig.size = a->sig->b64_len; + sig.is_key = 0; + if (!handle_string(&a->compact_handler, &sig)) { + note_error(&a->errs, "push @wssig val oob"); + return 0; + } + + if (!handle_token(&a->compact_handler, ',', &nop)) { + note_error(&a->errs, "push @ws_sig : tok oob"); + return 0; + } + + return 1; +} + +static int handle_wsstamp(struct ap_json *a) +{ + unsigned int *nop; + struct json_strtok str; + init_json_strtok(&str); + + str.text = (unsigned char *)"@wsstamp"; + str.size = 8; + str.is_key = 1; + if (!handle_string(&a->compact_handler, &str)) { + note_error(&a->errs, "push @wsstamp : tok oob"); + return 0; + } + + if (!handle_token(&a->compact_handler, ':', &nop)) { + note_error(&a->errs, "push @wsstamp : tok oob"); + return 0; + } + + if (!handle_number(&a->compact_handler, time(NULL))) { + note_error(&a->errs, "push @wsstamp oob number"); + return 0; + } + + if (!handle_token(&a->compact_handler, ',', &nop)) { + note_error(&a->errs, "push @ws_sig : tok oob"); + return 0; + } + + return 1; +} + +static int handle_wskeyid(struct ap_json *a) +{ + unsigned int *nop; + struct json_strtok str; + init_json_strtok(&str); + + str.text = (unsigned char *)"@wskeyid"; + str.size = 8; + str.is_key = 1; + if (!handle_string(&a->compact_handler, &str)) { + note_error(&a->errs, "push @wskeyid : tok oob"); + return 0; + } + + if (!handle_token(&a->compact_handler, ':', &nop)) { + note_error(&a->errs, "push @wskeyid : tok oob"); + return 0; + } + + str.text = (unsigned char*)a->sig->key_id; + str.size = strlen(a->sig->key_id); + str.is_key = 0; + if (!handle_string(&a->compact_handler, &str)) { + note_error(&a->errs, "push @wskeyid oob number"); + return 0; + } + + if (!handle_token(&a->compact_handler, ',', &nop)) { + note_error(&a->errs, "push @wskeyid , tok oob"); + return 0; + } + + return 1; +} + +static int handle_header(struct ap_json *a, struct http_header *header) +{ + struct json_strtok str; + unsigned int *nop; + init_json_strtok(&str); + + str.text = (unsigned char*)header->name; + str.size = strlen(header->name); + str.is_key = 1; + if (!handle_string(&a->compact_handler, &str)) { + note_error(&a->errs, "push '%s' header key oob", header->name); + return 0; + } + + if (!handle_token(&a->compact_handler, ':', &nop)) { + note_error(&a->errs, "push header : tok oob"); + return 0; + } + + str.text = (unsigned char*)header->value; + str.size = strlen(header->value); + str.is_key = 1; + str.needs_escape = 1; + if (!handle_string(&a->compact_handler, &str)) { + note_error(&a->errs, "push '%s' header value '%s' oob", + header->name, header->value); + return 0; + } + + return 1; +} + +static int handle_wsheaders(struct ap_json *a) +{ + unsigned int *nop; + struct http_header *header; + struct json_strtok str; + init_json_strtok(&str); + + str.text = (unsigned char *)"@wsheaders"; + str.size = 10; + str.is_key = 1; + if (!handle_string(&a->compact_handler, &str)) { + note_error(&a->errs, "push @wsheaders oob"); + return 0; + } + + if (!handle_token(&a->compact_handler, ':', &nop)) { + note_error(&a->errs, "push @wsheaders : tok oob"); + return 0; + } + + if (!handle_token(&a->compact_handler, '{', &nop)) { + note_error(&a->errs, "push @wsheaders { tok oob"); + return 0; + } + + for (header = a->headers; header; header = header->next) { + if (!handle_header(a, header)) { + note_error(&a->errs, "header"); + return 0; + } + + if (header->next) { + if (!handle_token(&a->compact_handler, ',', &nop)) { + note_error(&a->errs, "push header , tok oob"); + return 0; + } + } + } + + if (!handle_token(&a->compact_handler, '}', &nop)) { + note_error(&a->errs, "push @wsheaders } tok oob"); + return 0; + } + + if (!handle_token(&a->compact_handler, ',', &nop)) { + note_error(&a->errs, "push @wsheaders , tok oob"); + return 0; + } + + return 1; +} + +static int handle_ap_token(struct json_handlers *h, char token, + unsigned int **len) +{ + struct ap_json *a = (struct ap_json*)h->data; + unsigned int *nop; + + /* push some extra data after the start of the initial object */ + if (token == '{' && !(a->flags & AP_HAD_START)) { + a->flags |= AP_HAD_START | AP_IS_START; + + if (!handle_token(&a->compact_handler, '{', &nop)) { + note_error(&a->errs, "push @ws_sig { tok oob"); + return 0; + } + + if (!handle_wssig(a)) { + note_error(&a->errs, "push wssig"); + return 0; + } + + if (!handle_wsstamp(a)) { + note_error(&a->errs, "push wsstamp"); + return 0; + } + + if (!handle_wskeyid(a)) { + note_error(&a->errs, "push wskeyid"); + return 0; + } + + if (!handle_wsheaders(a)) { + note_error(&a->errs, "push wsheaders"); + return 0; + } + + return 1; + } + + return handle_token(&a->compact_handler, token, len); +} + +void init_ap_json(struct ap_json *a, struct json_handlers *inner) +{ + memset(a, 0, sizeof(*a)); + init_errors(&a->errs); + copy_json_handlers(inner, &a->compact_handler); +} + +static int handle_ap_bool(struct json_handlers *h, int val) +{ + struct ap_json *a = (struct ap_json*)h->data; + return handle_bool(&a->compact_handler, val); +} + +static int handle_ap_null(struct json_handlers *h) +{ + struct ap_json *a = (struct ap_json*)h->data; + return handle_null(&a->compact_handler); +} + +static int handle_ap_number(struct json_handlers *h, unsigned int number) +{ + struct ap_json *a = (struct ap_json*)h->data; + return handle_number(&a->compact_handler, number); +} + +void make_ap_json_pusher(struct json_handlers *h, struct ap_json *out) +{ + h->data = out; + h->string = handle_ap_string; + h->boolean = handle_ap_bool; + h->null = handle_ap_null; + h->number = handle_ap_number; + h->token = handle_ap_token; +} + diff --git a/src/ap_json.h b/src/ap_json.h @@ -0,0 +1,23 @@ + +#ifndef WOLFSOCKS_APJSON +#define WOLFSOCKS_APJSON + +#include "json.h" +#include "http.h" + +#define AP_IS_CONTEXT (1 << 0) +#define AP_IS_START (1 << 1) +#define AP_HAD_START (1 << 2) + +struct ap_json { + struct json_handlers compact_handler; + struct errors errs; + struct http_header *headers; + struct sig_header *sig; + int flags; +}; + +void init_ap_json(struct ap_json *, struct json_handlers *inner); +void make_ap_json_pusher(struct json_handlers *h, struct ap_json *out); + +#endif /* WOLFSOCKS_APJSON */ diff --git a/src/cursor.h b/src/cursor.h @@ -122,7 +122,11 @@ static inline int pull_data_into_cursor(struct cursor *cursor, static inline int push_data(struct cursor *cursor, unsigned char *data, int len) { if (unlikely(cursor->p + len > cursor->end)) { - printf("push_data oob\n"); + printf("push_data oob: %ld + %d len (end: %ld)\n", + cursor->p - cursor->start, + len, + cursor->end - cursor->start + ); return 0; } diff --git a/src/inbox.c b/src/inbox.c @@ -3,6 +3,7 @@ #include "http.h" #include "util.h" #include "base64.h" +#include "parse.h" #include <assert.h> #include <stdio.h> @@ -33,23 +34,35 @@ static int parse_until(struct cursor *cur, struct cursor *arena, char match, return 0; } -static int parse_kv(struct errors *errs, struct cursor *cur, +static int parse_kv(struct errors *errs, struct cursor *cur, struct cursor *arena, const char **key, const char **val) { + char b = 0; + if (!parse_until(cur, arena, '=', key)) { note_error(errs, "= not found"); return 0; } - if (!parse_until(cur, arena, ',', val)) { - *val = (char*)cur->p; + if (!parse_char(cur, &b, '"')) { + note_error(errs, "\" expected"); + return 0; + } + + if (!parse_until(cur, arena, '"', val)) { + note_error(errs, "\" expected"); + return 0; + } + + if (!parse_char(cur, &b, ',')) { assert(*cur->end == 0); + return 1; } return 1; } -int parse_signature_header(struct errors *errs, struct cursor *arena, +int parse_signature_header(struct errors *errs, struct cursor *arena, const char *value, struct sig_header *out) { const char *key; @@ -64,9 +77,9 @@ int parse_signature_header(struct errors *errs, struct cursor *arena, break; if (!parse_kv(errs, &cur, arena, &key, &val)) { - note_error(errs, "keyid:%s headers:%s sig:%s", - out->key_id, - out->headers, + note_error(errs, "keyid:%s headers:%s sig:%s", + out->key_id, + out->headers, out->signature); break; } @@ -77,8 +90,11 @@ int parse_signature_header(struct errors *errs, struct cursor *arena, out->headers = val; } else if (stricmp(key, "signature")) { out->signature = arena->p; + out->b64_sig = (char*)val; + out->b64_len = strlen(out->b64_sig); - if (!base64_decode((const unsigned char*)val, strlen(val), + if (!base64_decode((const unsigned char*)out->b64_sig, + out->b64_len, arena->p, arena->end - arena->p, &out_len)) { note_error(errs, "base64 decode signature"); @@ -106,7 +122,7 @@ int verify_signature_header(struct sig_header *sig) { int i; - printf("verifying\nkeyid %s\nheaders %s\nsignature ", + printf("verifying\nkeyid %s\nheaders %s\nsignature ", sig->key_id, sig->headers); for (i = 0; i < sig->signature_len; i++) { diff --git a/src/inbox.h b/src/inbox.h @@ -6,6 +6,8 @@ struct sig_header { const char *key_id; + char *b64_sig; + int b64_len; const char *headers; unsigned char *signature; int signature_len; diff --git a/src/json.c b/src/json.c @@ -6,6 +6,11 @@ #include <assert.h> #include <ctype.h> +void init_json_strtok(struct json_strtok *s) +{ + memset(s, 0, sizeof(*s)); +} + void init_json_pusher_with(struct json_pusher *p, struct cursor *out) { memset(p, 0, sizeof(*p)); @@ -134,14 +139,17 @@ static inline int parse_escape(struct json_parser *p) return 1; } -static int parse_string(struct json_parser *p) +static int parse_string_with(struct json_parser *p, int is_key) { char c; unsigned int chr; unsigned char *start; + struct json_strtok str; c = 0; chr = 0; + init_json_strtok(&str); + start = p->cur.p; if (!parse_char(&p->cur, &c, '"')) { @@ -156,8 +164,11 @@ static int parse_string(struct json_parser *p) } if (chr == '"') { - return (*p->handlers.string)(&p->handlers, start+1, - p->cur.p-start-2); + str.text = start+1; + str.size = p->cur.p - start - 2; + str.is_key = is_key; + + return (*p->handlers.string)(&p->handlers, &str); } if (chr == '\\' && !parse_escape(p)) { @@ -170,6 +181,16 @@ static int parse_string(struct json_parser *p) return 0; } +static int inline parse_string(struct json_parser *p) +{ + return parse_string_with(p, 0); +} + +static int inline parse_key(struct json_parser *p) +{ + return parse_string_with(p, 1); +} + static int parse_digits(struct json_parser *p, unsigned int *out) { char c; @@ -271,7 +292,7 @@ static int parse_kv(struct json_parser *p) unsigned int *len; c = 0; - if (!parse_string(p)) { + if (!parse_key(p)) { note_error(&p->errs, "key"); return 0; } @@ -503,8 +524,7 @@ static int parse_array_or_object(struct json_parser *p) } -static void copy_json_handlers(struct json_handlers *src, - struct json_handlers *dst) +void copy_json_handlers(struct json_handlers *src, struct json_handlers *dst) { dst->data = src->data; dst->string = src->string; @@ -514,7 +534,25 @@ static void copy_json_handlers(struct json_handlers *src, dst->token = src->token; } -static int handle_string(struct json_handlers *h, unsigned char *text, int size) +int push_escaped(struct cursor *cur, unsigned char *text, int size) +{ + unsigned char *p; + for (p = text; p < text+size; p++) { + if (*p == '"') { + if (!push_str(cur, "\\\"")) + return 0; + continue; + } + + if (!push_byte(cur, *p)) { + return 0; + } + } + + return 1; +} + +int handle_string(struct json_handlers *h, struct json_strtok *str) { struct json_pusher *p = (struct json_pusher*)h->data; @@ -523,10 +561,16 @@ static int handle_string(struct json_handlers *h, unsigned char *text, int size) return 0; } - /* TODO: re-escape when we have unescaped chars in here? */ - if (!push_data(&p->cur, text, size)) { - note_error(&p->errs, "oob"); - return 0; + if (str->needs_escape) { + if (!push_escaped(&p->cur, str->text, str->size)) { + note_error(&p->errs, "oob"); + return 0; + } + } else { + if (!push_data(&p->cur, str->text, str->size)) { + note_error(&p->errs, "oob"); + return 0; + } } if (!push_byte(&p->cur, '"')) { @@ -537,19 +581,19 @@ static int handle_string(struct json_handlers *h, unsigned char *text, int size) return 1; } -static int handle_bool(struct json_handlers *h, int val) +int handle_bool(struct json_handlers *h, int val) { struct json_pusher *p = (struct json_pusher*)h->data; return push_str(&p->cur, val? "true" : "false"); } -static int handle_null(struct json_handlers *h) +int handle_null(struct json_handlers *h) { struct json_pusher *p = (struct json_pusher*)h->data; return push_data(&p->cur, (unsigned char*)"null", 4); } -static int handle_number(struct json_handlers *h, unsigned int number) +int handle_number(struct json_handlers *h, unsigned int number) { struct json_pusher *p = (struct json_pusher*)h->data; static char digits[16]; @@ -559,7 +603,7 @@ static int handle_number(struct json_handlers *h, unsigned int number) return push_data(&p->cur, (unsigned char*)digits, c); } -static inline int handle_token(struct json_handlers *h, char token, unsigned int **len) +int handle_token(struct json_handlers *h, char token, unsigned int **len) { struct json_pusher *p = (struct json_pusher*)h->data; return push_byte(&p->cur, token); diff --git a/src/json.h b/src/json.h @@ -11,9 +11,16 @@ struct json_pusher { struct cursor cur; }; +struct json_strtok { + unsigned char *text; + int size; + int is_key; + int needs_escape; +}; + struct json_handlers { void *data; - int (*string)(struct json_handlers *data, unsigned char *text, int size); + int (*string)(struct json_handlers *data, struct json_strtok *str); int (*boolean)(struct json_handlers *data, int val); int (*null)(struct json_handlers *data); int (*number)(struct json_handlers *data, unsigned int number); @@ -26,11 +33,18 @@ struct json_parser { struct json_handlers handlers; }; +int handle_string(struct json_handlers *h, struct json_strtok *str); +int handle_bool(struct json_handlers *h, int val); +int handle_null(struct json_handlers *h); +int handle_number(struct json_handlers *h, unsigned int number); +int handle_token(struct json_handlers *h, char type, unsigned int **len); +void init_json_strtok(struct json_strtok *str); void init_json_pusher_with(struct json_pusher *p, struct cursor *out); void init_json_pusher(struct json_pusher *p, unsigned char *buf, size_t size); void init_json_handlers(struct json_handlers *h); void make_compact_handlers(struct json_handlers *h, struct json_pusher *out); int parse_json(unsigned char *buf, size_t buf_size, struct json_parser *, struct json_handlers *); +void copy_json_handlers(struct json_handlers *src, struct json_handlers *dst); #endif diff --git a/src/test_json.c b/src/test_json.c @@ -50,7 +50,7 @@ static void test_ubjson_handler(unsigned char *out, size_t outlen) assert(parse_ubjson(empty, sizeof(empty), &ubjson)); ubjson.cur.p = ubjson.cur.start; - unsigned char kv[] = "{ \"key\" : {\"obj\":123} , \"otherkey\": \"stringy\"}"; + unsigned char kv[] = "{ \"key\" : {\"obj\":123} , \"hmm\":null,\"otherkey\": \"stringy\"}"; assert(parse_ubjson(kv, sizeof(kv), &ubjson)); const char *path[] = {"key", "obj"}; diff --git a/src/ubjson.c b/src/ubjson.c @@ -350,9 +350,9 @@ int ubjson_lookup(struct ubjson *ubjson, const char **path, int path_len, struct } -static inline int handle_ubjson_str(struct json_handlers *h, unsigned char *text, int size) +static inline int handle_ubjson_str(struct json_handlers *h, struct json_strtok *str) { - return push_ubjson_str((struct cursor*)h->data, text, size); + return push_ubjson_str((struct cursor*)h->data, str->text, str->size); } static inline int handle_ubjson_bool(struct json_handlers *h, int val) diff --git a/src/wolfsocks.c b/src/wolfsocks.c @@ -13,10 +13,11 @@ #include <base64.h> #include "http.h" +#include "ap_json.h" #include "inbox.h" #include "json.h" -#define BUF_SIZE 4096 +#define BUF_SIZE 1048576 #define ARENA_SIZE 134217728 /* 128 MB virtual mem arena */ #define streq(a,b) (!strcmp(a,b)) #define patheq(req, x) (streq(x, req->path) || streq(x "/", req->path)) @@ -150,9 +151,15 @@ static int handle_inbox_request(struct http_req *req, struct cursor *arena) struct sig_header sig; struct json_parser pull; struct json_pusher push; + struct ap_json apjson; + struct json_handlers compact; + struct json_handlers ap_handler; make_compact_handlers(&compact, &push); + make_ap_json_pusher(&ap_handler, &apjson); + init_ap_json(&apjson, &compact); + memset(&sig, 0, sizeof(sig)); if (!get_header(req->headers, "signature", &signature)) { @@ -167,6 +174,10 @@ static int handle_inbox_request(struct http_req *req, struct cursor *arena) return 0; } + apjson.sig = &sig; + apjson.headers = req->headers; + + // TODO: defer this check if (!verify_signature_header(&sig)) { note_error(&req->errs, "verify"); return 0; @@ -175,7 +186,7 @@ static int handle_inbox_request(struct http_req *req, struct cursor *arena) start = arena->p; init_json_pusher_with(&push, arena); - if (!parse_json(req->body, req->body_len, &pull, &compact)) { + if (!parse_json(req->body, req->body_len, &pull, &ap_handler)) { note_error(&req->errs, "json parse failed"); return 0; }