Exemple #1
0
// decode base64 into the pair of lob packets
lob_t jwt_decode(char *encoded, size_t len)
{
  lob_t header, claims;
  char *dot1, *dot2, *end;
  size_t dlen;

  if(!encoded) return NULL;
  if(!len) len = strlen(encoded);
  end = encoded+(len-1);
  
  // make sure the dot separators are there
  dot1 = strchr(encoded,'.');
  if(!dot1 || dot1+1 >= end) return LOG("missing/bad first separator");
  dot1++;
  dot2 = strchr(dot1,'.');
  if(!dot2 || (dot2+1) >= end) return LOG("missing/bad second separator");
  dot2++;

  claims = lob_new();
  header = lob_link(NULL, claims);
  
  // decode claims sig first
  dlen = base64_decoder(dot2, (end-dot2)+1, (uint8_t*)dot2);
  lob_body(claims, (uint8_t*)dot2, dlen);

  // decode claims json
  dlen = base64_decoder(dot1, (dot2-dot1), (uint8_t*)dot1);
  lob_head(claims, (uint8_t*)dot1, dlen);

  // decode header json
  dlen = base64_decoder(encoded, (dot1-encoded), (uint8_t*)encoded);
  lob_head(header, (uint8_t*)encoded, dlen);

  return header;
}
Exemple #2
0
// add a custom outgoing handshake packet to all links
mesh_t mesh_handshake(mesh_t mesh, lob_t handshake)
{
  if(!mesh) return NULL;
  if(handshake && !lob_get(handshake,"type")) return LOG("handshake missing a type: %s",lob_json(handshake));
  mesh->handshakes = lob_link(handshake, mesh->handshakes);
  return mesh;
}
Exemple #3
0
lob_t util_uri_add_path(lob_t uri, lob_t path)
{
  lob_t keys;
  lob_t query = lob_linked(uri);
  if(!uri || !path) return NULL;
  if(!query)
  {
    if(!(query = lob_new())) return LOG("OOM");
    lob_link(uri, query);
  }
  // encode and add to chain after query
  if(!(keys = lob_new())) return LOG("OOM");
  lob_set_base32(keys,"paths",path->head,path->head_len);
  lob_link(keys, lob_linked(query));
  lob_link(query, keys);
  
  return uri;
}
Exemple #4
0
lob_t link_handshakes(link_t link)
{
  uint32_t i;
  uint8_t csid;
  char *key;
  lob_t tmp, hs = NULL, handshakes = NULL;
  if(!link) return NULL;
  
  // no keys means we have to generate a handshake for each key
  if(!link->x)
  {
    for(i=0;(key = lob_get_index(link->mesh->keys,i));i+=2)
    {
      util_unhex(key,2,&csid);
      hs = lob_new();
      tmp = hashname_im(link->mesh->keys, csid);
      lob_body(hs, lob_raw(tmp), lob_len(tmp));
      lob_free(tmp);
      handshakes = lob_link(hs, handshakes);
    }
  }else{ // generate one just for this csid
    handshakes = lob_new();
    tmp = hashname_im(link->mesh->keys, link->csid);
    lob_body(handshakes, lob_raw(tmp), lob_len(tmp));
    lob_free(tmp);
  }

  // add any custom per-link
  for(hs = link->handshakes; hs; hs = lob_linked(hs)) handshakes = lob_link(lob_copy(hs), handshakes);

  // add any mesh-wide handshakes
  for(hs = link->mesh->handshakes; hs; hs = lob_linked(hs)) handshakes = lob_link(lob_copy(hs), handshakes);
  
  // encrypt them if we can
  if(link->x)
  {
    tmp = handshakes;
    handshakes = NULL;
    for(hs = tmp; hs; hs = lob_linked(hs)) handshakes = lob_link(e3x_exchange_handshake(link->x, hs), handshakes);
    lob_free(tmp);
  }

  return handshakes;
}
Exemple #5
0
// get paths from host and query
lob_t util_uri_paths(lob_t uri)
{
  uint32_t i;
  uint16_t port;
  uint8_t *buf;
  size_t len;
  char *key, *value;
  lob_t paths, query = lob_linked(uri);
  if(!query) return NULL;
  paths = NULL;
  
  // gen paths from host/port
  if((port = lob_get_uint(uri,"port")))
  {
    key = lob_get(uri,"host");
    paths = lob_chain(paths);
    lob_set(paths,"type","upd4");
    lob_set(paths,"ip",key);
    lob_set_uint(paths,"port",port);
    paths = lob_chain(paths);
    lob_set(paths,"type","tcp4");
    lob_set(paths,"ip",key);
    lob_set_uint(paths,"port",port);
  }

  // loop through all keyval pairs to find paths
  buf = NULL;
  for(i=0;(key = lob_get_index(query,i));i+=2)
  {
    value = lob_get_index(query,i+1);
    if(util_cmp(key,"paths") != 0 || !value) continue;
    len = base32_decode_floor(strlen(value));
    buf = util_reallocf(buf,len);
    if(!buf) continue;
    if(base32_decode(value,strlen(value),buf,len) < len) continue;
    paths = lob_link(lob_parse(buf,len), paths);
  }
  free(buf);
  
  return paths;
}
Exemple #6
0
// decode base64 into the pair of lob packets
lob_t jwt_decode(char *encoded, size_t len)
{
  lob_t header, claims;
  char *dot1, *dot2, *end;

  if(!encoded) return NULL;
  if(!len) len = strlen(encoded);
  end = encoded+len;
  
  // make sure the dot separators are there
  dot1 = memchr(encoded,'.',(end-encoded));
  if(!dot1) return LOG_INFO("missing/bad first separator");
  dot1++;
  dot2 = memchr(dot1,'.',(end-dot1));
  if(!dot2) return LOG_INFO("missing/bad second separator");
  dot2++;

  // quick sanity check of the base64
  if(!base64_decoder(dot2, (end-dot2), NULL)) return LOG_INFO("invalid sig base64: %.*s",(end-dot2),dot2);
  if(!base64_decoder(dot1, (dot2-dot1)-1, NULL)) return LOG_INFO("invalid claims base64: %.*s",(dot2-dot1)-1,dot1);
  if(!base64_decoder(encoded, (dot1-encoded)-1, NULL)) return LOG_INFO("invalid header b64: %.*s",(dot1-encoded)-1,encoded);

  claims = lob_new();
  header = lob_link(NULL, claims);
  
  // decode claims json
  lob_head(claims, NULL, base64_decoder(dot1, (dot2-dot1)-1, NULL));
  base64_decoder(dot1, (dot2-dot1)-1, lob_head_get(claims));

  // decode claims sig 
  lob_body(claims, NULL, base64_decoder(dot2, (end-dot2), NULL));
  base64_decoder(dot2, (end-dot2), lob_body_get(claims));

  // decode header json
  lob_head(header, NULL, base64_decoder(encoded, (dot1-encoded)-1, NULL));
  base64_decoder(encoded, (dot1-encoded)-1, lob_head_get(header));

  return header;
}
Exemple #7
0
lob_t util_uri_add_keys(lob_t uri, lob_t keys)
{
  uint32_t i;
  char *key, *value, csid[5];
  lob_t query = lob_linked(uri);
  if(!uri || !keys) return NULL;
  if(!query)
  {
    query = lob_new();
    lob_link(uri, query);
  }
  
  for(i=0;(key = lob_get_index(keys,i));i+=2)
  {
    value = lob_get_index(keys,i+1);
    if(strlen(key) != 2 || !value) continue; // paranoid
    snprintf(csid,5,"cs%s",key);
    lob_set(query,csid,value);
  }

  return uri;
}
Exemple #8
0
// generate an outgoing request, send the response attached to the note
chan_t thtp_req(switch_t s, lob_t note)
{
  char *uri, *path, *method;
  hashname_t to = NULL;
  lob_t req;
  chan_t c;
  if(!s || !note) return NULL;

  method = lob_get_str(note,"method");
  path = lob_get_str(note,"path");
  if((uri = lob_get_str(note,"uri")) && strncmp(uri,"thtp://",7) == 0)
  {
    uri += 7;
    path = strchr(uri,'/');
    to = hashname_gethex(s->index,uri);
  }
  if(!to) to = hashname_gethex(s->index,lob_get_str(note,"to"));
  if(!to) return NULL;
  req = lob_linked(note);
  if(!req)
  {
    req = lob_chain(note);
    lob_set_str(req,"path",path?path:"/");
    lob_set_str(req,"method",method?method:"get");
  }

  DEBUG_PRINTF("thtp req %s %s %s %.*s",lob_get_str(req,"method"),lob_get_str(req,"path"),to->hexname,note->json_len,note->json);

  // open channel and send req
  c = chan_new(s, to, "thtp", 0);
  c->arg = lob_link(NULL,note); // create buffer packet w/ the note linked
  c->handler = ext_thtp; // shortcut
  chan_reliable(c,10);
  thtp_send(c,req);

  return c;
}
Exemple #9
0
// just a convenience, generates handshake w/ current e3x_exchange_at value
lob_t e3x_exchange_handshake(e3x_exchange_t x, lob_t inner)
{
  lob_t tmp;
  uint8_t i;
  uint8_t local = 0;
  if(!x) return LOG("invalid args");
  if(!x->out) return LOG("no out set");

  // create deprecated key handshake inner from all supported csets
  if(!inner)
  {
    local = 1;
    inner = lob_new();
    lob_set(inner, "type", "key");
    // loop through all ciphersets for any keys
    for(i=0; i<CS_MAX; i++)
    {
      if(!(tmp = x->self->keys[i])) continue;
      // this csid's key is the body, rest is intermediate in json
      if(e3x_cipher_sets[i] == x->cs)
      {
        lob_body(inner,tmp->body,tmp->body_len);
      }else{
        uint8_t hash[32];
        e3x_hash(tmp->body,tmp->body_len,hash);
        lob_set_base32(inner,e3x_cipher_sets[i]->hex,hash,32);
      }
    }
  }

  // set standard values
  lob_set_uint(inner,"at",x->out);

  tmp = e3x_exchange_message(x, inner);
  if(!local) return tmp;
  return lob_link(tmp, inner);
}
Exemple #10
0
// processes incoming packet, it will take ownership of p
link_t mesh_receive(mesh_t mesh, lob_t outer, pipe_t pipe)
{
  lob_t inner;
  link_t link;
  char token[17];
  hashname_t id;

  if(!mesh || !outer || !pipe) return LOG("bad args");
  
  LOG("mesh receiving %s to %s via pipe %s",outer->head_len?"handshake":"channel",hashname_short(mesh->id),pipe->id);

  // process handshakes
  if(outer->head_len == 1)
  {
    inner = e3x_self_decrypt(mesh->self, outer);
    if(!inner)
    {
      LOG("%02x handshake failed %s",outer->head[0],e3x_err());
      lob_free(outer);
      return NULL;
    }
    
    // couple the two together, inner->outer
    lob_link(inner,outer);

    // set the unique id string based on some of the first 16 (routing token) bytes in the body
    base32_encode(outer->body,10,token,17);
    lob_set(inner,"id",token);

    // process the handshake
    return mesh_receive_handshake(mesh, inner, pipe);
  }

  // handle channel packets
  if(outer->head_len == 0)
  {
    if(outer->body_len < 16)
    {
      LOG("packet too small %d",outer->body_len);
      lob_free(outer);
      return NULL;
    }
    
    route_t route;
    for(route = mesh->routes;route;route = route->next) if(memcmp(route->token,outer->body,8) == 0) break;
    link = route ? route->link : NULL;
    if(!link)
    {
      LOG("dropping, no link for token %s",util_hex(outer->body,16,NULL));
      lob_free(outer);
      return NULL;
    }
    
    // forward packet
    if(!route->flag)
    {
      LOG("forwarding route token %s via %s len %d",util_hex(route->token,8,NULL),hashname_short(link->id),lob_len(outer));
      return link_send(link, outer);
    }
    
    inner = e3x_exchange_receive(link->x, outer);
    lob_free(outer);
    if(!inner) return LOG("channel decryption fail for link %s %s",hashname_short(link->id),e3x_err());
    
    LOG("channel packet %d bytes from %s",lob_len(inner),hashname_short(link->id));
    return link_receive(link,inner,pipe);
    
  }

  // transform incoming bare link json format into handshake for discovery
  if((inner = lob_get_json(outer,"keys")))
  {
    if((id = hashname_vkeys(inner)))
    {
      lob_set(outer,"hashname",hashname_char(id));
      lob_set_int(outer,"at",0);
      lob_set(outer,"type","link");
      LOG("bare incoming link json being discovered %s",lob_json(outer));
    }
    lob_free(inner);
  }
  
  // run everything else through discovery, usually plain handshakes
  mesh_discover(mesh, outer, pipe);
  link = mesh_linked(mesh, lob_get(outer,"hashname"), 0);
  lob_free(outer);

  return link;
}
Exemple #11
0
// add a custom outgoing handshake packet
link_t link_handshake(link_t link, lob_t handshake)
{
  if(!link) return NULL;
  link->handshakes = lob_link(handshake, link->handshakes);
  return link;
}
Exemple #12
0
void ext_thtp(chan_t c)
{
  lob_t p, buf, req, match, note;
  char *path;
  thtp_t t = thtp_get(c->s);

  // incoming note as an answer
  if((note = chan_notes(c)))
  {
    DEBUG_PRINTF("got note resp %.*s",note->json_len,note->json);
    thtp_send(c,lob_linked(note));
    lob_free(note);
    return;
  }

  while((p = chan_pop(c)))
  {
    if(!c->arg)
    {
      c->arg = buf = p;
    }else{
      buf = c->arg;
      lob_append(buf,p->body,p->body_len);
      lob_free(p);
    }
    // for now we're processing whole-requests-at-once, to do streaming we can try parsing note->body for the headers anytime
    if(c->ended) continue;

    // parse the payload
    p = lob_parse(buf->body,buf->body_len);

    // this is a response, send it
    if((note = lob_unlink(buf)))
    {
      lob_free(buf);
      if(p)
      {
        DEBUG_PRINTF("got response %.*s for %.*s",p->json_len,p->json,note->json_len,note->json);        
      }
      lob_link(note,p);
      lob_set_str(note,"thtp","resp");
      chan_reply(c,note);
      chan_end(c,NULL);
      return;
    }

    // this is an incoming request
    lob_free(buf);
    if(!p) return (void)chan_fail(c,"422");
    req = p;

    DEBUG_PRINTF("thtp req packet %.*s", req->json_len, req->json);
    path = lob_get_str(req,"path");
    match = xht_get(t->index,path);
    if(!match) match = _thtp_glob(t,path);
    if(!match)
    {
      chan_fail(c,"404");
      lob_free(req);
      return;
    }

    // built in response
    if(lob_linked(match))
    {
      thtp_send(c,lob_linked(match));
      lob_free(req);
      return;
    }
    
    // attach and route request to a new note
    note = lob_copy(match);
    lob_link(note,req);
    lob_set_str(note,"thtp","req");
    if(chan_reply(c,note) == 0) return;

    chan_fail(c,"500");
    lob_free(req);
  }
  
  // optionally sends ack if needed
  chan_ack(c);
}