Commit fc1b6d6d authored by Tuong Lien's avatar Tuong Lien Committed by David S. Miller
Browse files

tipc: introduce TIPC encryption & authentication



This commit offers an option to encrypt and authenticate all messaging,
including the neighbor discovery messages. The currently most advanced
algorithm supported is the AEAD AES-GCM (like IPSec or TLS). All
encryption/decryption is done at the bearer layer, just before leaving
or after entering TIPC.

Supported features:
- Encryption & authentication of all TIPC messages (header + data);
- Two symmetric-key modes: Cluster and Per-node;
- Automatic key switching;
- Key-expired revoking (sequence number wrapped);
- Lock-free encryption/decryption (RCU);
- Asynchronous crypto, Intel AES-NI supported;
- Multiple cipher transforms;
- Logs & statistics;

Two key modes:
- Cluster key mode: One single key is used for both TX & RX in all
nodes in the cluster.
- Per-node key mode: Each nodes in the cluster has one specific TX key.
For RX, a node requires its peers' TX key to be able to decrypt the
messages from those peers.

Key setting from user-space is performed via netlink by a user program
(e.g. the iproute2 'tipc' tool).

Internal key state machine:

                                 Attach    Align(RX)
                                     +-+   +-+
                                     | V   | V
        +---------+      Attach     +---------+
        |  IDLE   |---------------->| PENDING |(user = 0)
        +---------+                 +---------+
           A   A                   Switch|  A
           |   |                         |  |
           |   | Free(switch/revoked)    |  |
     (Free)|   +----------------------+  |  |Timeout
           |              (TX)        |  |  |(RX)
           |                          |  |  |
           |                          |  v  |
        +---------+      Switch     +---------+
        | PASSIVE |<----------------| ACTIVE  |
        +---------+       (RX)      +---------+
        (user = 1)                  (user >= 1)

The number of TFMs is 10 by default and can be changed via the procfs
'net/tipc/max_tfms'. At this moment, as for simplicity, this file is
also used to print the crypto statistics at runtime:

echo 0xfff1 > /proc/sys/net/tipc/max_tfms

The patch defines a new TIPC version (v7) for the encryption message (-
backward compatibility as well). The message is basically encapsulated
as follows:

   +----------------------------------------------------------+
   | TIPCv7 encryption  | Original TIPCv2    | Authentication |
   | header             | packet (encrypted) | Tag            |
   +----------------------------------------------------------+

The throughput is about ~40% for small messages (compared with non-
encryption) and ~9% for large messages. With the support from hardware
crypto i.e. the Intel AES-NI CPU instructions, the throughput increases
upto ~85% for small messages and ~55% for large messages.

By default, the new feature is inactive (i.e. no encryption) until user
sets a key for TIPC. There is however also a new option - "TIPC_CRYPTO"
in the kernel configuration to enable/disable the new code when needed.

MAINTAINERS | add two new files 'crypto.h' & 'crypto.c' in tipc

Acked-by: default avatarYing Xue <ying.xue@windreiver.com>
Acked-by: default avatarJon Maloy <jon.maloy@ericsson.com>
Signed-off-by: default avatarTuong Lien <tuong.t.lien@dektech.com.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 134bdac3
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -35,6 +35,21 @@ config TIPC_MEDIA_UDP
	  Saying Y here will enable support for running TIPC over IP/UDP
	bool
	default y
config TIPC_CRYPTO
	bool "TIPC encryption support"
	depends on TIPC
	select CRYPTO
	select CRYPTO_AES
	select CRYPTO_GCM
	help
	  Saying Y here will enable support for TIPC encryption.
	  All TIPC messages will be encrypted/decrypted by using the currently most
	  advanced algorithm: AEAD AES-GCM (like IPSec or TLS) before leaving/
	  entering the TIPC stack.
	  Key setting from user-space is performed via netlink by a user program
	  (e.g. the iproute2 'tipc' tool).
	bool
	default y

config TIPC_DIAG
	tristate "TIPC: socket monitoring interface"
+1 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ CFLAGS_trace.o += -I$(src)
tipc-$(CONFIG_TIPC_MEDIA_UDP)	+= udp_media.o
tipc-$(CONFIG_TIPC_MEDIA_IB)	+= ib_media.o
tipc-$(CONFIG_SYSCTL)		+= sysctl.o
tipc-$(CONFIG_TIPC_CRYPTO)	+= crypto.o


obj-$(CONFIG_TIPC_DIAG)	+= diag.o
+1 −1
Original line number Diff line number Diff line
@@ -84,7 +84,7 @@ static struct tipc_bc_base *tipc_bc_base(struct net *net)
 */
int tipc_bcast_get_mtu(struct net *net)
{
	return tipc_link_mtu(tipc_bc_sndlink(net)) - INT_H_SIZE;
	return tipc_link_mss(tipc_bc_sndlink(net));
}

void tipc_bcast_disable_rcast(struct net *net)
+27 −8
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@
#include "netlink.h"
#include "udp_media.h"
#include "trace.h"
#include "crypto.h"

#define MAX_ADDR_STR 60

@@ -516,10 +517,15 @@ void tipc_bearer_xmit_skb(struct net *net, u32 bearer_id,

	rcu_read_lock();
	b = bearer_get(net, bearer_id);
	if (likely(b && (test_bit(0, &b->up) || msg_is_reset(hdr))))
	if (likely(b && (test_bit(0, &b->up) || msg_is_reset(hdr)))) {
#ifdef CONFIG_TIPC_CRYPTO
		tipc_crypto_xmit(net, &skb, b, dest, NULL);
		if (skb)
#endif
			b->media->send_msg(net, skb, b, dest);
	else
	} else {
		kfree_skb(skb);
	}
	rcu_read_unlock();
}

@@ -527,7 +533,8 @@ void tipc_bearer_xmit_skb(struct net *net, u32 bearer_id,
 */
void tipc_bearer_xmit(struct net *net, u32 bearer_id,
		      struct sk_buff_head *xmitq,
		      struct tipc_media_addr *dst)
		      struct tipc_media_addr *dst,
		      struct tipc_node *__dnode)
{
	struct tipc_bearer *b;
	struct sk_buff *skb, *tmp;
@@ -541,11 +548,16 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id,
		__skb_queue_purge(xmitq);
	skb_queue_walk_safe(xmitq, skb, tmp) {
		__skb_dequeue(xmitq);
		if (likely(test_bit(0, &b->up) || msg_is_reset(buf_msg(skb))))
		if (likely(test_bit(0, &b->up) || msg_is_reset(buf_msg(skb)))) {
#ifdef CONFIG_TIPC_CRYPTO
			tipc_crypto_xmit(net, &skb, b, dst, __dnode);
			if (skb)
#endif
				b->media->send_msg(net, skb, b, dst);
		else
		} else {
			kfree_skb(skb);
		}
	}
	rcu_read_unlock();
}

@@ -555,6 +567,7 @@ void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,
			 struct sk_buff_head *xmitq)
{
	struct tipc_net *tn = tipc_net(net);
	struct tipc_media_addr *dst;
	int net_id = tn->net_id;
	struct tipc_bearer *b;
	struct sk_buff *skb, *tmp;
@@ -569,7 +582,12 @@ void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,
		msg_set_non_seq(hdr, 1);
		msg_set_mc_netid(hdr, net_id);
		__skb_dequeue(xmitq);
		b->media->send_msg(net, skb, b, &b->bcast_addr);
		dst = &b->bcast_addr;
#ifdef CONFIG_TIPC_CRYPTO
		tipc_crypto_xmit(net, &skb, b, dst, NULL);
		if (skb)
#endif
			b->media->send_msg(net, skb, b, dst);
	}
	rcu_read_unlock();
}
@@ -596,6 +614,7 @@ static int tipc_l2_rcv_msg(struct sk_buff *skb, struct net_device *dev,
	if (likely(b && test_bit(0, &b->up) &&
		   (skb->pkt_type <= PACKET_MULTICAST))) {
		skb_mark_not_on_list(skb);
		TIPC_SKB_CB(skb)->flags = 0;
		tipc_rcv(dev_net(b->pt.dev), skb, b);
		rcu_read_unlock();
		return NET_RX_SUCCESS;
+2 −1
Original line number Diff line number Diff line
@@ -232,7 +232,8 @@ void tipc_bearer_xmit_skb(struct net *net, u32 bearer_id,
			  struct tipc_media_addr *dest);
void tipc_bearer_xmit(struct net *net, u32 bearer_id,
		      struct sk_buff_head *xmitq,
		      struct tipc_media_addr *dst);
		      struct tipc_media_addr *dst,
		      struct tipc_node *__dnode);
void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,
			 struct sk_buff_head *xmitq);
void tipc_clone_to_loopback(struct net *net, struct sk_buff_head *pkts);
Loading