summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
088f80a)
For the most part, this slots into the space previously prepared for
it. However, there are a few subtleties.
The most significant one is that existing Secnets don't pay attention to
the high 16 cap bits. To bring them into availability, we introduce a
signalling system. If bit 15 is set, then
* all of the bits are scanned for capabilities, and
* it is expected that sender has advertised its DH groups explicitly.
If the bit is clear, then we have the old situation:
* firstly, only the low 16 bits are scanned for transform cap bits,
and
* secondly, it is assumed that the sender only implements traditional
integer Diffie--Hellman, cap 10, with some appropriately determined
group.
We also set the explicit bit if one of the high capability bits is set.
As part of this, add a parameter to the `diffie-hellman' closure to
configure its advertised group cap.
Signed-off-by: Mark Wooding <mdw@distorted.org.uk>
applicable. They may also appear in MSG1, but this is not
guaranteed. MSG4 must advertise the same set as MSG2.
applicable. They may also appear in MSG1, but this is not
guaranteed. MSG4 must advertise the same set as MSG2.
-Currently, the low 16 bits are allocated for negotiating bulk-crypto
-transforms. Bits 8 to 15 are used by Secnet as default capability
-numbers for the various kinds of transform closures: bit 8 is for the
-original CBCMAC-based transform, and bit 9 for the new EAX transform;
-bits 10 to 15 are reserved for future expansion. The the low eight bits
-are reserved for local use, e.g., to allow migration from one set of
-parameters for a particular transform to a different, incompatible set
-of parameters for the same transform. Bit 31, if advertised by both
-ends, indicates that a mobile end gets priority in case of crossed MSG1.
-The remaining bits have not yet been assigned a purpose.
+Capability bits 8 to 31 are used by Secnet as default capability numbers
+for various features: bit 8 is for the original CBCMAC-based transform,
+and bit 9 for the new EAX transform; bit 10 for traditional finite-field
+Diffie--Hellman; bits 11 to 14 and 16 to 30 are reserved for future
+expansion. The the low eight bits are reserved for local use, e.g., to
+allow migration from one set of parameters for a particular transform to
+a different, incompatible set of parameters for the same transform. Bit
+31, if advertised by both ends, indicates that a mobile end gets
+priority in case of crossed MSG1.
+
+Bit 15 is special: it signifies (a) that the sender is reporting all of
+its transforms and DH groups explicitly, and (b) that it uses all 32
+capability bits to do so. Older Secnets only checked the low 16 bits
+for known capabilities.
Whether a capability number is early depends on its meaning, rather than
being a static property of its number. That said, the mobile-end-gets
Whether a capability number is early depends on its meaning, rather than
being a static property of its number. That said, the mobile-end-gets
#include <limits.h>
#include "secnet.h"
#include <limits.h>
#include "secnet.h"
#include "util.h"
struct dh {
#include "util.h"
struct dh {
/* According to the docs, mpz_sizeinbase(,256) is allowed to return
* an answer which is 1 too large. But mpz_sizeinbase(,2) isn't. */
/* According to the docs, mpz_sizeinbase(,256) is allowed to return
* an answer which is 1 too large. But mpz_sizeinbase(,2) isn't. */
+ if (!dict)
+ st->ops.capab_bit = CAPAB_BIT_TRADZP;
+ else
+ st->ops.capab_bit = dict_read_number(dict, "capab-num", False,
+ "dh", loc, CAPAB_BIT_TRADZP);
+ if (st->ops.capab_bit > CAPAB_BIT_MAX)
+ cfgfatal(loc,"dh","capab-num out of range 0..%d\n",
+ CAPAB_BIT_MAX);
+
return new_closure(&st->cl);
}
return new_closure(&st->cl);
}
#define LABEL_MSG2 MSGCODE( 2, 0)
#define LABEL_MSG3 MSGCODE( 3, 0)
#define LABEL_MSG3BIS MSGCODE( 3, 1)
#define LABEL_MSG2 MSGCODE( 2, 0)
#define LABEL_MSG3 MSGCODE( 3, 0)
#define LABEL_MSG3BIS MSGCODE( 3, 1)
+#define LABEL_MSG3TER MSGCODE( 3, 2)
#define LABEL_MSG4 MSGCODE( 4, 0)
#define LABEL_MSG5 MSGCODE( 5, 0)
#define LABEL_MSG6 MSGCODE( 6, 0)
#define LABEL_MSG4 MSGCODE( 4, 0)
#define LABEL_MSG5 MSGCODE( 5, 0)
#define LABEL_MSG6 MSGCODE( 6, 0)
*/
/* uses of the 32-bit capability bitmap */
*/
/* uses of the 32-bit capability bitmap */
-#define CAPAB_TRANSFORM_MASK 0x0000ffff
+#define CAPAB_INEXPLICIT_TRANSFORM_MASK 0x0000ffff /* DH group implicit */
+#define CAPAB_EXPLICIT_TRANSFORM_DH 0x00008000 /* Explicit xform and DH */
#define CAPAB_PRIORITY_MOBILE 0x80000000 /* mobile site has MSG1 priority */
/* remaining bits are unused */
#define CAPAB_PRIORITY_MOBILE 0x80000000 /* mobile site has MSG1 priority */
/* remaining bits are unused */
#define CAPAB_BIT_USER_MAX 7
#define CAPAB_BIT_SERPENT256CBC 8
#define CAPAB_BIT_EAXSERPENT 9
#define CAPAB_BIT_USER_MAX 7
#define CAPAB_BIT_SERPENT256CBC 8
#define CAPAB_BIT_EAXSERPENT 9
-#define CAPAB_BIT_MAX 15
+#define CAPAB_BIT_TRADZP 10
+#define CAPAB_BIT_EXPLICIT_TRANSFORM_DH 15
+#define CAPAB_BIT_MAX 31
#define CAPAB_BIT_ANCIENTTRANSFORM CAPAB_BIT_SERPENT256CBC
#define CAPAB_BIT_ANCIENTTRANSFORM CAPAB_BIT_SERPENT256CBC
local function dump_algs(algs)
-- Dump the algorithms selection ALGS from a site structure.
local function dump_algs(algs)
-- Dump the algorithms selection ALGS from a site structure.
- return "xform=" .. algs.transform
+ return "xform=" .. algs.transform .. "; dh=" .. algs.dhgroup
end
local function dump_str(str) return str end
end
local function dump_str(str) return str end
desc = "Deprecated Serpent256-CBC transform" },
[9] = { name = "eaxserpent", kind = "transform",
desc = "Serpent256-EAX transform" },
desc = "Deprecated Serpent256-CBC transform" },
[9] = { name = "eaxserpent", kind = "transform",
desc = "Serpent256-EAX transform" },
+ [10] = { name = "tradzp", kind = "dhgroup",
+ desc = "Traditional Z_p Diffie--Hellman key agreement" },
[31] = { name = "mobile-priority", kind = "early",
desc = "Mobile site takes priority in case of MSG1 crossing" }
}
[31] = { name = "mobile-priority", kind = "early",
desc = "Mobile site takes priority in case of MSG1 crossing" }
}
-- Record the algorithm selections declared in the packet described by ST.
local transform = get_algname("transform", st.transform, "serpent256cbc")
-- Record the algorithm selections declared in the packet described by ST.
local transform = get_algname("transform", st.transform, "serpent256cbc")
+ local dhgroup = get_algname("dhgroup", st.dhgroup, "tradzp")
local site = get_site_create(st.sndname)
local peer = get_site_create(st.rcvname)
local now = st.pinfo.rel_ts
local site = get_site_create(st.sndname)
local peer = get_site_create(st.rcvname)
local now = st.pinfo.rel_ts
- local algs = { transform = transform }
+ local algs = { transform = transform, dhgroup = dhgroup }
tl_add(get_timeline_create(site.algs, st.rcvname), now, algs)
tl_add(get_timeline_create(peer.algs, st.sndname), now, algs)
end
tl_add(get_timeline_create(site.algs, st.rcvname), now, algs)
tl_add(get_timeline_create(peer.algs, st.sndname), now, algs)
end
MSG2 = msgcode( 2, 0),
MSG3 = msgcode( 3, 0),
MSG3BIS = msgcode( 3, 1),
MSG2 = msgcode( 2, 0),
MSG3 = msgcode( 3, 0),
MSG3BIS = msgcode( 3, 1),
+ MSG3TER = msgcode( 3, 2),
MSG4 = msgcode( 4, 0),
MSG5 = msgcode( 5, 0),
MSG6 = msgcode( 6, 0),
MSG4 = msgcode( 4, 0),
MSG5 = msgcode( 5, 0),
MSG6 = msgcode( 6, 0),
-- Firstly, build, in `caps', a list of the capability names and their
-- numbers.
local i = 1
-- Firstly, build, in `caps', a list of the capability names and their
-- numbers.
local i = 1
+ caps[i] = { i = 15, cap = "explicit" }; i = 1 + 1
for j, cap in pairs(CAPTAB) do
caps[i] = { i = j, cap = cap.name }
i = i + 1
for j, cap in pairs(CAPTAB) do
caps[i] = { i = j, cap = cap.name }
i = i + 1
+local function dissect_dhgroup(st, buf, tree, pos, sz)
+ -- Dissect the selected DH group. Note this in the packet state for later.
+
+ st.dhgroup = buf(pos, 1):uint()
+ tree:add(PF["secnet.kx.dhgroup"], buf(pos, 1)); pos = pos + 1
+ return pos
+end
+
local function dissect_lenstr(st, buf, tree, label, pos, sz)
-- Dissect a simple string given its length.
local len = buf(pos, 2):uint()
local function dissect_lenstr(st, buf, tree, label, pos, sz)
-- Dissect a simple string given its length.
local len = buf(pos, 2):uint()
dissect_wtf },
hook = notice_alg_selection
},
dissect_wtf },
hook = notice_alg_selection
},
+ [M.MSG3TER] = {
+ label = "MSG3TER",
+ info = "MSG3TER",
+ dissect = { make_dissect_name_xinfo("secnet.kx.sndname",
+ { dissect_caps,
+ dissect_mtu,
+ dissect_wtf },
+ notice_sndname),
+ make_dissect_name_xinfo("secnet.kx.rcvname",
+ { dissect_wtf },
+ notice_rcvname),
+ dissect_sndnonce, dissect_rcvnonce,
+ dissect_transform, dissect_dhgroup,
+ dissect_dhval, dissect_sig,
+ dissect_wtf },
+ hook = notice_alg_selection
+ },
[M.MSG4] = {
label = "MSG4",
info = "MSG4",
[M.MSG4] = {
label = "MSG4",
info = "MSG4",
local msgtab = { }
for i, v in pairs(PKTINFO) do msgtab[i] = v.label end
local msgtab = { }
for i, v in pairs(PKTINFO) do msgtab[i] = v.label end
- local capmap = { transform = { }, early = { } }
+ local capmap = { transform = { }, dhgroup = { }, early = { } }
for i, v in pairs(CAPTAB) do capmap[v.kind][i] = v.desc end
local ftab = {
for i, v in pairs(CAPTAB) do capmap[v.kind][i] = v.desc end
local ftab = {
name = "User-assigned capability bits",
type = ftypes.UINT32, mask = 0x000000ff, base = base.HEX
},
name = "User-assigned capability bits",
type = ftypes.UINT32, mask = 0x000000ff, base = base.HEX
},
+ ["secnet.cap.explicit"] = {
+ name = "Transforms listed explicitly; all capability bits used",
+ type = ftypes.BOOLEAN, mask = 0x00008000, base = 32
+ },
["secnet.mtu"] = {
name = "Sender's requested MTU", type = ftypes.UINT16, base = base.DEC
},
["secnet.mtu"] = {
name = "Sender's requested MTU", type = ftypes.UINT16, base = base.DEC
},
name = "Selected bulk-crypto transform", type = ftypes.UINT8,
base = base.DEC, tab = capmap.transform
},
name = "Selected bulk-crypto transform", type = ftypes.UINT8,
base = base.DEC, tab = capmap.transform
},
+ ["secnet.kx.dhgroup"] = {
+ name = "Selected Diffie--Hellman group kind", type = ftypes.UINT8,
+ base = base.DEC, tab = capmap.dhgroup
+ },
["secnet.kx.dhval"] = {
name = "Sender's public Diffie--Hellman value", type = ftypes.NONE
},
["secnet.kx.dhval"] = {
name = "Sender's public Diffie--Hellman value", type = ftypes.NONE
},
Corresponds to the
.I CHECK
argument.
Corresponds to the
.I CHECK
argument.
+.TP
+.B capab-num
+The capability number to use when advertising
+this Diffie\(enHellman group.
+The default capability number is 10.
+
.PP
A \fIdh closure\fR defines a group to be used for key exchange.
.PP
A \fIdh closure\fR defines a group to be used for key exchange.
at the other end is irrelevant.)
.TP
.B dh
at the other end is irrelevant.)
.TP
.B dh
-A \fIdh closure\fR.
-The group to use in key exchange.
+A list of one or more \fIdh closure\fRs.
+The groups to use in key exchange.
+These should all have distinct
+.B capab-num
+values,
+and the same
+.B capab-num
+value should have the same (or a compatible) meaning 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 hash
The hash function used during setup.
.TP
.B hash
The hash function used during setup.
void *st;
int32_t secret_len; /* Size of random secret to generate */
int32_t shared_len; /* Size of generated shared secret */
void *st;
int32_t secret_len; /* Size of random secret to generate */
int32_t shared_len; /* Size of generated shared secret */
dh_makepublic_fn *makepublic;
dh_makeshared_fn *makeshared;
};
dh_makepublic_fn *makepublic;
dh_makeshared_fn *makeshared;
};
#define SITE_SENTMSG5 7
#define SITE_WAIT 8
#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;
int32_t site_max_start_pad = 4*4;
struct rsapubkey_if *pubkey;
struct transform_if **transforms;
int ntransforms;
struct rsapubkey_if *pubkey;
struct transform_if **transforms;
int ntransforms;
+ struct dh_if **dhs;
+ int ndhs;
struct hash_if *hash;
uint32_t index; /* Index of this site */
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;
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 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;
uint32_t remote_capabilities;
uint16_t remote_mtu;
int capab_transformnum;
uint8_t *nR;
uint8_t *nL;
int32_t pklen;
uint8_t *nR;
uint8_t *nL;
int32_t pklen;
/* Generate the shared key */
assert(!st->sharedsecret);
/* 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");
+ if (!st->chosen_dh->makeshared(st->chosen_dh->st,
+ st->dhsecret,st->chosen_dh->secret_len,
+ pk,
+ 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,
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;
dispose_transform(&st->new_transform);
if (!ok) return False;
minor = MSGMINOR(type);
if (minor < 1) break;
buf_append_uint8(&st->buffer,st->chosen_transform->capab_bit);
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);
- dhpub=st->dh->makepublic(st->dh->st,st->dhsecret,st->dh->secret_len);
+ dhpub=st->chosen_dh->makepublic(st->chosen_dh->st,
+ st->dhsecret,st->chosen_dh->secret_len);
buf_append_string(&st->buffer,dhpub);
free(dhpub);
hash=safe_malloc(st->hash->len, "generate_msg");
buf_append_string(&st->buffer,dhpub);
free(dhpub);
hash=safe_malloc(st->hash->len, "generate_msg");
- 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);
m->hashstart=msg->start;
CHECK_AVAIL(msg,4);
m->dest=buf_unprepend_uint32(msg);
} \
} while (0)
MAYBE_READ_CAP(1, transform, CAPAB_BIT_ANCIENTTRANSFORM);
} \
} 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);
#undef MAYBE_READ_CAP
} while (0);
CHECK_AVAIL(msg,2);
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 */
+ /* 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)
/* 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; \
#define CHOOSE_CRYPTO(kind, whats) do { \
struct kind##_if *iface; \
} while (0)
CHOOSE_CRYPTO(transform, "transforms");
} while (0)
CHOOSE_CRYPTO(transform, "transforms");
+ CHOOSE_CRYPTO(dh, "Diffie--Hellman groups");
static void generate_dhsecret(struct site *st)
{
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);
- 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)
}
static bool_t generate_msg3(struct site *st)
and create message number 3. */
generate_dhsecret(st);
return generate_msg(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");
? LABEL_MSG3BIS
: LABEL_MSG3,
"site:MSG3");
} while (0)
CHOSE_CRYPTO(transform, "transform");
} while (0)
CHOSE_CRYPTO(transform, "transform");
+ CHOSE_CRYPTO(dh, "Diffie--Hellman group");
FILLZERO(st->remoteN);
dispose_transform(&st->new_transform);
if (st->dhsecret) {
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) {
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;
}
free(st->sharedsecret);
st->sharedsecret = 0;
}
assert(index_sequence < 0xffffffffUL);
st->index = ++index_sequence;
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->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);
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->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->remote_capabilities=0;
st->chosen_transform=0;
st->current.key_timeout=0;
st->auxiliary_key.key_timeout=0;
transport_peers_clear(st,&st->peers);
st->current.key_timeout=0;
st->auxiliary_key.key_timeout=0;
transport_peers_clear(st,&st->peers);
for (i=0; i<st->ntransforms; i++)
SET_CAPBIT(st->transforms[i]->capab_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);