Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tipc: add automatic rekeying for encryption key

Rekeying is required for security since a key is less secure when using
for a long time. Also, key will be detached when its nonce value (or
seqno ...) is exhausted. We now make the rekeying process automatic and
configurable by user.

Basically, TIPC will at a specific interval generate a new key by using
the kernel 'Random Number Generator' cipher, then attach it as the node
TX key and securely distribute to others in the cluster as RX keys (-
the key exchange). The automatic key switching will then take over, and
make the new key active shortly. Afterwards, the traffic from this node
will be encrypted with the new session key. The same can happen in peer
nodes but not necessarily at the same time.

For simplicity, the automatically generated key will be initiated as a
per node key. It is not too hard to also support a cluster key rekeying
(e.g. a given node will generate a unique cluster key and update to the
others in the cluster...), but that doesn't bring much benefit, while a
per-node key is even more secure.

We also enable user to force a rekeying or change the rekeying interval
via netlink, the new 'set key' command option: 'TIPC_NLA_NODE_REKEYING'
is added for these purposes as follows:
- A value >= 1 will be set as the rekeying interval (in minutes);
- A value of 0 will disable the rekeying;
- A value of 'TIPC_REKEYING_NOW' (~0) will force an immediate rekeying;

The default rekeying interval is (60 * 24) minutes i.e. done every day.
There isn't any restriction for the value but user shouldn't set it too
small or too large which results in an "ineffective" rekeying (thats ok
for testing though).

Acked-by: Jon Maloy <jmaloy@redhat.com>
Signed-off-by: Tuong Lien <tuong.t.lien@dektech.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Tuong Lien and committed by
David S. Miller
23700da2 1ef6f7c9

+141 -3
+2
include/uapi/linux/tipc.h
··· 254 254 return sizeof(*key) + key->keylen; 255 255 } 256 256 257 + #define TIPC_REKEYING_NOW (~0U) 258 + 257 259 /* The macros and functions below are deprecated: 258 260 */ 259 261
+1
include/uapi/linux/tipc_netlink.h
··· 166 166 TIPC_NLA_NODE_ID, /* data */ 167 167 TIPC_NLA_NODE_KEY, /* data */ 168 168 TIPC_NLA_NODE_KEY_MASTER, /* flag */ 169 + TIPC_NLA_NODE_REKEYING, /* u32 */ 169 170 170 171 __TIPC_NLA_NODE_MAX, 171 172 TIPC_NLA_NODE_MAX = __TIPC_NLA_NODE_MAX - 1
+112 -1
net/tipc/crypto.c
··· 36 36 37 37 #include <crypto/aead.h> 38 38 #include <crypto/aes.h> 39 + #include <crypto/rng.h> 39 40 #include "crypto.h" 40 41 #include "msg.h" 41 42 #include "bcast.h" ··· 48 47 49 48 #define TIPC_MAX_TFMS_DEF 10 50 49 #define TIPC_MAX_TFMS_LIM 1000 50 + 51 + #define TIPC_REKEYING_INTV_DEF (60 * 24) /* default: 1 day */ 51 52 52 53 /** 53 54 * TIPC Key ids ··· 184 181 * @wq: common workqueue on TX crypto 185 182 * @work: delayed work sched for TX/RX 186 183 * @key_distr: key distributing state 184 + * @rekeying_intv: rekeying interval (in minutes) 187 185 * @stats: the crypto statistics 188 186 * @name: the crypto name 189 187 * @sndnxt: the per-peer sndnxt (TX) ··· 210 206 #define KEY_DISTR_SCHED 1 211 207 #define KEY_DISTR_COMPL 2 212 208 atomic_t key_distr; 209 + u32 rekeying_intv; 213 210 214 211 struct tipc_crypto_stats __percpu *stats; 215 212 char name[48]; ··· 299 294 static int tipc_crypto_key_xmit(struct net *net, struct tipc_aead_key *skey, 300 295 u16 gen, u8 mode, u32 dnode); 301 296 static bool tipc_crypto_key_rcv(struct tipc_crypto *rx, struct tipc_msg *hdr); 297 + static void tipc_crypto_work_tx(struct work_struct *work); 302 298 static void tipc_crypto_work_rx(struct work_struct *work); 299 + static int tipc_aead_key_generate(struct tipc_aead_key *skey); 303 300 304 301 #define is_tx(crypto) (!(crypto)->node) 305 302 #define is_rx(crypto) (!is_tx(crypto)) ··· 351 344 } 352 345 353 346 return 0; 347 + } 348 + 349 + /** 350 + * tipc_aead_key_generate - Generate new session key 351 + * @skey: input/output key with new content 352 + * 353 + * Return: 0 in case of success, otherwise < 0 354 + */ 355 + static int tipc_aead_key_generate(struct tipc_aead_key *skey) 356 + { 357 + int rc = 0; 358 + 359 + /* Fill the key's content with a random value via RNG cipher */ 360 + rc = crypto_get_default_rng(); 361 + if (likely(!rc)) { 362 + rc = crypto_rng_get_bytes(crypto_default_rng, skey->key, 363 + skey->keylen); 364 + crypto_put_default_rng(); 365 + } 366 + 367 + return rc; 354 368 } 355 369 356 370 static struct tipc_aead *tipc_aead_get(struct tipc_aead __rcu *aead) ··· 1499 1471 atomic64_set(&c->sndnxt, 0); 1500 1472 c->timer1 = jiffies; 1501 1473 c->timer2 = jiffies; 1474 + c->rekeying_intv = TIPC_REKEYING_INTV_DEF; 1502 1475 spin_lock_init(&c->lock); 1503 1476 scnprintf(c->name, 48, "%s(%s)", (is_rx(c)) ? "RX" : "TX", 1504 1477 (is_rx(c)) ? tipc_node_get_id_str(c->node) : ··· 1507 1478 1508 1479 if (is_rx(c)) 1509 1480 INIT_DELAYED_WORK(&c->work, tipc_crypto_work_rx); 1481 + else 1482 + INIT_DELAYED_WORK(&c->work, tipc_crypto_work_tx); 1510 1483 1511 1484 *crypto = c; 1512 1485 return 0; ··· 1523 1492 return; 1524 1493 1525 1494 /* Flush any queued works & destroy wq */ 1526 - if (is_tx(c)) 1495 + if (is_tx(c)) { 1496 + c->rekeying_intv = 0; 1497 + cancel_delayed_work_sync(&c->work); 1527 1498 destroy_workqueue(c->wq); 1499 + } 1528 1500 1529 1501 /* Release AEAD keys */ 1530 1502 rcu_read_lock(); ··· 2384 2350 return; 2385 2351 2386 2352 tipc_node_put(rx->node); 2353 + } 2354 + 2355 + /** 2356 + * tipc_crypto_rekeying_sched - (Re)schedule rekeying w/o new interval 2357 + * @tx: TX crypto 2358 + * @changed: if the rekeying needs to be rescheduled with new interval 2359 + * @new_intv: new rekeying interval (when "changed" = true) 2360 + */ 2361 + void tipc_crypto_rekeying_sched(struct tipc_crypto *tx, bool changed, 2362 + u32 new_intv) 2363 + { 2364 + unsigned long delay; 2365 + bool now = false; 2366 + 2367 + if (changed) { 2368 + if (new_intv == TIPC_REKEYING_NOW) 2369 + now = true; 2370 + else 2371 + tx->rekeying_intv = new_intv; 2372 + cancel_delayed_work_sync(&tx->work); 2373 + } 2374 + 2375 + if (tx->rekeying_intv || now) { 2376 + delay = (now) ? 0 : tx->rekeying_intv * 60 * 1000; 2377 + queue_delayed_work(tx->wq, &tx->work, msecs_to_jiffies(delay)); 2378 + } 2379 + } 2380 + 2381 + /** 2382 + * tipc_crypto_work_tx - Scheduled TX works handler 2383 + * @work: the struct TX work 2384 + * 2385 + * The function processes the previous scheduled work, i.e. key rekeying, by 2386 + * generating a new session key based on current one, then attaching it to the 2387 + * TX crypto and finally distributing it to peers. It also re-schedules the 2388 + * rekeying if needed. 2389 + */ 2390 + static void tipc_crypto_work_tx(struct work_struct *work) 2391 + { 2392 + struct delayed_work *dwork = to_delayed_work(work); 2393 + struct tipc_crypto *tx = container_of(dwork, struct tipc_crypto, work); 2394 + struct tipc_aead_key *skey = NULL; 2395 + struct tipc_key key = tx->key; 2396 + struct tipc_aead *aead; 2397 + int rc = -ENOMEM; 2398 + 2399 + if (unlikely(key.pending)) 2400 + goto resched; 2401 + 2402 + /* Take current key as a template */ 2403 + rcu_read_lock(); 2404 + aead = rcu_dereference(tx->aead[key.active ?: KEY_MASTER]); 2405 + if (unlikely(!aead)) { 2406 + rcu_read_unlock(); 2407 + /* At least one key should exist for securing */ 2408 + return; 2409 + } 2410 + 2411 + /* Lets duplicate it first */ 2412 + skey = kmemdup(aead->key, tipc_aead_key_size(aead->key), GFP_ATOMIC); 2413 + rcu_read_unlock(); 2414 + 2415 + /* Now, generate new key, initiate & distribute it */ 2416 + if (likely(skey)) { 2417 + rc = tipc_aead_key_generate(skey) ?: 2418 + tipc_crypto_key_init(tx, skey, PER_NODE_KEY, false); 2419 + if (likely(rc > 0)) 2420 + rc = tipc_crypto_key_distr(tx, rc, NULL); 2421 + kzfree(skey); 2422 + } 2423 + 2424 + if (unlikely(rc)) 2425 + pr_warn_ratelimited("%s: rekeying returns %d\n", tx->name, rc); 2426 + 2427 + resched: 2428 + /* Re-schedule rekeying if any */ 2429 + tipc_crypto_rekeying_sched(tx, false, 0); 2387 2430 }
+2
net/tipc/crypto.h
··· 171 171 int tipc_crypto_key_distr(struct tipc_crypto *tx, u8 key, 172 172 struct tipc_node *dest); 173 173 void tipc_crypto_msg_rcv(struct net *net, struct sk_buff *skb); 174 + void tipc_crypto_rekeying_sched(struct tipc_crypto *tx, bool changed, 175 + u32 new_intv); 174 176 int tipc_aead_key_validate(struct tipc_aead_key *ukey, struct genl_info *info); 175 177 bool tipc_ehdr_validate(struct sk_buff *skb); 176 178
+1
net/tipc/netlink.c
··· 109 109 [TIPC_NLA_NODE_KEY] = { .type = NLA_BINARY, 110 110 .len = TIPC_AEAD_KEY_SIZE_MAX}, 111 111 [TIPC_NLA_NODE_KEY_MASTER] = { .type = NLA_FLAG }, 112 + [TIPC_NLA_NODE_REKEYING] = { .type = NLA_U32 }, 112 113 }; 113 114 114 115 /* Properties valid for media, bearer and link */
+23 -2
net/tipc/node.c
··· 2879 2879 return 0; 2880 2880 } 2881 2881 2882 + static int tipc_nl_retrieve_rekeying(struct nlattr **attrs, u32 *intv) 2883 + { 2884 + struct nlattr *attr = attrs[TIPC_NLA_NODE_REKEYING]; 2885 + 2886 + if (!attr) 2887 + return -ENODATA; 2888 + 2889 + *intv = nla_get_u32(attr); 2890 + return 0; 2891 + } 2892 + 2882 2893 static int __tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info) 2883 2894 { 2884 2895 struct nlattr *attrs[TIPC_NLA_NODE_MAX + 1]; ··· 2897 2886 struct tipc_crypto *tx = tipc_net(net)->crypto_tx, *c = tx; 2898 2887 struct tipc_node *n = NULL; 2899 2888 struct tipc_aead_key *ukey; 2900 - bool master_key = false; 2889 + bool rekeying = true, master_key = false; 2901 2890 u8 *id, *own_id, mode; 2891 + u32 intv = 0; 2902 2892 int rc = 0; 2903 2893 2904 2894 if (!info->attrs[TIPC_NLA_NODE]) ··· 2917 2905 return -EPERM; 2918 2906 } 2919 2907 2908 + rc = tipc_nl_retrieve_rekeying(attrs, &intv); 2909 + if (rc == -ENODATA) 2910 + rekeying = false; 2911 + 2920 2912 rc = tipc_nl_retrieve_key(attrs, &ukey); 2921 - if (rc) 2913 + if (rc == -ENODATA && rekeying) 2914 + goto rekeying; 2915 + else if (rc) 2922 2916 return rc; 2923 2917 2924 2918 rc = tipc_aead_key_validate(ukey, info); ··· 2963 2945 /* Distribute TX key but not master one */ 2964 2946 if (!master_key && tipc_crypto_key_distr(tx, rc, NULL)) 2965 2947 GENL_SET_ERR_MSG(info, "failed to replicate new key"); 2948 + rekeying: 2949 + /* Schedule TX rekeying if needed */ 2950 + tipc_crypto_rekeying_sched(tx, rekeying, intv); 2966 2951 } 2967 2952 2968 2953 return 0;