ec-field-test.c: Make the field-element type use internal format.
[secnet] / site.c
diff --git a/site.c b/site.c
index 4f954e6..3971e68 100644 (file)
--- a/site.c
+++ b/site.c
 #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,22 +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 */
     assert(!st->sharedsecret);
-    st->sharedsecret = safe_malloc(st->dh->shared_len, "site:sharedsecret");
-    if (!st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->secret_len,
-                           pk, st->sharedsecret,st->dh->shared_len))
+    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;
@@ -609,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;
@@ -643,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);
@@ -680,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);
@@ -726,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);
@@ -831,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;                                           \
@@ -857,6 +881,7 @@ kind##_found:                                                               \
 } while (0)
 
     CHOOSE_CRYPTO(transform, "transforms");
+    CHOOSE_CRYPTO(dh, "Diffie--Hellman groups");
 
 #undef CHOOSE_CRYPTO
 
@@ -866,9 +891,14 @@ kind##_found:                                                              \
 
 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->dh->secret_len, "site:dhsecret");
-    st->random->generate(st->random->st, st->dh->secret_len,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)
@@ -877,7 +907,11 @@ 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");
@@ -949,6 +983,7 @@ kind##_found:                                                               \
 } while (0)
 
     CHOSE_CRYPTO(transform, "transform");
+    CHOSE_CRYPTO(dh, "Diffie--Hellman group");
 
 #undef CHOSE_CRYPTO
 
@@ -961,7 +996,7 @@ kind##_found:                                                               \
     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;
 }
@@ -992,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;
 }
@@ -1520,12 +1555,12 @@ static void enter_state_run(struct site *st)
     FILLZERO(st->remoteN);
     dispose_transform(&st->new_transform);
     if (st->dhsecret) {
-       memset(st->dhsecret, 0, st->dh->secret_len);
+       memset(st->dhsecret, 0, st->chosen_dh->secret_len);
        free(st->dhsecret);
        st->dhsecret = 0;
     }
     if (st->sharedsecret) {
-       memset(st->sharedsecret, 0, st->dh->shared_len);
+       memset(st->sharedsecret, 0, st->chosen_dh->shared_len);
        free(st->sharedsecret);
        st->sharedsecret = 0;
     }
@@ -2151,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);
 
@@ -2195,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        \
@@ -2260,6 +2295,7 @@ 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);
@@ -2277,6 +2313,8 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
 
     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