#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;
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 */
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 */
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;
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;
{
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;
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);
{
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);
} \
} 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);
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; \
} while (0)
CHOOSE_CRYPTO(transform, "transforms");
+ CHOOSE_CRYPTO(dh, "Diffie--Hellman groups");
#undef CHOOSE_CRYPTO
static void generate_dhsecret(struct site *st)
{
- st->random->generate(st->random->st, st->dh->secret_len,st->dhsecret);
+ 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)
and create message number 3. */
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");
} while (0)
CHOSE_CRYPTO(transform, "transform");
+ CHOSE_CRYPTO(dh, "Diffie--Hellman group");
#undef CHOSE_CRYPTO
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;
}
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;
}
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))
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);
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 \
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); \
for (i=0; i<st->ntransforms; i++)
SET_CAPBIT(st->transforms[i]->capab_bit);
+ for (i=0; i<st->ndhs; i++)
+ SET_CAPBIT(st->dhs[i]->capab_bit);
#undef SET_CAPBIT