Adding tipc-discusson to the recipient list of this disacussion.

///jon

> -----Original Message-----
> From: Jon Maloy
> Sent: 21-Dec-19 10:56
> To: Tuong Lien <tuong.t.l...@dektech.com.au>; tipc-...@dektech.com.au
> Subject: RE: [PATCH RFC] tipc: add automatic rekeying for TIPC encryption
> 
> Hi Tuong,
> I am getting more and more ambivalent about this.
> Before introducing this we must weigh the pro and cons correctly:
> 
> Pros:
> - It will give less time for a sniffer to crack the key, since we change it 
> often.
> - If a sniffer cracks a key, he only gets access to messages from the node 
> owning that key, not the whole
> cluster.
> 
> Cons:
> - Larger code footprint.
> - No forward security. If a sniffer gets hold of a node key, he can listen 
> forever, as you have already noted.
> - New nodes cannot be added to the cluster unless there is a way for the user 
> land framework to read the
> current key on each node and distribute to the new node.
> - What happens when a node restarts, and forgets about all current keys, both 
> its own and those of its
> peers.
> 
> The last two bullets are showstoppers,  in my view. We must find a way to 
> add/re-insert nodes as easily as
> we do now, at least.
> 
> This means we must come back to the solution with a "master"  cluster key. 
> I suspect a typical user will just aim for adding the key or keys to
> the cluster configuration file, and at a maximum update that key at regular 
> intervals.
> 
> So, maybe, apart from the 'current' node key we also keep a 'cluster'  master 
> key that can always be used
> for attaching new nodes, but allow for this to be updated via the tipc tool.
> The user may then, of he wants, replace/update this key at regular intervals.
> At the same time this key must be reserved for new/restarting nodes only, and 
> not be permitted for use by
> existing nodes which already are using 'current' keys.
> 
> This would at least make it somewhat more acceptable for the user than the 
> current approach.
> 
> Regards
> ///jon
> 
> 
> 
> 
> > -----Original Message-----
> > From: Jon Maloy
> > Sent: 18-Dec-19 19:33
> > To: Tuong Lien <tuong.t.l...@dektech.com.au>; tipc-...@dektech.com.au
> > Subject: RE: [PATCH RFC] tipc: add automatic rekeying for TIPC encryption
> >
> > I have a couple comments below, but in general it looks good.
> > So, after some hesitation I suggest you send this to tipc-discussion for 
> > further review.
> >
> > ///jon
> >
> >
> > > -----Original Message-----
> > > From: Tuong Lien <tuong.t.l...@dektech.com.au>
> > > Sent: 10-Dec-19 06:48
> > > To: Jon Maloy <jon.ma...@ericsson.com>; tipc-...@dektech.com.au
> > > Subject: [PATCH RFC] tipc: add automatic rekeying for TIPC encryption
> > >
> > > This commit adds functionality for TIPC encryption to automatically
> > > generate a new symmetric key and attach as new TX key for the own node.
> > > The new key will also be distributed to peer nodes and set as RX keys,
> > > i.e. the per-node key mode. This process of rekeying will be repeated,
> > > for example every ~ 10 minutes (from the time a certain key becomes
> > > active), so new session keys will be created and applied regularly to
> > > the cluster.
> > >
> > > Since the key exchange needs a secure communication channel in advance,
> > > the commit simplifies this by only starting with an initial key (either
> > > in cluster or per-node key mode) which is set by user first (e.g. via
> > > the "tipc node set key ..." command), so the entire cluster is already
> > > secure and authenticated. After that, the rekeying will be scheduled as
> > > said above.
> > >
> > > Also, the key exchange utilizes the broadcast link which is reliable.
> > > And, the key switching with no impact on traffic is already supported
> > > by the previous commit.
> > >
> > > ----------------------------------------------
> > > Note: this solution has two issues:
> > > - No forward secrecy
> > > - how a new VM joins the cluster...?
> >
> > We still need a framework for distributing the initial key for a new node, 
> > but it will probably be simpler
> > than before since we don't need to distribute keys regularly.
> >
> > > ----------------------------------------------
> > >
> > > Signed-off-by: Tuong Lien <tuong.t.l...@dektech.com.au>
> > > ---
> > >  net/tipc/bcast.c  |   4 +-
> > >  net/tipc/bcast.h  |   2 +
> > >  net/tipc/crypto.c | 195 
> > > +++++++++++++++++++++++++++++++++++++++++++++++++++++-
> > >  net/tipc/crypto.h |   1 +
> > >  net/tipc/link.c   |   3 +
> > >  net/tipc/msg.h    |   1 +
> > >  net/tipc/node.c   |   8 +++
> > >  net/tipc/node.h   |   1 +
> > >  8 files changed, 211 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
> > > index 55aeba681cf4..330b683f335e 100644
> > > --- a/net/tipc/bcast.c
> > > +++ b/net/tipc/bcast.c
> > > @@ -249,8 +249,8 @@ static void tipc_bcast_select_xmit_method(struct net 
> > > *net, int dests,
> > >   * Consumes the buffer chain.
> > >   * Returns 0 if success, otherwise errno: -EHOSTUNREACH,-EMSGSIZE
> > >   */
> > > -static int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts,
> > > -                    u16 *cong_link_cnt)
> > > +int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts,
> > > +             u16 *cong_link_cnt)
> > >  {
> > >   struct tipc_link *l = tipc_bc_sndlink(net);
> > >   struct sk_buff_head xmitq;
> > > diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h
> > > index 9e847d9617d3..f095a2ac27cb 100644
> > > --- a/net/tipc/bcast.h
> > > +++ b/net/tipc/bcast.h
> > > @@ -89,6 +89,8 @@ void tipc_bcast_toggle_rcast(struct net *net, bool 
> > > supp);
> > >  int tipc_mcast_xmit(struct net *net, struct sk_buff_head *pkts,
> > >               struct tipc_mc_method *method, struct tipc_nlist *dests,
> > >               u16 *cong_link_cnt);
> > > +int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts,
> > > +             u16 *cong_link_cnt);
> > >  int tipc_bcast_rcv(struct net *net, struct tipc_link *l, struct sk_buff 
> > > *skb);
> > >  void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l,
> > >                   struct tipc_msg *hdr);
> > > diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c
> > > index 990a872cec46..b415c9adf14d 100644
> > > --- a/net/tipc/crypto.c
> > > +++ b/net/tipc/crypto.c
> > > @@ -36,12 +36,17 @@
> > >
> > >  #include <crypto/aead.h>
> > >  #include <crypto/aes.h>
> > > +#include <crypto/rng.h>
> > >  #include "crypto.h"
> > > +#include "msg.h"
> > > +#include "bcast.h"
> > >
> > >  #define TIPC_TX_PROBE_LIM        msecs_to_jiffies(1000) /* > 1s */
> > >  #define TIPC_TX_LASTING_LIM      msecs_to_jiffies(120000) /* 2 mins */
> > >  #define TIPC_RX_ACTIVE_LIM       msecs_to_jiffies(3000) /* 3s */
> > >  #define TIPC_RX_PASSIVE_LIM      msecs_to_jiffies(180000) /* 3 mins */
> > > +#define TIPC_REKEYING_TIME       msecs_to_jiffies(600000) /* 10 mins */
> > > +
> > >  #define TIPC_MAX_TFMS_DEF        10
> > >  #define TIPC_MAX_TFMS_LIM        1000
> > >
> > > @@ -132,6 +137,7 @@ struct tipc_tfm {
> > >   * @mode: crypto mode is applied to the key
> > >   * @hint[]: a hint for user key
> > >   * @rcu: struct rcu_head
> > > + * @keylen: the aead key length
> > >   * @seqno: the key seqno (cluster scope)
> > >   * @refcnt: the key reference counter
> > >   */
> > > @@ -146,6 +152,7 @@ struct tipc_aead {
> > >   u8 mode;
> > >   char hint[TIPC_AEAD_HINT_LEN + 1];
> > >   struct rcu_head rcu;
> > > + unsigned int keylen;
> > >
> > >   atomic64_t seqno ____cacheline_aligned;
> > >   refcount_t refcnt ____cacheline_aligned;
> > > @@ -172,6 +179,8 @@ struct tipc_crypto_stats {
> > >   * @timer1: general timer 1 (jiffies)
> > >   * @timer2: general timer 1 (jiffies)
> > >   * @lock: tipc_key lock
> > > + * @work: delayed work for rekeying
> > > + * @skey: session key
> > >   */
> > >  struct tipc_crypto {
> > >   struct net *net;
> > > @@ -186,6 +195,8 @@ struct tipc_crypto {
> > >   unsigned long timer1;
> > >   unsigned long timer2;
> > >   spinlock_t lock; /* crypto lock */
> > > + struct delayed_work work;
> > > + struct tipc_aead_key *skey;
> > >
> > >  } ____cacheline_aligned;
> > >
> > > @@ -210,6 +221,8 @@ static void tipc_aead_users_inc(struct tipc_aead 
> > > __rcu *aead, int lim);
> > >  static void tipc_aead_users_dec(struct tipc_aead __rcu *aead, int lim);
> > >  static void tipc_aead_users_set(struct tipc_aead __rcu *aead, int val);
> > >  static struct crypto_aead *tipc_aead_tfm_next(struct tipc_aead *aead);
> > > +static struct tipc_aead_key *tipc_aead_key_generate(unsigned int keylen);
> > > +static int tipc_aead_key_distribute(struct net *net, struct 
> > > tipc_aead_key *skey);
> > >  static int tipc_aead_init(struct tipc_aead **aead, struct tipc_aead_key 
> > > *ukey,
> > >                     u8 mode);
> > >  static int tipc_aead_clone(struct tipc_aead **dst, struct tipc_aead 
> > > *src);
> > > @@ -251,6 +264,7 @@ static char *tipc_crypto_key_dump(struct tipc_crypto 
> > > *c, char *buf);
> > >  static char *tipc_key_change_dump(struct tipc_key old, struct tipc_key 
> > > new,
> > >                             char *buf);
> > >  #endif
> > > +static void tipc_crypto_rekey(struct work_struct *work);
> > >
> > >  #define key_next(cur) ((cur) % KEY_MAX + 1)
> > >
> > > @@ -506,6 +520,7 @@ static int tipc_aead_init(struct tipc_aead **aead, 
> > > struct tipc_aead_key *ukey,
> > >   tmp->mode = mode;
> > >   tmp->cloned = NULL;
> > >   tmp->authsize = TIPC_AES_GCM_TAG_SIZE;
> > > + tmp->keylen = ukey->keylen;
> > >   memcpy(&tmp->salt, ukey->key + keylen, TIPC_AES_GCM_SALT_SIZE);
> > >   atomic_set(&tmp->users, 0);
> > >   atomic64_set(&tmp->seqno, 0);
> > > @@ -1368,8 +1383,9 @@ int tipc_crypto_start(struct tipc_crypto **crypto, 
> > > struct net *net,
> > >   c->timer1 = jiffies;
> > >   c->timer2 = jiffies;
> > >   spin_lock_init(&c->lock);
> > > - *crypto = c;
> > > + INIT_DELAYED_WORK(&c->work, tipc_crypto_rekey);
> > >
> > > + *crypto = c;
> > >   return 0;
> > >  }
> > >
> > > @@ -1382,6 +1398,10 @@ void tipc_crypto_stop(struct tipc_crypto **crypto)
> > >   if (!*crypto)
> > >           return;
> > >
> > > + /* Cancel any rekeying work */
> > > + c = *crypto;
> > > + cancel_delayed_work_sync(&c->work);
> > > +
> > >   rcu_read_lock();
> > >   /* RX stopping? => decrease TX key users if any */
> > >   is_rx = !!((*crypto)->node);
> > > @@ -1397,7 +1417,6 @@ void tipc_crypto_stop(struct tipc_crypto **crypto)
> > >   }
> > >
> > >   /* Release AEAD keys */
> > > - c = *crypto;
> > >   for (k = KEY_MIN; k <= KEY_MAX; k++)
> > >           tipc_aead_put(rcu_dereference(c->aead[k]));
> > >   rcu_read_unlock();
> > > @@ -1442,6 +1461,9 @@ void tipc_crypto_timeout(struct tipc_crypto *rx)
> > >   pr_info("TX(%s): key %d is activated!\n", tipc_own_id_string(tx->net),
> > >           key.pending);
> > >
> > > + /* Schedule rekeying */
> > > + schedule_delayed_work(&tx->work, TIPC_REKEYING_TIME);
> > > +
> > >  s1:
> > >   spin_unlock(&tx->lock);
> > >
> > > @@ -1984,3 +2006,172 @@ static char *tipc_key_change_dump(struct tipc_key 
> > > old, struct tipc_key
> > > new,
> > >   return buf;
> > >  }
> > >  #endif
> > > +
> > > +static struct tipc_aead_key *tipc_aead_key_generate(unsigned int keylen)
> > > +{
> > > + struct tipc_aead_key *skey;
> > > + int rc;
> > > +
> > > + if (!keylen)
> > > +         return NULL;
> > > +
> > > + skey = kmalloc(sizeof(*skey) + keylen, GFP_ATOMIC);
> > > + skey->keylen = keylen;
> > > + strcpy(skey->alg_name, "gcm(aes)");
> > > +
> > > + /* Obtain a key via the default RNG (like ECC) */
> > > + rc = crypto_get_default_rng();
> > > + if (unlikely(rc))
> > > +         goto exit;
> > > +
> > > + rc = crypto_rng_get_bytes(crypto_default_rng, skey->key, keylen);
> > > + crypto_put_default_rng();
> > > + if (unlikely(rc))
> > > +         goto exit;
> > > +
> > > + return skey;
> > > +
> > > +exit:
> > > + kfree(skey);
> > > + return NULL;
> > > +}
> > > +
> > > +static int tipc_aead_key_distribute(struct net *net, struct 
> > > tipc_aead_key *skey)
> > > +{
> > > + struct sk_buff_head pkts;
> > > + struct tipc_msg *hdr;
> > > + struct sk_buff *skb;
> > > + __be32 keylen = htonl(skey->keylen);
> > > + u16 size, cong_link_cnt;
> > > + u8 *data;
> > > + int rc;
> > > +
> > > + size = tipc_aead_key_size(skey);
> > > + skb = tipc_buf_acquire(INT_H_SIZE + size, GFP_ATOMIC);
> > > + if (!skb)
> > > +         return -ENOMEM;
> > > +
> > > + hdr = buf_msg(skb);
> > > + tipc_msg_init(tipc_own_addr(net), hdr, KEY_EXCHANGER, 0,
> > > +               INT_H_SIZE, 0);
> > > +
> > > + msg_set_non_seq(hdr, 1);
> > > + msg_set_size(hdr, INT_H_SIZE + size);
> > > +
> > > + data = msg_data(hdr);
> > > + memcpy(data, skey->alg_name, TIPC_AEAD_ALG_NAME);
> > > + memcpy(data + TIPC_AEAD_ALG_NAME, (u8 *)&keylen, sizeof(__be32));
> > > + memcpy(data + TIPC_AEAD_ALG_NAME + sizeof(__be32), skey->key,
> > > +        skey->keylen);
> > > +
> > > + __skb_queue_head_init(&pkts);
> > > + __skb_queue_tail(&pkts, skb);
> > > + rc = tipc_bcast_xmit(net, &pkts, &cong_link_cnt);
> > > +
> > > + return rc;
> > > +}
> > > +
> > > +int tipc_aead_key_rcv(struct net *net, struct sk_buff *skb)
> > > +{
> > > + struct tipc_msg *hdr = buf_msg(skb);
> > > + struct tipc_crypto *rx;
> > > + u16 size = msg_data_sz(hdr);
> > > + u8 *data = msg_data(hdr);
> > > + unsigned int keylen;
> > > + int rc = 0;
> > > +
> > > + rx = tipc_node_crypto_rx_by_addr(net, msg_prevnode(hdr));
> > > + if (unlikely(!rx || rx->skey)) {
> > > +         pr_err("RX(%s): no RX or one key has received\n",
> > > +                (rx) ? tipc_node_get_id_str(rx->node) : "-");
> > > +         rc = -EKEYREJECTED;
> > > +         goto exit;
> > > + }
> > > +
> > > + /* Sanity check */
> > > + keylen = ntohl(*((__be32*)(data + TIPC_AEAD_ALG_NAME)));
> > > + if (unlikely(size != sizeof(struct tipc_aead_key) + keylen)) {
> > > +         pr_err("RX(%s): key is not valid, keylen %d, size %d\n",
> > > +                tipc_node_get_id_str(rx->node), keylen, size);
> > > +         rc = -EFAULT;
> > > +         goto exit;
> > > + }
> > > +
> > > + /* Allocate memory for the key */
> > > + rx->skey = kmalloc(size, GFP_ATOMIC);
> > > + if (unlikely(!rx->skey)) {
> > > +         pr_err("RX(%s): no memory for session key\n",
> > > +                tipc_node_get_id_str(rx->node));
> > > +         rc = -ENOMEM;
> > > +         goto exit;
> > > + }
> > > +
> > > + /* Copy key from msg data */
> > > + rx->skey->keylen = keylen;
> > > + memcpy(rx->skey->alg_name, data, TIPC_AEAD_ALG_NAME);
> > > + memcpy(rx->skey->key, data + TIPC_AEAD_ALG_NAME + sizeof(__be32),
> > > +        rx->skey->keylen);
> > > +
> > > + /* Schedule key attaching on this RX */
> > > + schedule_delayed_work(&rx->work, 0);
> > > +
> > > +exit:
> > > + if (rx)
> > > +         tipc_node_put(rx->node);
> > > + kfree_skb(skb);
> > > + return rc;
> > > +}
> > > +
> > > +static void tipc_crypto_rekey(struct work_struct *work)
> > > +{
> > > + struct delayed_work *delayed_work = to_delayed_work(work);
> > > + struct tipc_crypto *c = container_of(delayed_work, struct tipc_crypto,
> > > +                                      work);
> > > + struct tipc_aead *aead;
> > > + struct tipc_key key;
> > > + unsigned int keylen = 0;
> > > + int rc;
> > > +
> > > + /* Generate new session key for TX crypto if not yet */
> > > + if (!c->node && !c->skey) {
> > > +         /* Make sure we had a TX key active i.e. secured channel */
> > > +         key = c->key;
> > > +         if (!key.active || key.pending)
> > > +                 return;
> > > +
> > > +         rcu_read_lock();
> > > +         aead = tipc_aead_get(c->aead[key.active]);
> > > +         if (aead) {
> > > +                 keylen = aead->keylen;
> > > +                 tipc_aead_put(aead);
> > > +         }
> > > +         rcu_read_unlock();
> > > +
> > > +         /* Generate new key */
> > > +         c->skey = tipc_aead_key_generate(keylen);
> > > +         if (unlikely(!c->skey))
> > > +                 goto retry;
> > > +
> > > +         /* Distribute key to peers */
> > > +         rc = tipc_aead_key_distribute(c->net, c->skey);
> > > +         if (unlikely(rc)) {
> > > +                 kfree(c->skey);
> > > +                 c->skey = NULL;
> > > +                 goto retry;
> > > +         }
> > > + }
> > > +
> > > + /* Attach the new key to TX/RX */
> > > + BUG_ON(!c->skey);
> >
> > BUG_ON() in production code is always frowned upon.
> > Better a warning and (if possible) continue with the old key.
> >
> >
> > > + rc = tipc_crypto_key_init(c, c->skey, PER_NODE_KEY);
> > > + if (unlikely(rc == -ENOMEM || rc == -EBUSY))
> > > +         goto retry;
> > > +
> > > + kfree(c->skey);
> > > + c->skey = NULL;
> > > + return;
> > > +
> > > +retry:
> > > + /* Let's try again after 1 min */
> > > + schedule_delayed_work(&c->work, msecs_to_jiffies(60000));
> > > +}
> > > diff --git a/net/tipc/crypto.h b/net/tipc/crypto.h
> > > index c3de769f49e8..d222fcafa88d 100644
> > > --- a/net/tipc/crypto.h
> > > +++ b/net/tipc/crypto.h
> > > @@ -161,6 +161,7 @@ int tipc_crypto_key_init(struct tipc_crypto *c, 
> > > struct tipc_aead_key *ukey,
> > >                    u8 mode);
> > >  void tipc_crypto_key_flush(struct tipc_crypto *c);
> > >  int tipc_aead_key_validate(struct tipc_aead_key *ukey);
> > > +int tipc_aead_key_rcv(struct net *net, struct sk_buff *skb);
> > >  bool tipc_ehdr_validate(struct sk_buff *skb);
> > >
> > >  #endif /* _TIPC_CRYPTO_H */
> > > diff --git a/net/tipc/link.c b/net/tipc/link.c
> > > index 24d4d10756d3..6e153f5d3a68 100644
> > > --- a/net/tipc/link.c
> > > +++ b/net/tipc/link.c
> > > @@ -1217,6 +1217,9 @@ static bool tipc_data_input(struct tipc_link *l, 
> > > struct sk_buff *skb,
> > >   case MSG_FRAGMENTER:
> > >   case BCAST_PROTOCOL:
> > >           return false;
> > > + case KEY_EXCHANGER:
> > > +         tipc_aead_key_rcv(l->net, skb);
> > > +         return true;
> > >   default:
> > >           pr_warn("Dropping received illegal msg type\n");
> > >           kfree_skb(skb);
> > > diff --git a/net/tipc/msg.h b/net/tipc/msg.h
> > > index 6d466ebdb64f..227fb708c32c 100644
> > > --- a/net/tipc/msg.h
> > > +++ b/net/tipc/msg.h
> > > @@ -82,6 +82,7 @@ struct plist;
> > >  #define  NAME_DISTRIBUTOR     11
> > >  #define  MSG_FRAGMENTER       12
> > >  #define  LINK_CONFIG          13
> > > +#define  KEY_EXCHANGER        14
> > >  #define  SOCK_WAKEUP          14       /* pseudo user */
> > >  #define  TOP_SRV              15       /* pseudo user */
> > >
> > > diff --git a/net/tipc/node.c b/net/tipc/node.c
> > > index ab04e00cb95b..19a560cfb10f 100644
> > > --- a/net/tipc/node.c
> > > +++ b/net/tipc/node.c
> > > @@ -276,6 +276,14 @@ struct tipc_crypto 
> > > *tipc_node_crypto_rx_by_list(struct list_head *pos)
> > >  {
> > >   return container_of(pos, struct tipc_node, list)->crypto_rx;
> > >  }
> > > +
> > > +struct tipc_crypto *tipc_node_crypto_rx_by_addr(struct net *net, u32 
> > > addr)
> > > +{
> > > + struct tipc_node *n;
> > > +
> > > + n = tipc_node_find(net, addr);
> > > + return (n) ? n->crypto_rx : NULL;
> > > +}
> > >  #endif
> > >
> > >  void tipc_node_free(struct rcu_head *rp)
> > > diff --git a/net/tipc/node.h b/net/tipc/node.h
> > > index a6803b449a2c..7b52a2a2b855 100644
> > > --- a/net/tipc/node.h
> > > +++ b/net/tipc/node.h
> > > @@ -83,6 +83,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 
> > > addr, u8 *peer_id,
> > >  #ifdef CONFIG_TIPC_CRYPTO
> >
> > #ifdefs directly in the code never looks good, and  should be avoided.
> > I think you in many cases can replace the #ifdef sections with macros, and 
> > put the #ifdef inside the
> macro.
> > This would of course require another patch, since we already have some such 
> > sections in the existing
> code.
> >
> > >  struct tipc_crypto *tipc_node_crypto_rx(struct tipc_node *__n);
> > >  struct tipc_crypto *tipc_node_crypto_rx_by_list(struct list_head *pos);
> > > +struct tipc_crypto *tipc_node_crypto_rx_by_addr(struct net *net, u32 
> > > addr);
> > >  #endif
> > >  u32 tipc_node_try_addr(struct net *net, u8 *id, u32 addr);
> > >  void tipc_node_check_dest(struct net *net, u32 onode, u8 *peer_id128,
> > > --
> > > 2.13.7


_______________________________________________
tipc-discussion mailing list
tipc-discussion@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tipc-discussion

Reply via email to