X-Git-Url: https://git.distorted.org.uk/~mdw/secnet/blobdiff_plain/3f488f14527df0f3da6616bcc26c2cf69f627df9..refs/heads/mdw/xdh:/site.c diff --git a/site.c b/site.c index 0b2e2d0..3971e68 100644 --- a/site.c +++ b/site.c @@ -107,6 +107,8 @@ #define SITE_SENTMSG5 7 #define SITE_WAIT 8 +#define CASES_MSG3_KNOWN LABEL_MSG3: case LABEL_MSG3BIS: case LABEL_MSG3TER + int32_t site_max_start_pad = 4*4; static cstring_t state_name(uint32_t state) @@ -314,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 */ @@ -359,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 */ @@ -505,10 +509,10 @@ static void dispose_transform(struct transform_inst_if **transform_var) static _Bool type_is_msg34(uint32_t type) { - return - type == LABEL_MSG3 || - type == LABEL_MSG3BIS || - type == LABEL_MSG4; + switch (type) { + case CASES_MSG3_KNOWN: case LABEL_MSG4: return True; + default: return False; + } } struct parsedname { @@ -526,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; @@ -545,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; @@ -605,7 +618,11 @@ 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; BUF_ALLOC(&st->buffer,what); @@ -634,12 +651,21 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what) if (hacky_par_mid_failnow()) return False; - if (type==LABEL_MSG3BIS) + if (MSGMAJOR(type) == 3) do { + minor = MSGMINOR(type); + if (minor < 1) break; buf_append_uint8(&st->buffer,st->chosen_transform->capab_bit); - - dhpub=st->dh->makepublic(st->dh->st,st->dhsecret,st->dh->secret_len); - buf_append_string(&st->buffer,dhpub); - free(dhpub); + if (minor < 2) break; + buf_append_uint8(&st->buffer,st->chosen_dh->capab_bit); + } while (0); + + 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); @@ -670,7 +696,9 @@ static bool_t unpick_name(struct buffer_if *msg, struct parsedname *nm) static bool_t unpick_msg(struct site *st, uint32_t type, struct buffer_if *msg, struct msg *m) { - m->capab_transformnum=-1; + unsigned minor; + + m->capab_transformnum=m->capab_dhnum=-1; m->hashstart=msg->start; CHECK_AVAIL(msg,4); m->dest=buf_unprepend_uint32(msg); @@ -705,12 +733,20 @@ static bool_t unpick_msg(struct site *st, uint32_t type, CHECK_EMPTY(msg); return True; } - if (type==LABEL_MSG3BIS) { - CHECK_AVAIL(msg,1); - m->capab_transformnum = buf_unprepend_uint8(msg); - } else { - m->capab_transformnum = CAPAB_BIT_ANCIENTTRANSFORM; - } + if (MSGMAJOR(type) == 3) do { + minor = MSGMINOR(type); +#define MAYBE_READ_CAP(minminor, kind, dflt) do { \ + if (minor < (minminor)) \ + m->capab_##kind##num = (dflt); \ + else { \ + CHECK_AVAIL(msg, 1); \ + m->capab_##kind##num = buf_unprepend_uint8(msg); \ + } \ +} 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); m->pklen=buf_unprepend_uint16(msg); CHECK_AVAIL(msg,m->pklen); @@ -765,7 +801,7 @@ static bool_t check_msg(struct site *st, uint32_t type, struct msg *m, } /* MSG3 has complicated rules about capabilities, which are * handled in process_msg3. */ - if (type==LABEL_MSG3 || type==LABEL_MSG3BIS) return True; + if (MSGMAJOR(type) == 3) return True; if (m->remote_capabilities!=st->remote_capabilities) { *error="remote capabilities changed"; return False; @@ -814,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; \ @@ -840,6 +881,7 @@ kind##_found: \ } while (0) CHOOSE_CRYPTO(transform, "transforms"); + CHOOSE_CRYPTO(dh, "Diffie--Hellman groups"); #undef CHOOSE_CRYPTO @@ -847,14 +889,31 @@ 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 - ? LABEL_MSG3BIS : LABEL_MSG3), + (st->remote_capabilities & + CAPAB_EXPLICIT_TRANSFORM_DH) + ? LABEL_MSG3TER + : (st->remote_capabilities & + CAPAB_INEXPLICIT_TRANSFORM_MASK) + ? LABEL_MSG3BIS + : LABEL_MSG3, "site:MSG3"); } @@ -888,7 +947,10 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3, struct msg m; cstring_t err; - assert(msgtype==LABEL_MSG3 || msgtype==LABEL_MSG3BIS); + switch (msgtype) { + case CASES_MSG3_KNOWN: break; + default: assert(0); + } if (!unpick_msg(st,msgtype,msg3,&m)) return False; if (!check_msg(st,msgtype,&m,&err)) { @@ -921,6 +983,7 @@ kind##_found: \ } while (0) CHOSE_CRYPTO(transform, "transform"); + CHOSE_CRYPTO(dh, "Diffie--Hellman group"); #undef CHOSE_CRYPTO @@ -930,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; } @@ -964,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; } @@ -1491,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)) @@ -1946,8 +2017,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf, slog(st,LOG_SEC,"invalid MSG2"); } break; - case LABEL_MSG3: - case LABEL_MSG3BIS: + case CASES_MSG3_KNOWN: /* Setup packet: expected only in state SENTMSG2 */ if (st->state!=SITE_SENTMSG2) { if ((st->state==SITE_SENTMSG4) && @@ -2116,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); @@ -2160,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 \ @@ -2225,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); \ @@ -2243,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