X-Git-Url: https://git.distorted.org.uk/~mdw/secnet/blobdiff_plain/0fa27fb315db6cb9a2523e630c58f6fac277dd6f..refs/heads/mdw/xdh:/site.c diff --git a/site.c b/site.c index fed1306..3971e68 100644 --- a/site.c +++ b/site.c @@ -107,7 +107,7 @@ #define SITE_SENTMSG5 7 #define SITE_WAIT 8 -#define CASES_MSG3_KNOWN LABEL_MSG3: case LABEL_MSG3BIS +#define CASES_MSG3_KNOWN LABEL_MSG3: case LABEL_MSG3BIS: case LABEL_MSG3TER int32_t site_max_start_pad = 4*4; @@ -316,7 +316,8 @@ struct site { struct rsapubkey_if *pubkey; struct transform_if **transforms; int ntransforms; - struct dh_if *dh; + struct dh_if **dhs; + int ndhs; struct hash_if *hash; uint32_t index; /* Index of this site */ @@ -361,6 +362,7 @@ struct site { uint32_t remote_capabilities; uint16_t remote_adv_mtu; struct transform_if *chosen_transform; + struct dh_if *chosen_dh; uint32_t setup_session_id; transport_peers setup_peers; uint8_t localN[NONCELEN]; /* Nonces for key exchange */ @@ -528,10 +530,11 @@ struct msg { uint32_t remote_capabilities; uint16_t remote_mtu; int capab_transformnum; + int capab_dhnum; uint8_t *nR; uint8_t *nL; int32_t pklen; - char *pk; + uint8_t *pk; int32_t hashlen; int32_t siglen; char *sig; @@ -547,20 +550,28 @@ static int32_t wait_timeout(struct site *st) { return t; } -static _Bool set_new_transform(struct site *st, char *pk) +static _Bool set_new_transform(struct site *st, uint8_t *pk, int32_t pklen) { _Bool ok; /* Generate the shared key */ - if (!st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->secret_len, - pk, st->sharedsecret,st->dh->shared_len)) + assert(!st->sharedsecret); + st->sharedsecret = safe_malloc(st->chosen_dh->shared_len, + "site:sharedsecret"); + pk[pklen]=0; /* clobbers the following signature length, which we've + * already copied */ + if (!st->chosen_dh->makeshared(st->chosen_dh->st, + st->dhsecret,st->chosen_dh->secret_len, + pk,pklen, + st->sharedsecret, + st->chosen_dh->shared_len)) return False; /* Set up the transform */ struct transform_if *generator=st->chosen_transform; struct transform_inst_if *generated=generator->create(generator->st); ok = generated->setkey(generated->st,st->sharedsecret, - st->dh->shared_len,st->our_name_later); + st->chosen_dh->shared_len,st->our_name_later); dispose_transform(&st->new_transform); if (!ok) return False; @@ -607,7 +618,10 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) { void *hst; uint8_t *hash; - string_t dhpub, sig; + string_t sig; + uint8_t *pklen_addr; + int32_t pklen; + void *pk; unsigned minor; st->retries=st->setup_retries; @@ -641,11 +655,17 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) minor = MSGMINOR(type); if (minor < 1) break; buf_append_uint8(&st->buffer,st->chosen_transform->capab_bit); + if (minor < 2) break; + buf_append_uint8(&st->buffer,st->chosen_dh->capab_bit); } while (0); - dhpub=st->dh->makepublic(st->dh->st,st->dhsecret,st->dh->secret_len); - buf_append_string(&st->buffer,dhpub); - free(dhpub); + pklen_addr=buf_append(&st->buffer,2); + pk=buf_append(&st->buffer,st->chosen_dh->public_len); + pklen=st->chosen_dh->makepublic(st->chosen_dh->st, + pk,st->chosen_dh->public_len, + st->dhsecret,st->chosen_dh->secret_len); + put_uint16(pklen_addr,pklen); + buf_unappend(&st->buffer,st->chosen_dh->public_len-pklen); hash=safe_malloc(st->hash->len, "generate_msg"); hst=st->hash->init(); st->hash->update(hst,st->buffer.start,st->buffer.size); @@ -678,7 +698,7 @@ static bool_t unpick_msg(struct site *st, uint32_t type, { unsigned minor; - m->capab_transformnum=-1; + m->capab_transformnum=m->capab_dhnum=-1; m->hashstart=msg->start; CHECK_AVAIL(msg,4); m->dest=buf_unprepend_uint32(msg); @@ -724,6 +744,7 @@ static bool_t unpick_msg(struct site *st, uint32_t type, } \ } while (0) MAYBE_READ_CAP(1, transform, CAPAB_BIT_ANCIENTTRANSFORM); + MAYBE_READ_CAP(2, dh, CAPAB_BIT_TRADZP); #undef MAYBE_READ_CAP } while (0); CHECK_AVAIL(msg,2); @@ -829,12 +850,17 @@ static bool_t process_msg2(struct site *st, struct buffer_if *msg2, st->setup_session_id=m.source; st->remote_capabilities=m.remote_capabilities; - /* Select the transform to use */ + /* Select the transform and DH group to use */ - uint32_t remote_crypto_caps = st->remote_capabilities & CAPAB_TRANSFORM_MASK; + uint32_t remote_crypto_caps = st->remote_capabilities; + if (!(remote_crypto_caps & CAPAB_EXPLICIT_TRANSFORM_DH)) + remote_crypto_caps &= CAPAB_INEXPLICIT_TRANSFORM_MASK; if (!remote_crypto_caps) /* old secnets only had this one transform */ remote_crypto_caps = 1UL << CAPAB_BIT_ANCIENTTRANSFORM; + if (!(remote_crypto_caps & CAPAB_EXPLICIT_TRANSFORM_DH)) + /* old secnets only had this one kind of group */ + remote_crypto_caps |= 1UL << CAPAB_BIT_TRADZP; #define CHOOSE_CRYPTO(kind, whats) do { \ struct kind##_if *iface; \ @@ -855,6 +881,7 @@ kind##_found: \ } while (0) CHOOSE_CRYPTO(transform, "transforms"); + CHOOSE_CRYPTO(dh, "Diffie--Hellman groups"); #undef CHOOSE_CRYPTO @@ -862,13 +889,29 @@ kind##_found: \ return True; } +static void generate_dhsecret(struct site *st) +{ + slog(st,LOG_SETUP_INIT,"key exchange negotiated DH group" + " %d (capabilities ours=%#"PRIx32" theirs=%#"PRIx32")", + st->chosen_dh->capab_bit, + st->local_capabilities, st->remote_capabilities); + assert(!st->dhsecret); + st->dhsecret = safe_malloc(st->chosen_dh->secret_len, "site:dhsecret"); + st->random->generate(st->random->st, + st->chosen_dh->secret_len,st->dhsecret); +} + static bool_t generate_msg3(struct site *st) { /* Now we have our nonce and their nonce. Think of a secret key, and create message number 3. */ - st->random->generate(st->random->st,st->dh->secret_len,st->dhsecret); + generate_dhsecret(st); return generate_msg(st, - (st->remote_capabilities & CAPAB_TRANSFORM_MASK) + (st->remote_capabilities & + CAPAB_EXPLICIT_TRANSFORM_DH) + ? LABEL_MSG3TER + : (st->remote_capabilities & + CAPAB_INEXPLICIT_TRANSFORM_MASK) ? LABEL_MSG3BIS : LABEL_MSG3, "site:MSG3"); @@ -940,6 +983,7 @@ kind##_found: \ } while (0) CHOSE_CRYPTO(transform, "transform"); + CHOSE_CRYPTO(dh, "Diffie--Hellman group"); #undef CHOSE_CRYPTO @@ -949,10 +993,10 @@ kind##_found: \ /* Terminate their DH public key with a '0' */ m.pk[m.pklen]=0; /* Invent our DH secret key */ - st->random->generate(st->random->st,st->dh->secret_len,st->dhsecret); + generate_dhsecret(st); /* Generate the shared key and set up the transform */ - if (!set_new_transform(st,m.pk)) return False; + if (!set_new_transform(st,m.pk,m.pklen)) return False; return True; } @@ -983,7 +1027,7 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4, m.pk[m.pklen]=0; /* Generate the shared key and set up the transform */ - if (!set_new_transform(st,m.pk)) return False; + if (!set_new_transform(st,m.pk,m.pklen)) return False; return True; } @@ -1510,8 +1554,16 @@ static void enter_state_run(struct site *st) FILLZERO(st->localN); FILLZERO(st->remoteN); dispose_transform(&st->new_transform); - memset(st->dhsecret,0,st->dh->secret_len); - memset(st->sharedsecret,0,st->dh->shared_len); + if (st->dhsecret) { + memset(st->dhsecret, 0, st->chosen_dh->secret_len); + free(st->dhsecret); + st->dhsecret = 0; + } + if (st->sharedsecret) { + memset(st->sharedsecret, 0, st->chosen_dh->shared_len); + free(st->sharedsecret); + st->sharedsecret = 0; + } set_link_quality(st); if (st->keepalive && !current_valid(st)) @@ -2134,7 +2186,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, assert(index_sequence < 0xffffffffUL); st->index = ++index_sequence; - st->local_capabilities = 0; + st->local_capabilities = CAPAB_EXPLICIT_TRANSFORM_DH; st->early_capabilities = CAPAB_PRIORITY_MOBILE; st->netlink=find_cl_if(dict,"link",CL_NETLINK,True,"site",loc); @@ -2178,8 +2230,8 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, st->pubkey=find_cl_if(dict,"key",CL_RSAPUBKEY,True,"site",loc); GET_CLOSURE_LIST("transform",transforms,ntransforms,CL_TRANSFORM); + GET_CLOSURE_LIST("dh",dhs,ndhs,CL_DH); - st->dh=find_cl_if(dict,"dh",CL_DH,True,"site",loc); st->hash=find_cl_if(dict,"hash",CL_HASH,True,"site",loc); #define DEFAULT(D) (st->peer_mobile || st->local_mobile \ @@ -2243,13 +2295,13 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, st->remote_capabilities=0; st->chosen_transform=0; + st->chosen_dh=0; st->current.key_timeout=0; st->auxiliary_key.key_timeout=0; transport_peers_clear(st,&st->peers); transport_peers_clear(st,&st->setup_peers); - /* XXX mlock these */ - st->dhsecret=safe_malloc(st->dh->secret_len,"site:dhsecret"); - st->sharedsecret=safe_malloc(st->dh->shared_len, "site:sharedsecret"); + st->dhsecret=0; + st->sharedsecret=0; #define SET_CAPBIT(bit) do { \ uint32_t capflag = 1UL << (bit); \ @@ -2261,6 +2313,8 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, for (i=0; intransforms; i++) SET_CAPBIT(st->transforms[i]->capab_bit); + for (i=0; indhs; i++) + SET_CAPBIT(st->dhs[i]->capab_bit); #undef SET_CAPBIT