From fe2a5dcf9de1f124ed3cfa2c6327860bd5aca820 Mon Sep 17 00:00:00 2001 Message-Id: From: Mark Wooding Date: Wed, 25 Jan 2012 23:49:47 +0000 Subject: [PATCH] Allow different peer associations to use different private keys. Organization: Straylight/Edgeware From: Mark Wooding Add a `peertag' slot to the `peerspec' structure stating which private key to use; a null pointer means to use the default `tag_priv'. Add a `p_privtag' function to retrieve the private key tag to use. The ADD command now has a `-priv' option which sets this slot appropriately. The `connect' service fetches a `priv' key. from the database to set this option. --- peerdb/peers.in.5.in | 3 +++ py/tripe.py.in | 3 ++- server/admin.c | 12 +++++++++++- server/keyexch.c | 8 ++++---- server/peer.c | 32 ++++++++++++++++++++------------ server/tripe-admin.5.in | 18 +++++++++++++++--- server/tripe.h | 10 ++++++++++ svc/connect.in | 1 + 8 files changed, 66 insertions(+), 21 deletions(-) diff --git a/peerdb/peers.in.5.in b/peerdb/peers.in.5.in index c8763656..48f69b3b 100644 --- a/peerdb/peers.in.5.in +++ b/peerdb/peers.in.5.in @@ -188,6 +188,9 @@ Network address for this peer, or Used by .BR connect (8). .TP +.B priv +Tag of the private key to use when communicating with the peer. +.TP .B raddr Remote address for the tunnel interface to the peer. Used by .BR tripe-ifup (8). diff --git a/py/tripe.py.in b/py/tripe.py.in index 78a305b8..c2b430be 100644 --- a/py/tripe.py.in +++ b/py/tripe.py.in @@ -831,7 +831,8 @@ class TripeCommandDispatcher (TripeConnection): return _simple(me.command(bg = True, *['ADD'] + _kwopts(kw, ['tunnel', 'keepalive', - 'key', 'cork', 'mobile']) + + 'key', 'priv', 'cork', + 'mobile']) + [peer] + list(addr))) def addr(me, peer): diff --git a/server/admin.c b/server/admin.c index 0fb57cd8..0e3effb0 100644 --- a/server/admin.c +++ b/server/admin.c @@ -1250,6 +1250,7 @@ static void acmd_add(admin *a, unsigned ac, char *av[]) add = xmalloc(sizeof(*add)); add->peer.name = 0; add->peer.tag = 0; + add->peer.privtag = 0; add->peer.t_ka = 0; add->peer.tops = tun_default; add->peer.f = 0; @@ -1279,6 +1280,11 @@ static void acmd_add(admin *a, unsigned ac, char *av[]) add->peer.tag = xstrdup(arg); }) OPT("-mobile", { add->peer.f |= PSF_MOBILE; }) + OPTARG("-priv", arg, { + if (add->peer.privtag) + xfree(add->peer.privtag); + add->peer.privtag = xstrdup(arg); + }) }); /* --- Make sure someone's not got there already --- */ @@ -1304,6 +1310,7 @@ bad_syntax: fail: if (add->peer.name) xfree(add->peer.name); if (add->peer.tag) xfree(add->peer.tag); + if (add->peer.privtag) xfree(add->peer.privtag); xfree(add); return; } @@ -1828,7 +1835,10 @@ static void acmd_peerinfo(admin *a, unsigned ac, char *av[]) if ((p = a_findpeer(a, av[0])) != 0) { ps = p_spec(p); a_info(a, "tunnel=%s", ps->tops->name, A_END); - a_info(a, "key=%s", p_tag(p), A_END); + a_info(a, "key=%s", p_tag(p), + "current-key=%s", p->kx.kpub->tag, A_END); + a_info(a, "private-key=%s", p_privtag(p), + "current-private-key=%s", p->kx.kpriv->tag, A_END); a_info(a, "keepalive=%lu", ps->t_ka, A_END); a_ok(a); } diff --git a/server/keyexch.c b/server/keyexch.c index 1527a297..50a85f6f 100644 --- a/server/keyexch.c +++ b/server/keyexch.c @@ -1383,11 +1383,11 @@ newkeys: int kx_init(keyexch *kx, peer *p, keyset **ks, unsigned f) { - if ((kx->kpriv = km_findpriv(tag_priv)) == 0) goto fail_0; + if ((kx->kpriv = km_findpriv(p_privtag(p))) == 0) goto fail_0; if ((kx->kpub = km_findpub(p_tag(p))) == 0) goto fail_1; - if (!km_samealgsp(kx->kpriv, kx->kpub)) { - a_warn("KX", "?PEER", kx->p, "algorithms-mismatch", - "local-private-key", "%s", tag_priv, + if (!group_samep(kx->kpriv->g, kx->kpub->g)) { + a_warn("KX", "?PEER", kx->p, "group-mismatch", + "local-private-key", "%s", p_privtag(p), "peer-public-key", "%s", p_tag(p), A_END); goto fail_2; diff --git a/server/peer.c b/server/peer.c index 308ab1d1..75f7acba 100644 --- a/server/peer.c +++ b/server/peer.c @@ -820,6 +820,7 @@ unsigned p_port(void) static void p_keepalive(struct timeval *now, void *pv) { peer *p = pv; + p_txstart(p, MSG_MISC | MISC_NOP); p_dotxend(p); T( trace(T_PEER, "peer: sent keepalive to %s", p->spec.name); ) p_setkatimer(p); @@ -871,8 +872,8 @@ peer *p_create(peerspec *spec) T( trace(T_PEER, "peer: creating new peer `%s'", spec->name); ) p->spec = *spec; p->spec.name = (/*unconst*/ char *)SYM_NAME(p->byname); - if (spec->tag) - p->spec.tag = xstrdup(spec->tag); + if (spec->tag) p->spec.tag = xstrdup(spec->tag); + if (spec->privtag) p->spec.privtag = xstrdup(spec->privtag); p->ks = 0; p->pings = 0; p->ifname = 0; @@ -902,8 +903,7 @@ peer *p_create(peerspec *spec) return (p); tidy_4: - if (spec->t_ka) - sel_rmtimer(&p->tka); + if (spec->t_ka) sel_rmtimer(&p->tka); xfree(p->ifname); p->t->ops->destroy(p->t); tidy_3: @@ -911,6 +911,7 @@ tidy_3: tidy_2: am_remove(&byaddr, p->byaddr); if (p->spec.tag) xfree(p->spec.tag); + if (p->spec.privtag) xfree(p->spec.privtag); tidy_1: sym_remove(&byname, p->byname); tidy_0: @@ -938,6 +939,16 @@ const char *p_name(peer *p) const char *p_tag(peer *p) { return (p->spec.tag ? p->spec.tag : p->spec.name); } +/* --- @p_privtag@ --- * + * + * Arguments: @peer *p@ = pointer to a peer block + * + * Returns: A pointer to the peer's private key tag. + */ + +const char *p_privtag(peer *p) + { return (p->spec.privtag ? p->spec.privtag : tag_priv); } + /* --- @p_spec@ --- * * * Arguments: @peer *p@ = pointer to a peer block @@ -1002,15 +1013,12 @@ void p_destroy(peer *p) a_notify("KILL", "%s", p->spec.name, A_END); ksl_free(&p->ks); kx_free(&p->kx); - if (p->spec.f & PSF_MOBILE) - nmobile--; - if (p->ifname) - xfree(p->ifname); - if (p->spec.tag) - xfree(p->spec.tag); + if (p->spec.f & PSF_MOBILE) nmobile--; + if (p->ifname) xfree(p->ifname); + if (p->spec.tag) xfree(p->spec.tag); + if (p->spec.privtag) xfree(p->spec.privtag); p->t->ops->destroy(p->t); - if (p->spec.t_ka) - sel_rmtimer(&p->tka); + if (p->spec.t_ka) sel_rmtimer(&p->tka); for (pg = p->pings; pg; pg = ppg) { ppg = pg->next; p_pingdone(pg, PING_PEERDIED); diff --git a/server/tripe-admin.5.in b/server/tripe-admin.5.in index a27179d8..6ffa6cd6 100644 --- a/server/tripe-admin.5.in +++ b/server/tripe-admin.5.in @@ -546,10 +546,22 @@ The keepalive interval, in seconds, or zero if no keepalives are to be sent. .TP .B key -The key tag being used for the peer, as passed to the +The (short) key tag being used for the peer, as passed to the .B ADD -command. (You don't get a full key-id, since that might change while -the daemon's running.) +command. +.TP +.B current-key +The full key tag of the peer's public key currently being used. This +may change during the life of the association. +.TP +.B private-key +The private key tag being used for the peer, as passed to the +.B ADD +command. +.TP +.B current-private-key +The full key tag of the private key currently being used for this +association. This may change during the life of the association. .RE .SP .BI "PING \fR[" options "\fR] " peer diff --git a/server/tripe.h b/server/tripe.h index b22dccce..b4eee1b3 100644 --- a/server/tripe.h +++ b/server/tripe.h @@ -353,6 +353,7 @@ typedef struct stats { typedef struct peerspec { char *name; /* Peer's name */ + char *privtag; /* Private key tag */ char *tag; /* Public key tag */ const tunnel_ops *tops; /* Tunnel operations */ unsigned long t_ka; /* Keep alive interval */ @@ -1330,6 +1331,15 @@ extern const char *p_name(peer */*p*/); extern const char *p_tag(peer */*p*/); +/* --- @p_privtag@ --- * + * + * Arguments: @peer *p@ = pointer to a peer block + * + * Returns: A pointer to the peer's private key tag. + */ + +extern const char *p_privtag(peer */*p*/); + /* --- @p_spec@ --- * * * Arguments: @peer *p@ = pointer to a peer block diff --git a/svc/connect.in b/svc/connect.in index 0ae539f5..5f8940e3 100644 --- a/svc/connect.in +++ b/svc/connect.in @@ -92,6 +92,7 @@ def addpeer(peer, addr): tunnel = peer.get('tunnel', None), keepalive = peer.get('keepalive', None), key = peer.get('key', None), + priv = peer.get('priv', None), mobile = peer.get('mobile', 'nil') in booltrue, cork = peer.get('cork', 'nil') in booltrue, *addr) -- [mdw]