#include #include #include #include #include "json.h" #include "misc.h" JSON* jalloc(int t) { JSON *j = mallocz(sizeof(JSON), 1); if(j == nil) sysfatal("jalloc: %r"); j->t = t; setmalloctag(j, getcallerpc(&t)); return j; } JSONEl* jealloc(JSONEl *next) { JSONEl *el = mallocz(sizeof(JSONEl), 1); if(el == nil) sysfatal("jealloc: %r"); el->next = next; setmalloctag(el, getcallerpc(&next)); return el; } JSON* jstr(char *s) { assert(s != nil); JSON *j = jalloc(JSONString); j->s = s; return j; } JSON* jstrdup(char *s) { assert(s != nil); return jstr(estrdup(s)); } static JSONEl* lastel(JSONEl* e) { JSONEl *it; for(it = e; it != nil && it->next != nil; it = it->next) ; return it; } // Insert a key/value in a JSONObject void jappend(JSON *j, char *k, JSON *v) { JSONEl *je; assert(j != nil); assert(j->t == JSONObject); assert(k != nil); assert(v != nil); je = jealloc(j->first); je->name = k; je->val = v; j->first = je; } void jappendstr(JSON *j, char *k, char *v) { JSON *jv = jstrdup(v); jappend(j, k, jv); } // Insert a value in a JSONArray void jarray(JSON *j, JSON *e) { JSONEl *je; assert(j != nil); assert(j->t = JSONArray); assert(e != nil); je = jealloc(j->first); je->val = e; j->first = je; } char* jgetstr(JSON *j, char *key) { JSON *jk; jk = jsonbyname(j, key); if(jk == nil) return nil; if(jk->t != JSONString) return nil; return estrdup(jk->s); } // acme stuff char* json_fmt_signed(char *header, char *protected, char *payload, char *signature) { JSON *jo = jalloc(JSONObject); //jappend(jo, estrdup("header"), jstrdup(header)); jappend(jo, estrdup("protected"), jstrdup(protected)); jappend(jo, estrdup("payload"), jstrdup(payload)); jappend(jo, estrdup("signature"), jstrdup(signature)); char *r = smprint("%J", jo); if(r == nil) sysfatal("smprint: %r"); jsonfree(jo); return r; } char* json_fmt_header_rsa(char *exp, char *mod) { JSON *jo = jalloc(JSONObject); jappend(jo, estrdup("alg"), jstrdup("RS256")); JSON *jwk = jalloc(JSONObject); jappend(jwk, estrdup("e"), jstrdup(exp)); jappend(jwk, estrdup("kty"), jstrdup("RSA")); jappend(jwk, estrdup("n"), jstrdup(mod)); jappend(jo, estrdup("jwk"), jwk); char *r = smprint("%J", jo); if(r == nil) sysfatal("smprint: %r"); jsonfree(jo); return r; } char* json_fmt_protected_rsa(char *exp, char *mod, char *nonce) { JSON *jo = jalloc(JSONObject); jappend(jo, estrdup("alg"), jstrdup("RS256")); jappend(jo, estrdup("nonce"), jstrdup(nonce)); JSON *jwk = jalloc(JSONObject); jappend(jwk, estrdup("e"), jstrdup(exp)); jappend(jwk, estrdup("kty"), jstrdup("RSA")); jappend(jwk, estrdup("n"), jstrdup(mod)); jappend(jo, estrdup("jwk"), jwk); char *r = smprint("%J", jo); if(r == nil) sysfatal("smprint: %r"); jsonfree(jo); return r; } char* json_fmt_thumb_rsa(char *exp, char *mod) { char *r; /*NOTE: WHITESPACE IS IMPORTANT. */ r = smprint("{\"e\":\"%s\",\"kty\":\"RSA\",\"n\":\"%s\"}", exp, mod); if(r == nil) sysfatal("smprint: %r"); return r; } char* json_fmt_newcert(char *cert) { JSON *jo = jalloc(JSONObject); jappend(jo, estrdup("resource"), jstrdup("new-cert")); jappend(jo, estrdup("csr"), jstrdup(cert)); char *r = smprint("%J", jo); if(r == nil) sysfatal("smprint: %r"); jsonfree(jo); return r; } char* json_fmt_newauthz(char *type, char *value) { JSON *jo = jalloc(JSONObject); jappend(jo, estrdup("resource"), jstrdup("new-authz")); JSON *jident = jalloc(JSONObject); jappend(jident, estrdup("type"), jstrdup(type)); jappend(jident, estrdup("value"), jstrdup(value)); jappend(jo, estrdup("identifier"), jident); char *r = smprint("%J", jo); if(r == nil) sysfatal("smprint: %r"); jsonfree(jo); return r; } char* json_fmt_challenge(char *token, char *thumb) { JSON *jo = jalloc(JSONObject); jappend(jo, estrdup("resource"), jstrdup("challenge")); char *k = smprint("%s.%s", token, thumb); if(k == nil) sysfatal("smprint: %r"); jappend(jo, estrdup("keyAuthorization"), jstr(k)); char *r = smprint("%J", jo); if(r == nil) sysfatal("smprint: %r"); jsonfree(jo); return r; } ACMEChallenge* json_parse_challenge(char *js, char *challtype) { int rc; char *s; JSON *j, *jchal, *jc; JSONEl *el; ACMEChallenge *chal = nil; j = jsonparse(js); if(j == nil){ werrstr("invalid challenge json: %r"); return nil; } if(challtype == nil) challtype = "http-01"; jchal = jsonbyname(j, "challenges"); if(jchal == nil){ werrstr("missing challenges field: %r"); goto Error; } if(jchal->t != JSONArray){ werrstr("challenges not an array"); goto Error; } chal = mallocz(sizeof(ACMEChallenge), 1); if(chal == nil) goto Error; for(el = jchal->first; el != nil; el = el->next){ if(el->val->t != JSONObject) continue; jc = el->val; s = jgetstr(jc, "type"); if(s == nil) continue; rc = strcmp(s, challtype); free(s); if(rc != 0) continue; chal->uri = jgetstr(jc, "uri"); chal->token = jgetstr(jc, "token"); if(chal->uri == nil || chal->token == nil) goto Error; return chal; } Error: challengefree(chal); jsonfree(j); return nil; } void challengefree(ACMEChallenge *chal) { if(chal != nil){ free(chal->uri); free(chal->token); } free(chal); }