chiark / gitweb /
site: support multiple transforms
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 25 Jul 2013 17:30:53 +0000 (18:30 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 25 Jul 2013 17:30:53 +0000 (18:30 +0100)
The "transform" key in site's dictionary argument can now be a list,
as well as just a single transform.

We use 16 bits of the capability mechanism to advertise the transforms
we support; the config is supposed to nominate a transform capability
number (from 0 to 15) for each transform closure - although the
default numbers are sufficient if you don't need to do parameter
rollover.

The receiver of MSG2 intersects the two bitmaps and chooses the best
transform, and states its choice in MSG3.

A protocol downgrade attack is prevented by the fact that the
capability bitmaps are advertised in the signed parts of MSG3 and
MSG4.  (If the one in MSG4 doesn't match what was in MSG2, the MSG4 is
rejected and presumably the key exchange fails.)

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
NOTES
example.conf
magic.h
secnet.8
secnet.h
site.c
test-example/common.conf
transform-cbcmac.c
transform-common.h
transform-eax.c

diff --git a/NOTES b/NOTES
index 8619ee5d9911c420b248277a360cd731fcb923aa..7ead923be70060d708e287b24d63a7dc2093e39a 100644 (file)
--- a/NOTES
+++ b/NOTES
@@ -232,7 +232,7 @@ zero as its "index" for another site.)
 (The order of B and A reverses in alternate messages so that the same
 code can be used to construct them...)
 
 (The order of B and A reverses in alternate messages so that the same
 code can be used to construct them...)
 
-3) A->B: {iB,iA,msg3,A+,B+,nA,nB,g^x mod m}_PK_A^-1
+3) A->B: {iB,iA,msg3,A+,B+,[chosen-transform],nA,nB,g^x mod m}_PK_A^-1
 
 If message 1 was a replay then A will not generate message 3, because
 it doesn't recognise nA.
 
 If message 1 was a replay then A will not generate message 3, because
 it doesn't recognise nA.
index d6908ff7c820c0b13b0c9e798d0e1c72b7b13f93..ab40d05e95a92208a2c7dd409f4e9fe9ac64e7f0 100644 (file)
@@ -148,9 +148,7 @@ local-name "your-site-name";
 local-key rsa-private("/etc/secnet/key");
 
 # On dodgy links you may want to specify a higher maximum sequence number skew
 local-key rsa-private("/etc/secnet/key");
 
 # On dodgy links you may want to specify a higher maximum sequence number skew
-transform serpent256-cbc {
-       max-sequence-skew 10;
-};
+transform eax-serpent, serpent256-cbc;
 
 include /etc/secnet/sites.conf
 
 
 include /etc/secnet/sites.conf
 
diff --git a/magic.h b/magic.h
index 3ae7af4d6dc729addfbcfac8af021ae4e24a01c0..e98f681df88f7d61005922372dbfb91f6da71ab6 100644 (file)
--- a/magic.h
+++ b/magic.h
@@ -3,20 +3,46 @@
 #ifndef magic_h
 #define magic_h
 
 #ifndef magic_h
 #define magic_h
 
-#define LABEL_NAK  0x00000000
-#define LABEL_MSG0 0x00020200
-#define LABEL_MSG1 0x01010101
-#define LABEL_MSG2 0x02020202
-#define LABEL_MSG3 0x03030303
-#define LABEL_MSG4 0x04040404
-#define LABEL_MSG5 0x05050505
-#define LABEL_MSG6 0x06060606
-#define LABEL_MSG7 0x07070707
-#define LABEL_MSG8 0x08080808
-#define LABEL_MSG9 0x09090909
+#define LABEL_NAK     0x00000000
+#define LABEL_MSG0    0x00020200
+#define LABEL_MSG1    0x01010101
+#define LABEL_MSG2    0x02020202
+#define LABEL_MSG3    0x03030303
+#define LABEL_MSG3BIS 0x13030313
+#define LABEL_MSG4    0x04040404
+#define LABEL_MSG5    0x05050505
+#define LABEL_MSG6    0x06060606
+#define LABEL_MSG7    0x07070707
+#define LABEL_MSG8    0x08080808
+#define LABEL_MSG9    0x09090909
 
 /* uses of the 32-bit capability bitmap */
 
 /* uses of the 32-bit capability bitmap */
-/* no flags currently defined */
-#define CAPAB_EARLY 0x00000000 /* no Early flags defined (see NOTES) */
+#define CAPAB_EARLY           0x00000000 /* no Early flags yet (see NOTES) */
+#define CAPAB_TRANSFORM_MASK  0x0000ffff
+/* remaining 16 bits are unused */
+
+/*
+ * The transform capability mask is a set of bits, one for each
+ * transform supported.  The transform capability numbers are set in
+ * the configuration (and should correspond between the two sites),
+ * although there are sensible defaults.
+ *
+ * Advertising a nonzero transform capability mask promises that
+ * the receiver understands LABEL_MSG3BIS messages, which
+ * contain an additional byte specifying the transform capability
+ * number actually chosen by the MSG3 sender.
+ *
+ * Aside from that, an empty bitmask is treated the same as
+ *  1u<<CAPAB_TRANSFORMNUM_ANCIENT
+ */
+
+/* bit indices, 0 is ls bit */
+#define CAPAB_TRANSFORMNUM_USER_MIN              0
+#define CAPAB_TRANSFORMNUM_USER_MAX              7
+#define CAPAB_TRANSFORMNUM_SERPENT256CBC         8
+#define CAPAB_TRANSFORMNUM_EAXSERPENT            9
+#define CAPAB_TRANSFORMNUM_MAX                  15
+
+#define CAPAB_TRANSFORMNUM_ANCIENT CAPAB_TRANSFORMNUM_SERPENT256CBC
 
 #endif /* magic_h */
 
 #endif /* magic_h */
index 2bf225043ace5f0ef91197489b1e148cc8d1be93..48cfaba2ff3c871babf36b59f20160d6cff4c0ce 100644 (file)
--- a/secnet.8
+++ b/secnet.8
@@ -434,6 +434,17 @@ blocksize, 16.  Must be have the same value at both ends.
 .B padding-rounding
 Messages are padded to a multiple of this many bytes.  This
 serves to obscure the exact length of messages.  The default is 16,
 .B padding-rounding
 Messages are padded to a multiple of this many bytes.  This
 serves to obscure the exact length of messages.  The default is 16,
+.TP
+.B capab-num
+The transform capability number to use when advertising this
+transform.  Both ends must have the same meaning (or, at least, a
+compatible transform) for each transform capability number they have
+in common.  The default for serpent-eax is 9.
+.IP
+Transform capability numbers in the range 8..15 are intended for
+allocation by the implementation, and may be assigned as the default
+for new transforms in the future.  Transform capability numbers in the
+range 0..7 are reserved for definition by the user.
 .PP
 A \fItransform closure\fR is a reversible means of transforming
 messages for transmission over a (presumably) insecure network.
 .PP
 A \fItransform closure\fR is a reversible means of transforming
 messages for transmission over a (presumably) insecure network.
@@ -442,8 +453,15 @@ It is responsible for both confidentiality and integrity.
 .SS serpent256-cbc
 \fBserpent256-cbc(\fIDICT\fB)\fR => \fItransform closure\fR
 .PP
 .SS serpent256-cbc
 \fBserpent256-cbc(\fIDICT\fB)\fR => \fItransform closure\fR
 .PP
+This transform
+is deprecated as its security properties are poor; it should be
+specified only alongside a better transform such as eax-serpent.
+.PP
 Valid keys in the \fIDICT\fR argument are:
 .TP
 Valid keys in the \fIDICT\fR argument are:
 .TP
+.B capab-num
+As above.  The default for serpent256-cbc is 8.
+.TP
 .B max-sequence-skew
 As above.
 .PP
 .B max-sequence-skew
 As above.
 .PP
@@ -520,8 +538,13 @@ An \fIrsapubkey closure\fR.
 The key used to verify the peer's identity.
 .TP
 .B transform
 The key used to verify the peer's identity.
 .TP
 .B transform
-A \fItransform closure\fR.
-Used to protect packets exchanged with the peer.
+One or more \fItransform closures\fR.
+Used to protect packets exchanged with the peer.  These should
+all have distinct \fBcapab-num\fR values, and the same \fBcapab-num\fR
+value should refer to the same (or a compatible) transform at both
+ends.  The list should be in order of preference, most preferred
+first.  (The end which sends MSG1,MSG3 ends up choosing; the ordering
+at the other end is irrelevant.)
 .TP
 .B dh
 A \fIdh closure\fR.
 .TP
 .B dh
 A \fIdh closure\fR.
index 2ccf161989507e43fbf1e326ca69a5c04b0ed55b..252eeb659b7f01fda5a8ba0b61e1788471195249 100644 (file)
--- a/secnet.h
+++ b/secnet.h
@@ -403,6 +403,7 @@ struct transform_if {
     void *st;
     int32_t max_start_pad; /* these two are both <<< INT_MAX */
     int32_t keylen; /* 0 means give the transform exactly as much as there is */
     void *st;
     int32_t max_start_pad; /* these two are both <<< INT_MAX */
     int32_t keylen; /* 0 means give the transform exactly as much as there is */
+    int capab_transformnum;
     transform_createinstance_fn *create;
 };
 
     transform_createinstance_fn *create;
 };
 
diff --git a/site.c b/site.c
index 2ada372edfadc88e1d354ddcb92e34926f5bdb8b..6c92193e58193e87934e74e8325215d7117974ae 100644 (file)
--- a/site.c
+++ b/site.c
@@ -239,7 +239,8 @@ struct site {
     struct random_if *random;
     struct rsaprivkey_if *privkey;
     struct rsapubkey_if *pubkey;
     struct random_if *random;
     struct rsaprivkey_if *privkey;
     struct rsapubkey_if *pubkey;
-    struct transform_if *transform;
+    struct transform_if **transforms;
+    int ntransforms;
     struct dh_if *dh;
     struct hash_if *hash;
 
     struct dh_if *dh;
     struct hash_if *hash;
 
@@ -277,6 +278,7 @@ struct site {
        timeout before we can listen for another setup packet); perhaps
        we should keep a list of 'bad' sources for setup packets. */
     uint32_t remote_capabilities;
        timeout before we can listen for another setup packet); perhaps
        we should keep a list of 'bad' sources for setup packets. */
     uint32_t remote_capabilities;
+    struct transform_if *chosen_transform;
     uint32_t setup_session_id;
     transport_peers setup_peers;
     uint8_t localN[NONCELEN]; /* Nonces for key exchange */
     uint32_t setup_session_id;
     transport_peers setup_peers;
     uint8_t localN[NONCELEN]; /* Nonces for key exchange */
@@ -287,7 +289,7 @@ struct site {
     uint64_t timeout; /* Timeout for current state */
     uint8_t *dhsecret;
     uint8_t *sharedsecret;
     uint64_t timeout; /* Timeout for current state */
     uint8_t *dhsecret;
     uint8_t *sharedsecret;
-    uint32_t sharedsecretlen;
+    uint32_t sharedsecretlen, sharedsecretallocd;
     struct transform_inst_if *new_transform; /* For key setup/verify */
 };
 
     struct transform_inst_if *new_transform; /* For key setup/verify */
 };
 
@@ -390,6 +392,7 @@ struct msg {
     struct parsedname remote;
     struct parsedname local;
     uint32_t remote_capabilities;
     struct parsedname remote;
     struct parsedname local;
     uint32_t remote_capabilities;
+    int capab_transformnum;
     uint8_t *nR;
     uint8_t *nL;
     int32_t pklen;
     uint8_t *nR;
     uint8_t *nL;
     int32_t pklen;
@@ -399,14 +402,33 @@ struct msg {
     char *sig;
 };
 
     char *sig;
 };
 
-static void set_new_transform(struct site *st)
+static void set_new_transform(struct site *st, char *pk)
 {
 {
-    struct transform_if *generator=st->transform;
+    /* Make room for the shared key */
+    st->sharedsecretlen=st->chosen_transform->keylen?:st->dh->ceil_len;
+    assert(st->sharedsecretlen);
+    if (st->sharedsecretlen > st->sharedsecretallocd) {
+       st->sharedsecretallocd=st->sharedsecretlen;
+       st->sharedsecret=realloc(st->sharedsecret,st->sharedsecretallocd);
+    }
+    if (!st->sharedsecret) fatal_perror("site:sharedsecret");
+
+    /* Generate the shared key */
+    st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,pk,
+                      st->sharedsecret,st->sharedsecretlen);
+
+    /* Set up the transform */
+    struct transform_if *generator=st->chosen_transform;
     struct transform_inst_if *generated=generator->create(generator->st);
     generated->setkey(generated->st,st->sharedsecret,
                      st->sharedsecretlen,st->setup_priority);
     dispose_transform(&st->new_transform);
     st->new_transform=generated;
     struct transform_inst_if *generated=generator->create(generator->st);
     generated->setkey(generated->st,st->sharedsecret,
                      st->sharedsecretlen,st->setup_priority);
     dispose_transform(&st->new_transform);
     st->new_transform=generated;
+
+    slog(st,LOG_SETUP_INIT,"key exchange negotiated transform"
+        " %d (capabilities ours=%#"PRIx32" theirs=%#"PRIx32")",
+        st->chosen_transform->capab_transformnum,
+        st->local_capabilities, st->remote_capabilities);
 }
 
 struct xinfoadd {
 }
 
 struct xinfoadd {
@@ -468,6 +490,9 @@ static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what)
 
     if (hacky_par_mid_failnow()) return False;
 
 
     if (hacky_par_mid_failnow()) return False;
 
+    if (type==LABEL_MSG3BIS)
+       buf_append_uint8(&st->buffer,st->chosen_transform->capab_transformnum);
+
     dhpub=st->dh->makepublic(st->dh->st,st->dhsecret,st->dh->len);
     buf_append_string(&st->buffer,dhpub);
     free(dhpub);
     dhpub=st->dh->makepublic(st->dh->st,st->dhsecret,st->dh->len);
     buf_append_string(&st->buffer,dhpub);
     free(dhpub);
@@ -501,6 +526,7 @@ 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)
 {
 static bool_t unpick_msg(struct site *st, uint32_t type,
                         struct buffer_if *msg, struct msg *m)
 {
+    m->capab_transformnum=-1;
     m->hashstart=msg->start;
     CHECK_AVAIL(msg,4);
     m->dest=buf_unprepend_uint32(msg);
     m->hashstart=msg->start;
     CHECK_AVAIL(msg,4);
     m->dest=buf_unprepend_uint32(msg);
@@ -526,6 +552,12 @@ static bool_t unpick_msg(struct site *st, uint32_t type,
        CHECK_EMPTY(msg);
        return True;
     }
        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_TRANSFORMNUM_ANCIENT;
+    }
     CHECK_AVAIL(msg,2);
     m->pklen=buf_unprepend_uint16(msg);
     CHECK_AVAIL(msg,m->pklen);
     CHECK_AVAIL(msg,2);
     m->pklen=buf_unprepend_uint16(msg);
     CHECK_AVAIL(msg,m->pklen);
@@ -573,7 +605,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. */
     }
     /* MSG3 has complicated rules about capabilities, which are
      * handled in process_msg3. */
-    if (type==LABEL_MSG3) return True;
+    if (type==LABEL_MSG3 || type==LABEL_MSG3BIS) return True;
     if (m->remote_capabilities!=st->remote_capabilities) {
        *error="remote capabilities changed";
        return False;
     if (m->remote_capabilities!=st->remote_capabilities) {
        *error="remote capabilities changed";
        return False;
@@ -622,6 +654,29 @@ static bool_t process_msg2(struct site *st, struct buffer_if *msg2,
     }
     st->setup_session_id=m.source;
     st->remote_capabilities=m.remote_capabilities;
     }
     st->setup_session_id=m.source;
     st->remote_capabilities=m.remote_capabilities;
+
+    /* Select the transform to use */
+
+    uint32_t remote_transforms = st->remote_capabilities & CAPAB_TRANSFORM_MASK;
+    if (!remote_transforms)
+       /* old secnets only had this one transform */
+       remote_transforms = 1UL << CAPAB_TRANSFORMNUM_ANCIENT;
+
+    struct transform_if *ti;
+    int i;
+    for (i=0; i<st->ntransforms; i++) {
+       ti=st->transforms[i];
+       if ((1UL << ti->capab_transformnum) & remote_transforms)
+           goto transform_found;
+    }
+    slog(st,LOG_ERROR,"no transforms in common"
+        " (us %#"PRIx32"; them: %#"PRIx32")",
+        st->local_capabilities & CAPAB_TRANSFORM_MASK,
+        remote_transforms);
+    return False;
+ transform_found:
+    st->chosen_transform=ti;
+
     memcpy(st->remoteN,m.nR,NONCELEN);
     return True;
 }
     memcpy(st->remoteN,m.nR,NONCELEN);
     return True;
 }
@@ -631,19 +686,24 @@ 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->len,st->dhsecret);
     /* 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->len,st->dhsecret);
-    return generate_msg(st,LABEL_MSG3,"site:MSG3");
+    return generate_msg(st,
+                       (st->remote_capabilities & CAPAB_TRANSFORM_MASK
+                        ? LABEL_MSG3BIS : LABEL_MSG3),
+                       "site:MSG3");
 }
 
 static bool_t process_msg3(struct site *st, struct buffer_if *msg3,
 }
 
 static bool_t process_msg3(struct site *st, struct buffer_if *msg3,
-                          const struct comm_addr *src)
+                          const struct comm_addr *src, uint32_t msgtype)
 {
     struct msg m;
     uint8_t *hash;
     void *hst;
     cstring_t err;
 
 {
     struct msg m;
     uint8_t *hash;
     void *hst;
     cstring_t err;
 
-    if (!unpick_msg(st,LABEL_MSG3,msg3,&m)) return False;
-    if (!check_msg(st,LABEL_MSG3,&m,&err)) {
+    assert(msgtype==LABEL_MSG3 || msgtype==LABEL_MSG3BIS);
+
+    if (!unpick_msg(st,msgtype,msg3,&m)) return False;
+    if (!check_msg(st,msgtype,&m,&err)) {
        slog(st,LOG_SEC,"msg3: %s",err);
        return False;
     }
        slog(st,LOG_SEC,"msg3: %s",err);
        return False;
     }
@@ -657,6 +717,19 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3,
     }
     st->remote_capabilities|=m.remote_capabilities;
 
     }
     st->remote_capabilities|=m.remote_capabilities;
 
+    struct transform_if *ti;
+    int i;
+    for (i=0; i<st->ntransforms; i++) {
+       ti=st->transforms[i];
+       if (ti->capab_transformnum == m.capab_transformnum)
+           goto transform_found;
+    }
+    slog(st,LOG_SEC,"peer chose unknown-to-us transform %d!",
+        m.capab_transformnum);
+    return False;
+ transform_found:
+    st->chosen_transform=ti;
+
     /* Check signature and store g^x mod m */
     hash=safe_malloc(st->hash->len, "process_msg3");
     hst=st->hash->init();
     /* Check signature and store g^x mod m */
     hash=safe_malloc(st->hash->len, "process_msg3");
     hst=st->hash->init();
@@ -676,12 +749,8 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3,
     /* Invent our DH secret key */
     st->random->generate(st->random->st,st->dh->len,st->dhsecret);
 
     /* Invent our DH secret key */
     st->random->generate(st->random->st,st->dh->len,st->dhsecret);
 
-    /* Generate the shared key */
-    st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,m.pk,
-                      st->sharedsecret,st->sharedsecretlen);
-
-    /* Set up the transform */
-    set_new_transform(st);
+    /* Generate the shared key and set up the transform */
+    set_new_transform(st,m.pk);
 
     return True;
 }
 
     return True;
 }
@@ -723,11 +792,9 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4,
 
     /* Terminate their DH public key with a '0' */
     m.pk[m.pklen]=0;
 
     /* Terminate their DH public key with a '0' */
     m.pk[m.pklen]=0;
-    /* Generate the shared key */
-    st->dh->makeshared(st->dh->st,st->dhsecret,st->dh->len,m.pk,
-                      st->sharedsecret,st->sharedsecretlen);
-    /* Set up the transform */
-    set_new_transform(st);
+
+    /* Generate the shared key and set up the transform */
+    set_new_transform(st,m.pk);
 
     return True;
 }
 
     return True;
 }
@@ -1454,10 +1521,11 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
            }
            break;
        case LABEL_MSG3:
            }
            break;
        case LABEL_MSG3:
+       case LABEL_MSG3BIS:
            /* Setup packet: expected only in state SENTMSG2 */
            if (st->state!=SITE_SENTMSG2) {
                slog(st,LOG_UNEXPECTED,"unexpected MSG3");
            /* Setup packet: expected only in state SENTMSG2 */
            if (st->state!=SITE_SENTMSG2) {
                slog(st,LOG_UNEXPECTED,"unexpected MSG3");
-           } else if (process_msg3(st,buf,source)) {
+           } else if (process_msg3(st,buf,source,msgtype)) {
                transport_setup_msgok(st,source);
                enter_new_state(st,SITE_SENTMSG4);
            } else {
                transport_setup_msgok(st,source);
                enter_new_state(st,SITE_SENTMSG4);
            } else {
@@ -1600,19 +1668,25 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
     st->local_capabilities = 0;
     st->netlink=find_cl_if(dict,"link",CL_NETLINK,True,"site",loc);
 
     st->local_capabilities = 0;
     st->netlink=find_cl_if(dict,"link",CL_NETLINK,True,"site",loc);
 
-    list_t *comms_cfg=dict_lookup(dict,"comm");
-    if (!comms_cfg) cfgfatal(loc,"site","closure list \"comm\" not found\n");
-    st->ncomms=list_length(comms_cfg);
-    st->comms=safe_malloc_ary(sizeof(*st->comms),st->ncomms,"comms");
-    assert(st->ncomms);
-    for (i=0; i<st->ncomms; i++) {
-       item_t *item=list_elem(comms_cfg,i);
-       if (item->type!=t_closure)
-           cfgfatal(loc,"site","comm is not a closure\n");
-       closure_t *cl=item->data.closure;
-       if (cl->type!=CL_COMM) cfgfatal(loc,"site","comm closure wrong type\n");
-       st->comms[i]=cl->interface;
-    }
+#define GET_CLOSURE_LIST(dictkey,things,nthings,CL_TYPE) do{           \
+    list_t *things##_cfg=dict_lookup(dict,dictkey);                    \
+    if (!things##_cfg)                                                 \
+       cfgfatal(loc,"site","closure list \"%s\" not found\n",dictkey); \
+    st->nthings=list_length(things##_cfg);                             \
+    st->things=safe_malloc_ary(sizeof(*st->things),st->nthings,dictkey "s"); \
+    assert(st->nthings);                                               \
+    for (i=0; i<st->nthings; i++) {                                    \
+       item_t *item=list_elem(things##_cfg,i);                         \
+       if (item->type!=t_closure)                                      \
+           cfgfatal(loc,"site","%s is not a closure\n",dictkey);       \
+       closure_t *cl=item->data.closure;                               \
+       if (cl->type!=CL_TYPE)                                          \
+           cfgfatal(loc,"site","%s closure wrong type\n",dictkey);     \
+       st->things[i]=cl->interface;                                    \
+    }                                                                  \
+}while(0)
+
+    GET_CLOSURE_LIST("comm",comms,ncomms,CL_COMM);
 
     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->resolver=find_cl_if(dict,"resolver",CL_RESOLVER,True,"site",loc);
     st->log=find_cl_if(dict,"log",CL_LOG,True,"site",loc);
@@ -1625,8 +1699,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
     else st->remoteport=0;
     st->pubkey=find_cl_if(dict,"key",CL_RSAPUBKEY,True,"site",loc);
 
     else st->remoteport=0;
     st->pubkey=find_cl_if(dict,"key",CL_RSAPUBKEY,True,"site",loc);
 
-    st->transform=
-       find_cl_if(dict,"transform",CL_TRANSFORM,True,"site",loc);
+    GET_CLOSURE_LIST("transform",transforms,ntransforms,CL_TRANSFORM);
 
     st->dh=find_cl_if(dict,"dh",CL_DH,True,"site",loc);
     st->hash=find_cl_if(dict,"hash",CL_HASH,True,"site",loc);
 
     st->dh=find_cl_if(dict,"dh",CL_DH,True,"site",loc);
     st->hash=find_cl_if(dict,"hash",CL_HASH,True,"site",loc);
@@ -1685,29 +1758,40 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
     st->timeout=0;
 
     st->remote_capabilities=0;
     st->timeout=0;
 
     st->remote_capabilities=0;
+    st->chosen_transform=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->len,"site:dhsecret");
     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->len,"site:dhsecret");
-    st->sharedsecretlen=st->transform->keylen?:st->dh->ceil_len;
-    st->sharedsecret=safe_malloc(st->sharedsecretlen,"site:sharedsecret");
-
-    /* We need to compute some properties of our comms */
-#define COMPUTE_WORST(pad)                     \
-    int worst_##pad=0;                         \
-    for (i=0; i<st->ncomms; i++) {             \
-       int thispad=st->comms[i]->pad;          \
-       if (thispad > worst_##pad)              \
-           worst_##pad=thispad;                \
+    st->sharedsecretlen=st->sharedsecretallocd=0;
+    st->sharedsecret=0;
+
+    /* We need to compute some properties of our comms and transports */
+#define COMPUTE_WORST(things,pad)              \
+    int things##_worst_##pad=0;                        \
+    for (i=0; i<st->n##things; i++) {          \
+       int thispad=st->things[i]->pad;         \
+       if (thispad > things##_worst_##pad)     \
+           things##_worst_##pad=thispad;       \
+    }
+    COMPUTE_WORST(comms,min_start_pad)
+    COMPUTE_WORST(transforms,max_start_pad)
+
+    for (i=0; i<st->ntransforms; i++) {
+       struct transform_if *ti=st->transforms[i];
+       uint32_t capbit = 1UL << ti->capab_transformnum;
+       if (st->local_capabilities & capbit)
+           slog(st,LOG_ERROR,"transformnum capability bit"
+                " %d (%#"PRIx32") reused", ti->capab_transformnum, capbit);
+       st->local_capabilities |= capbit;
     }
     }
-    COMPUTE_WORST(min_start_pad)
 
     /* We need to register the remote networks with the netlink device */
     st->netlink->reg(st->netlink->st, site_outgoing, st,
 
     /* We need to register the remote networks with the netlink device */
     st->netlink->reg(st->netlink->st, site_outgoing, st,
-                    st->transform->max_start_pad+(4*4)+
-                    worst_min_start_pad);
+                    transforms_worst_max_start_pad+(4*4)+
+                    comms_worst_min_start_pad);
     
     for (i=0; i<st->ncomms; i++)
        st->comms[i]->request_notify(st->comms[i]->st, st, site_incoming);
     
     for (i=0; i<st->ncomms; i++)
        st->comms[i]->request_notify(st->comms[i]->st, st, site_incoming);
index 64bfc819436c1c1cd9bd67ad476ad28f60b12f65..b849052b78064662433b5feddb0401873c204470 100644 (file)
@@ -8,8 +8,6 @@ resolver adns {
 };
 log-events "all";
 random randomfile("/dev/urandom",no);
 };
 log-events "all";
 random randomfile("/dev/urandom",no);
-transform serpent256-cbc {
-        max-sequence-skew 10;
-};
+transform eax-serpent { }, serpent256-cbc { };
 include test-example/sites.conf
 sites map(site,vpn/test-example/all-sites);
 include test-example/sites.conf
 sites map(site,vpn/test-example/all-sites);
index 69201654da6f9e7c6e80f297f2b92e501f038c15..95c64e859a7abfbaba2839df15e3d7da92fac48b 100644 (file)
@@ -278,6 +278,8 @@ static list_t *transform_apply(closure_t *self, struct cloc loc,
     st->max_seq_skew=dict_read_number(dict, "max-sequence-skew",
                                      False, "serpent-cbc256", loc, 10);
 
     st->max_seq_skew=dict_read_number(dict, "max-sequence-skew",
                                      False, "serpent-cbc256", loc, 10);
 
+    SET_CAPAB_TRANSFORMNUM(CAPAB_TRANSFORMNUM_SERPENT256CBC);
+
     return new_closure(&st->cl);
 }
 
     return new_closure(&st->cl);
 }
 
index de198176cdd81ef15e0c01cbb5a446969771341a..52f606777e53d554cd509651ab0febbffef781de 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef TRANSFORM_COMMON_H
 #define TRANSFORM_COMMON_H
 
 #ifndef TRANSFORM_COMMON_H
 #define TRANSFORM_COMMON_H
 
+#include "magic.h"
+
 #define KEYED_CHECK do{                                \
        if (!ti->keyed) {                       \
            *errmsg="transform unkeyed";        \
 #define KEYED_CHECK do{                                \
        if (!ti->keyed) {                       \
            *errmsg="transform unkeyed";        \
        free(st);                                       \
     }
 
        free(st);                                       \
     }
 
+#define SET_CAPAB_TRANSFORMNUM(def) do{                                        \
+        st->ops.capab_transformnum=dict_read_number(dict, "capab-num", \
+                                     False, "transform", loc, def);    \
+        if (st->ops.capab_transformnum > CAPAB_TRANSFORMNUM_MAX)       \
+           cfgfatal(loc,"transform","capab-num out of range 0..%d\n",  \
+                    CAPAB_TRANSFORMNUM_MAX);                           \
+    }while(0)
+
 #define TRANSFORM_CREATE_CORE                          \
        struct transform_inst *ti;                      \
        ti=safe_malloc(sizeof(*ti),"transform_create"); \
 #define TRANSFORM_CREATE_CORE                          \
        struct transform_inst *ti;                      \
        ti=safe_malloc(sizeof(*ti),"transform_create"); \
index 89c46c87b17cf0d78655ea550cc4223f820dc70c..31d81714de8a71d69177335a6b6b48151301171d 100644 (file)
@@ -273,6 +273,8 @@ static list_t *transform_apply(closure_t *self, struct cloc loc,
        cfgfatal(loc,"eax-serpent","parameter must be a dictionary\n");
     dict=item->data.dict;
 
        cfgfatal(loc,"eax-serpent","parameter must be a dictionary\n");
     dict=item->data.dict;
 
+    SET_CAPAB_TRANSFORMNUM(CAPAB_TRANSFORMNUM_EAXSERPENT);
+
     st->p.max_seq_skew=dict_read_number(dict, "max-sequence-skew",
                                        False, "eax-serpent", loc, 10);
 
     st->p.max_seq_skew=dict_read_number(dict, "max-sequence-skew",
                                        False, "eax-serpent", loc, 10);