X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=site.c;h=72cee24fc8d094d791a5ed8dab4b17ae71224671;hb=49b56eafcd147185c28848a7c04e31a32c49a82e;hp=3ce60fe48a5d6d7b8b81c58f3956fdf6cf72efa6;hpb=ffbf811dd1b9e7f390ac2fa497e15764a87694ff;p=secnet.git diff --git a/site.c b/site.c index 3ce60fe..72cee24 100644 --- a/site.c +++ b/site.c @@ -662,10 +662,7 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what, struct xinfoadd xia; append_string_xinfo_start(&st->buffer,&xia,st->localname); - if ((st->local_capabilities & st->early_capabilities) || - (type != LABEL_MSG1)) { - buf_append_uint32(&st->buffer,st->local_capabilities); - } + buf_append_uint32(&st->buffer,st->local_capabilities); if (type_is_msg34(type)) { buf_append_uint16(&st->buffer,st->mtu_target); } @@ -710,6 +707,8 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what, return False; privkey_found: + slog(st,LOG_SIGKEYS,"using private key #%d " SIGKEYID_PR_FMT, + ki, SIGKEYID_PR_VAL(prompt->pubkeys_accepted[ki])); buf_append_uint8(&st->buffer,ki); } @@ -928,118 +927,6 @@ static void peerkeys_maybe_incorporate(struct site *st, const char *file, static void peerkeys_check_for_update(struct site *st) { - /* peerkeys files - * - * live file, loaded on startup, updated by secnet - * (only). * in-memory peerkeys_current is kept - * synced with this file - * - * ~update update file from config manager, checked before - * every key exchange. config manager must rename - * this file into place; it will be renamed and - * then removed by secnet. - * - * ~proc update file being processed by secnet. - * only secnet may write or remove. - * - * ~incoming update file from peer, being received by secnet - * may be incomplete, unverified, or even malicious - * only secnet may write or remove. - * - * ~tmp update file from config manager, only mss may - * write or rename - * - * secnet discards updates that are not more recent than (by - * serial) the live file. But it may not process updates - * immediately. - * - * The implied keyset to be used is MAX(live, proc, update). - * - * secnet does: - * check live vs proc, either mv proc live or rm proc - * if proc doesn't exist, mv update proc - * - * make-secnet-sites does: - * write: rename something onto update - * read: read update,proc,live in that order and take max - * - * We support only one concurrent secnet, one concurrent - * writing make-secnet-sites, and any number of readers. - * We want to maintain a live file at all times as that - * is what secnet actually reads at startup and uses. - * - * Proof that this is sound: - * Let us regard update,proc,live as i=0,1,2 - * Files contain public key sets and are manipulated as - * a whole, and we may regard key sets with the same - * serial as equivalent. - * We talk below about reading as if it were atomic. - * Actually the atomic operation is open(2); the - * reading gets whatever that name refers to. So - * we can model this as an atomic read. - * secnet eventually moves all data into the live file - * or deletes it, so there should be no indefinitely - * stale data; informally this means we can disregard - * the possibility of very old serials and regard - * serials as fully ordered. (We don't bother with - * a formal proof of this property.) - * Consequently we will only think about the serial - * and not the contents. We treat absent files as - * minimal (we will write -1 for convenience although - * we don't mean a numerical value). We write S(i). - * - * Invariant 1 for secnet's transformations is as follows: - * Each file S(i) is only reduced (to S'(i)) if for some j S'(j) - * >= S(i), with S'(j) either being >= S(i) beforehand, or - * updated atomically together with S(i). - * - * Proof of invariant 1 for the secnet operations: - * (a) check live vs proc, proc>live, mv: - * j=2, i=1; S'(i)=-1, so S(i) is being reduced. S'(j) is - * equal to S(i), and the rename is atomic [1], so S'(j) and - * S'(i) are updated simultaneously. S(j) is being - * increased. (There are no hazards from concurrent writers; - * only we ourselves (secnet) write to live or proc.) - * (b) check live vs proc, proc<=live, rm: - * j=2, i=1; S'(i)=-1, so S(i) is being reduced. But - * S(j) is >= $(i) throughout. (Again, no concurrent - * writer hazards.) - * (c) mv update proc (when proc does not exist): - * j=1, i=0; S(i) is being reduced to -1. But simultaneously - * S(j) is being increased to the old S(i). Our precondition - * (proc not existing) is not subject to a concurrent writer - * hazards because only we write to proc; our action is - * atomic and takes whatever update is available (if any). - * - * Proof of soundness for the mss reading operation: - * Let M be MAX(\forall S) at the point where mss reads update. - * Invariant 2: when mss reads S(k), MAX(K, S(k)..S(2)) >= M, - * where K is the max S it has seen so far. Clearly this is - * true for k=0 (with K==-1). secnet's operations never break - * this invariant because if any S() is reduced, another one - * counted must be increased. mss's step operation - * updates K with S(k), so MAX(K', S(k+1)..)=MAX(K, S(k)..), - * and updates k to k+1, preserving the invariant. - * At the end we have k=3 and K=>M. Since secnet never - * invents serials, K=M in the absence of an mss update - * with a bigger S. - * - * Consideration of the mss update operation: - * Successive serials from sites file updates etc. are supposed - * to be increasing. When this is true, M is increased. A - * concurrent reading mss which makes its first read after the - * update will get the new data (by the proofs above). This - * seems to be the required property. - * - * QED. - * - * [1] From "Base Specifications issue 7", - * 2.9.7 Thread Interactions with Regular File Operations - * All of the following functions shall be atomic with respect to - * each other in the effects specified in POSIX.1-2017 when they - * operate on regular files or symbolic links: - * ... rename ... open ... - */ if (!st->peerkeys_path) return; pathprefix_template_setsuffix(&st->peerkeys_tmpl,"~proc"); @@ -1199,9 +1086,14 @@ static bool_t process_msg3_msg4(struct site *st, struct msg *m) if (!pubkey->check(pubkey->st, m->hashstart,m->hashlen, &m->sig)) { - slog(st,LOG_SEC,"msg3/msg4 signature failed check!"); + slog(st,LOG_SEC,"msg3/msg4 signature failed check!" + " (key #%d " SIGKEYID_PR_FMT ")", + ki, SIGKEYID_PR_VAL(&st->peerkeys_kex->keys[ki].id)); return False; } + slog(st,LOG_SIGKEYS,"verified peer signature with key #%d " + SIGKEYID_PR_FMT, ki, + SIGKEYID_PR_VAL(&st->peerkeys_kex->keys[ki].id)); st->remote_adv_mtu=m->remote_mtu; @@ -2422,17 +2314,6 @@ 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) { @@ -2461,9 +2342,19 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, cfgfatal(loc,"site","parameter must be a dictionary\n"); dict=item->data.dict; + st->log=find_cl_if(dict,"log",CL_LOG,True,"site",loc); + st->log_events=string_list_to_word(dict_lookup(dict,"log-events"), + log_event_table,"site"); + st->localname=dict_read_string(dict, "local-name", True, "site", loc); st->remotename=dict_read_string(dict, "name", True, "site", loc); + st->tunname=safe_malloc(strlen(st->localname)+strlen(st->remotename)+5, + "site_apply"); + sprintf(st->tunname,"%s<->%s",st->localname,st->remotename); + + /* Now slog is working */ + st->keepalive=dict_read_bool(dict,"keepalive",False,"site",loc,False); st->peer_mobile=dict_read_bool(dict,"mobile",False,"site",loc,False); @@ -2525,16 +2416,12 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, } st->resolver=find_cl_if(dict,"resolver",CL_RESOLVER,True,"site",loc); - 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->privkeys=find_cl_if(dict,"key-cache",CL_PRIVCACHE,False,"site",loc); if (!st->privkeys) { st->privkey_fixed= find_cl_if(dict,"local-key",CL_SIGPRIVKEY,True,"site",loc); - SETUP_SETHASH(st->privkey_fixed); } struct sigpubkey_if *fixed_pubkey @@ -2551,7 +2438,6 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, } } else { assert(fixed_pubkey); - SETUP_SETHASH(fixed_pubkey); NEW(st->peerkeys_current); st->peerkeys_current->refcount=1; st->peerkeys_current->nkeys=1; @@ -2604,16 +2490,9 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, "renegotiate-time must be less than key-lifetime\n"); } - st->log_events=string_list_to_word(dict_lookup(dict,"log-events"), - log_event_table,"site"); - st->resolving_count=0; st->allow_send_prod=0; - st->tunname=safe_malloc(strlen(st->localname)+strlen(st->remotename)+5, - "site_apply"); - sprintf(st->tunname,"%s<->%s",st->localname,st->remotename); - /* The information we expect to see in incoming messages of type 1 */ /* fixme: lots of unchecked overflows here, but the results are only corrupted packets rather than undefined behaviour */ @@ -2720,6 +2599,8 @@ static void transport_peers_debug(struct site *st, transport_peers *dst, static void transport_peers_expire(struct site *st, transport_peers *peers) { /* peers must be sorted first */ + if (st->local_mobile) return; + int previous_peers=peers->npeers; struct timeval oldest; oldest.tv_sec = tv_now->tv_sec - st->mobile_peer_expiry;