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:
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;
}