chiark / gitweb /
site: Introduce `pubkey' variable (twice)
[secnet.git] / site.c
diff --git a/site.c b/site.c
index 5f415dec7a55093e7aa00dfd34ad1e7400ef3f86..922aa590396e85acef813696aec2764393d05b7a 100644 (file)
--- a/site.c
+++ b/site.c
@@ -142,6 +142,7 @@ static cstring_t state_name(uint32_t state)
 #define LOG_DUMP          0x00000100
 #define LOG_ERROR         0x00000400
 #define LOG_PEER_ADDRS    0x00000800
+#define LOG_SIGKEYS       0x00001000
 
 static struct flagstr log_event_table[]={
     { "unexpected", LOG_UNEXPECTED },
@@ -155,8 +156,9 @@ static struct flagstr log_event_table[]={
     { "dump-packets", LOG_DUMP },
     { "errors", LOG_ERROR },
     { "peer-addrs", LOG_PEER_ADDRS },
+    { "sigkeys", LOG_SIGKEYS },
     { "default", LOG_SETUP_INIT|LOG_SETUP_TIMEOUT|
-      LOG_ACTIVATE_KEY|LOG_TIMEOUT_KEY|LOG_SEC|LOG_ERROR },
+      LOG_ACTIVATE_KEY|LOG_TIMEOUT_KEY|LOG_SEC|LOG_ERROR|LOG_SIGKEYS },
     { "all", 0xffffffff },
     { NULL, 0 }
 };
@@ -392,19 +394,28 @@ static uint32_t event_log_priority(struct site *st, uint32_t event)
     case LOG_DUMP:          return M_DEBUG;
     case LOG_ERROR:         return M_ERR;
     case LOG_PEER_ADDRS:    return M_DEBUG;
+    case LOG_SIGKEYS:       return M_INFO;
     default:                return M_ERR;
     }
 }
 
+static uint32_t slog_start(struct site *st, uint32_t event)
+{
+    uint32_t class=event_log_priority(st, event);
+    if (class) {
+       slilog_part(st->log,class,"%s: ",st->tunname);
+    }
+    return class;
+}
+
 static void vslog(struct site *st, uint32_t event, cstring_t msg, va_list ap)
 FORMAT(printf,3,0);
 static void vslog(struct site *st, uint32_t event, cstring_t msg, va_list ap)
 {
     uint32_t class;
 
-    class=event_log_priority(st, event);
+    class=slog_start(st,event);
     if (class) {
-       slilog_part(st->log,class,"%s: ",st->tunname);
        vslilog_part(st->log,class,msg,ap);
        slilog_part(st->log,class,"\n");
     }
@@ -639,6 +650,7 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what,
     if (type_is_msg34(type)) {
        buf_append_uint16(&st->buffer,st->mtu_target);
     }
+    struct sigprivkey_if *privkey=st->privkey;
     append_string_xinfo_done(&st->buffer,&xia);
 
     buf_append_string(&st->buffer,st->remotename);
@@ -659,10 +671,10 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what,
     buf_append_string(&st->buffer,dhpub);
     free(dhpub);
 
-    bool_t ok=st->privkey->sign(st->privkey->st,
-                               st->buffer.start,
-                               st->buffer.size,
-                               &st->buffer);
+    bool_t ok=privkey->sign(privkey->st,
+                           st->buffer.start,
+                           st->buffer.size,
+                           &st->buffer);
     if (!ok) goto fail;
     return True;
 
@@ -744,8 +756,9 @@ static bool_t unpick_msg(struct site *st, uint32_t type,
     CHECK_AVAIL(msg,m->pklen);
     m->pk=buf_unprepend(msg,m->pklen);
     m->hashlen=msg->start-m->hashstart;
+    struct sigpubkey_if *pubkey=st->pubkey;
 
-    if (!st->pubkey->unpick(st->pubkey->st,msg,&m->sig)) {
+    if (!pubkey->unpick(pubkey->st,msg,&m->sig)) {
        return False;
     }
 
@@ -798,10 +811,16 @@ static bool_t check_msg(struct site *st, uint32_t type, struct msg *m,
     return False;
 }
 
-static bool_t generate_msg1(struct site *st, const struct msg *prompt_maybe_0)
+static bool_t kex_init(struct site *st)
 {
     st->random->generate(st->random->st,NONCELEN,st->localN);
-    return generate_msg(st,LABEL_MSG1,"site:MSG1",prompt_maybe_0);
+    return True;
+}
+
+static bool_t generate_msg1(struct site *st, const struct msg *prompt_maybe_0)
+{
+    return
+       generate_msg(st,LABEL_MSG1,"site:MSG1",prompt_maybe_0);
 }
 
 static bool_t process_msg1(struct site *st, struct buffer_if *msg1,
@@ -821,8 +840,8 @@ static bool_t process_msg1(struct site *st, struct buffer_if *msg1,
 static bool_t generate_msg2(struct site *st,
                            const struct msg *prompt_may_be_null)
 {
-    st->random->generate(st->random->st,NONCELEN,st->localN);
-    return generate_msg(st,LABEL_MSG2,"site:MSG2",prompt_may_be_null);
+    return
+       generate_msg(st,LABEL_MSG2,"site:MSG2",prompt_may_be_null);
 }
 
 static bool_t process_msg2(struct site *st, struct buffer_if *msg2,
@@ -886,10 +905,12 @@ static bool_t generate_msg3(struct site *st, const struct msg *prompt)
 
 static bool_t process_msg3_msg4(struct site *st, struct msg *m)
 {
+    struct sigpubkey_if *pubkey=st->pubkey;
+
     /* Check signature and store g^x mod m */
-    if (!st->pubkey->check(st->pubkey->st,
-                          m->hashstart,m->hashlen,
-                          &m->sig)) {
+    if (!pubkey->check(pubkey->st,
+                      m->hashstart,m->hashlen,
+                      &m->sig)) {
        slog(st,LOG_SEC,"msg3/msg4 signature failed check!");
        return False;
     }
@@ -1585,12 +1606,14 @@ static bool_t enter_new_state(struct site *st, uint32_t next,
     switch(next) {
     case SITE_SENTMSG1:
        state_assert(st,st->state==SITE_RUN || st->state==SITE_RESOLVE);
+       if (!kex_init(st)) return False;
        gen=generate_msg1;
        st->msg1_crossed_logged = False;
        break;
     case SITE_SENTMSG2:
        state_assert(st,st->state==SITE_RUN || st->state==SITE_RESOLVE ||
                     st->state==SITE_SENTMSG1 || st->state==SITE_WAIT);
+       if (!kex_init(st)) return False;
        gen=generate_msg2;
        break;
     case SITE_SENTMSG3:
@@ -1805,15 +1828,31 @@ static void site_outgoing(void *sst, struct buffer_if *buf)
 }
 
 static bool_t named_for_us(struct site *st, const struct buffer_if *buf_in,
-                          uint32_t type, struct msg *m)
+                          uint32_t type, struct msg *m,
+                          struct priomsg *whynot)
     /* For packets which are identified by the local and remote names.
      * If it has our name and our peer's name in it it's for us. */
 {
     struct buffer_if buf[1];
     buffer_readonly_clone(buf,buf_in);
-    return unpick_msg(st,type,buf,m)
-       && name_matches(&m->remote,st->remotename)
-       && name_matches(&m->local,st->localname);
+
+    if (!unpick_msg(st,type,buf,m)) {
+       priomsg_update_fixed(whynot, comm_notify_whynot_unpick, "malformed");
+       return False;
+    }
+#define NAME_MATCHES(lr)                                               \
+    if (!name_matches(&m->lr, st->lr##name)) {                         \
+       if (priomsg_update_fixed(whynot, comm_notify_whynot_name_##lr,  \
+                                 "unknown " #lr " name: ")) {          \
+            truncmsg_add_packet_string(&whynot->m, m->lr.len, m->lr.name); \
+        }                                                              \
+        return False;                                                  \
+    }
+    NAME_MATCHES(remote);
+    NAME_MATCHES(local );
+#undef NAME_MATCHES
+
+    return True;
 }
 
 static bool_t we_have_priority(struct site *st, const struct msg *m) {
@@ -1834,7 +1873,7 @@ static bool_t setup_late_msg_ok(struct site *st,
      * late.  Maybe they came via a different path.  All we do is make
      * a note of the sending address, iff they look like they are part
      * of the current key setup attempt. */
-    if (!named_for_us(st,buf_in,msgtype,m))
+    if (!named_for_us(st,buf_in,msgtype,m,0))
        /* named_for_us calls unpick_msg which gets the nonces */
        return False;
     if (!consttime_memeq(m->nR,st->remoteN,NONCELEN) ||
@@ -1851,7 +1890,8 @@ static bool_t setup_late_msg_ok(struct site *st,
    this current site instance (and should therefore not be processed
    by other sites), even if the packet was otherwise ignored. */
 static bool_t site_incoming(void *sst, struct buffer_if *buf,
-                           const struct comm_addr *source)
+                           const struct comm_addr *source,
+                           struct priomsg *whynot)
 {
     struct site *st=sst;
 
@@ -1863,7 +1903,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
       /* initialised by named_for_us, or process_msgN for N!=1 */
 
     if (msgtype==LABEL_MSG1) {
-       if (!named_for_us(st,buf,msgtype,&msg))
+       if (!named_for_us(st,buf,msgtype,&msg,whynot))
            return False;
        /* It's a MSG1 addressed to us. Decide what to do about it. */
        dump_packet(st,buf,source,True,True);
@@ -1927,7 +1967,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
        return True;
     }
     if (msgtype==LABEL_PROD) {
-       if (!named_for_us(st,buf,msgtype,&msg))
+       if (!named_for_us(st,buf,msgtype,&msg,whynot))
            return False;
        dump_packet(st,buf,source,True,True);
        if (st->state!=SITE_RUN) {
@@ -2056,6 +2096,8 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
        return True;
     }
 
+    priomsg_update_fixed(whynot, comm_notify_whynot_general,
+                        "not MSG1 or PROD; unknown dest index");
     return False;
 }
 
@@ -2091,6 +2133,17 @@ static void site_childpersist_clearkeys(void *sst, uint32_t newphase)
        crypto operations, but that's a task for another day. */
 }
 
+static void setup_sethash(struct site *st, dict_t *dict,
+                         struct hash_if **hash, struct cloc loc,
+                         sig_sethash_fn *sethash, void *sigkey_st) {
+    if (!*hash) *hash=find_cl_if(dict,"hash",CL_HASH,True,"site",loc);
+    sethash(sigkey_st,*hash);
+}
+#define SETUP_SETHASH(k) do{                                           \
+    if ((k)->sethash)                                                  \
+        setup_sethash(st,dict, &hash,loc, (k)->sethash,(k)->st);       \
+}while(0)
+
 static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
                          list_t *args)
 {
@@ -2183,6 +2236,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
     st->log=find_cl_if(dict,"log",CL_LOG,True,"site",loc);
     st->random=find_cl_if(dict,"random",CL_RANDOMSRC,True,"site",loc);
 
+    struct hash_if *hash=0;
     st->privkey=find_cl_if(dict,"local-key",CL_SIGPRIVKEY,True,"site",loc);
     st->addresses=dict_read_string_array(dict,"address",False,"site",loc,0);
     if (st->addresses)
@@ -2194,11 +2248,8 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
 
     st->dh=find_cl_if(dict,"dh",CL_DH,True,"site",loc);
 
-    if (st->privkey->sethash || st->pubkey->sethash) {
-       struct hash_if *hash=find_cl_if(dict,"hash",CL_HASH,True,"site",loc);
-       if (st->privkey->sethash) st->privkey->sethash(st->privkey->st,hash);
-       if (st->pubkey->sethash) st->pubkey->sethash(st->pubkey->st,hash);
-    }
+    SETUP_SETHASH(st->privkey);
+    SETUP_SETHASH(st->pubkey);
 
 #define DEFAULT(D) (st->peer_mobile || st->local_mobile        \
                     ? DEFAULT_MOBILE_##D : DEFAULT_##D)