From patchwork Sat Aug 29 19:41:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tuong Lien X-Patchwork-Id: 261767 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-11.3 required=3.0 tests=BAYES_00, DATE_IN_PAST_06_12, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MSGID_FROM_MTA_HEADER, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2DB29C433E2 for ; Sun, 30 Aug 2020 04:41:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E945720E65 for ; Sun, 30 Aug 2020 04:41:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=dektech.com.au header.i=@dektech.com.au header.b="grs7hcSe" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726394AbgH3ElV (ORCPT ); Sun, 30 Aug 2020 00:41:21 -0400 Received: from mail-eopbgr60101.outbound.protection.outlook.com ([40.107.6.101]:6823 "EHLO EUR04-DB3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726226AbgH3ElT (ORCPT ); Sun, 30 Aug 2020 00:41:19 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=VHuTdRehQq3Fu9sklBVrJYspkOM0rwITUmq1pmyOmJ0Fiy69asFmZSxuwb7n+noYrqioK9LIJvghb0yrLOr8D7kYpwVut0xoy39qTsgONWBz0GD/z7uVZwAoiwUH5HTNfAqqTXQow/YHns2+1k7eQ166uqNvDTvBhJSg/mhvIwRdCkzDGWTAc5U3wjIHxpwgBcDr7wCec/2fBMXk4je9K/PJfCBTI9/EylMNXqSL009sIKWHGsTjiIwr9Wvs5F/nFJJHJFaxo9sbnlGQd4bQ1yRnpo8KQXgL2C7Rd1cmYfhKsdPMhyGwN8J63VO9p2UnVeKJjjO5g/3Tz/ZHbLkpYA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=nMhyH0K6NCvV5Xicj6dXOZrN+IjydjSSfkNhTtbiVYY=; b=Imrv8lT1Sz/f1vVTRgELpRAlXu9F9ynyKcqcvxb+s0UTqm/G6osgpfLiU7DE4+C0CbZbADEszUP2DVXrrIgV+m1Prv0hA+C1B3YkZ7XJLEAFuvx+KZahEub5Xc7EqeduhjZ7f5RuYM65ASoiJUGsMu1vuyX94QArDypIPYWRGWPls4p3vI6WwH2NfihYqi9CDcGFIV9is13UbzHvVDGJNOLe/hVTrHK3SPoyZ6v3zv/OsaFGRA1eICxvGpCYhW34T27o6Y4gIjTa+qBzOv8W51O9bPCD2zu/g3eVCcxe1J72Monz2VJifoII1Cc+hG8B8EqkW3fqeiVwXNb+paW6Og== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=dektech.com.au; dmarc=pass action=none header.from=dektech.com.au; dkim=pass header.d=dektech.com.au; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dektech.com.au; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=nMhyH0K6NCvV5Xicj6dXOZrN+IjydjSSfkNhTtbiVYY=; b=grs7hcSeV07oS1thSTP/Q+lei872N6gdxWqfKScwtirFcjmw2XfoFiu9vDUiogUmuIitaFvS33smFd7H/BAJndsgLwdM6Ea8EON77Pk6X49g4tpIPJBH2L+ohS8yPqLCJKhRlaPbm96On52I86ihTx2dXAlPE9/dRGx1GxqTDd0= Authentication-Results: davemloft.net; dkim=none (message not signed) header.d=none;davemloft.net; dmarc=none action=none header.from=dektech.com.au; Received: from AM8PR05MB7332.eurprd05.prod.outlook.com (2603:10a6:20b:1db::9) by AM0PR05MB5105.eurprd05.prod.outlook.com (2603:10a6:208:f4::25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3326.23; Sun, 30 Aug 2020 04:41:08 +0000 Received: from AM8PR05MB7332.eurprd05.prod.outlook.com ([fe80::64de:d33d:e82:b902]) by AM8PR05MB7332.eurprd05.prod.outlook.com ([fe80::64de:d33d:e82:b902%7]) with mapi id 15.20.3326.025; Sun, 30 Aug 2020 04:41:08 +0000 From: Tuong Lien To: davem@davemloft.net, jmaloy@redhat.com, maloy@donjonn.com, ying.xue@windriver.com, netdev@vger.kernel.org Cc: tipc-discussion@lists.sourceforge.net Subject: [net-next 2/4] tipc: introduce encryption master key Date: Sun, 30 Aug 2020 02:41:55 +0700 Message-Id: <20200829194157.10273-3-tuong.t.lien@dektech.com.au> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200829194157.10273-1-tuong.t.lien@dektech.com.au> References: <20200829194157.10273-1-tuong.t.lien@dektech.com.au> X-ClientProxiedBy: SG2PR02CA0040.apcprd02.prod.outlook.com (2603:1096:3:18::28) To AM8PR05MB7332.eurprd05.prod.outlook.com (2603:10a6:20b:1db::9) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from dektech.com.au (14.161.14.188) by SG2PR02CA0040.apcprd02.prod.outlook.com (2603:1096:3:18::28) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3326.19 via Frontend Transport; Sun, 30 Aug 2020 04:41:05 +0000 X-Mailer: git-send-email 2.26.2 X-Originating-IP: [14.161.14.188] X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 0f6e6ee3-0b7c-4357-43a0-08d84c9ee954 X-MS-TrafficTypeDiagnostic: AM0PR05MB5105: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:331; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: WMyCOacFbG+IDzPj50UFBRxY39YnbKaT2xEceQSDaTPHOyely9pHszduA8pDRzM+fhjK62aECN23p6T+Cw4fyA3fcvCIh4kGefyTA6eGBOjTK2JrET6A6AC/t2PFFhh+hrer222zEuOy9Pr+xLVc8thogCBrDRygbFKRQKfG5SG8pHIvICwYmC2BWFQaxVz0cl5Mb/y6p8UVOpm1AGRDycQFWFQ8xH6IobYPD/r+/BeBeNiWiIo0HaDlR26kSbZbt3D4uSY1q94zD/K+ANPotMxpjnYCqCFhbNdJANyuKKD6MrS1plt9XxQW6nyEjfsZ X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:AM8PR05MB7332.eurprd05.prod.outlook.com; PTR:; CAT:NONE; SFS:(396003)(346002)(136003)(376002)(366004)(39830400003)(36756003)(86362001)(16526019)(2906002)(478600001)(26005)(186003)(6666004)(55016002)(316002)(66476007)(66556008)(66946007)(8936002)(8676002)(1076003)(956004)(2616005)(103116003)(5660300002)(52116002)(83380400001)(7696005)(30864003)(4326008); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData: MWgpoOi/VvVF8sXHZmj1cVqqHZBO1vHSknr//r4sN/2O1LOITevlUsGx1zRkJK/WhthnWk9hJ9yyfZtqAvnYDve7eMGgU4Cw5Y1lGyBLhDzU/aMpfY0WjqeiwvGIvs5QvRZYFrwwURf+O1Z8O66qn0CL2y6dbogNlRPZoainJmNjdVn8584GDz3OuiuqxLUZ5A/kNLK7J3XEho+FfC2P5IRWaRwPxBMRwVt/nNIfVIHzzmq+v18mDhrFq7uMpL52hwWhL9GgDkWVbmxTke9vi9zKpwjwpjJefPyX3GLF8JSjXxPXadzYhoNPn7Y5uJOXcr/Z3rT68jTkl2tZnYiiXVbhEohz0M4RBcxvOLvzAd9rbVwdad6HC8ATDp85y0H7nKzV2njrjtpD+JhKIuIYRqH9EpYFuUpIPkoTKOtZ75Udxyhe/4KvjDB6DKISl71QvDqDQYdfjUq3QupnGEtA4CiNaMhhF8q5Wvqsl62ek9UyRPmQrl+Bz0s7p7f5GxkV/4zE/CFl37i+4y1Tch1AdTvoq1UKhU1pgyU3zLtRn0vwZ/CvKIF9B5ieNoTjwxOU63uc9rRirAyYkEtuf4AsZ0pJ9nhW3coRI3nhYyfvqv+2gI+Lh9GLms6wighaUEh5+d6wiwAhwDbr2W1hiIp/Jw== X-OriginatorOrg: dektech.com.au X-MS-Exchange-CrossTenant-Network-Message-Id: 0f6e6ee3-0b7c-4357-43a0-08d84c9ee954 X-MS-Exchange-CrossTenant-AuthSource: AM8PR05MB7332.eurprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Aug 2020 04:41:07.9333 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 1957ea50-0dd8-4360-8db0-c9530df996b2 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: SJW9Zl9YO1PDpVJeGMhHyNz6LRVZxQNFrzW/9ut+Bp05ri23izzxbDGpJb9q6yHfgGx+Wa0IGxK7BcvmcZisANk9aw1aOlk8Zf6/ZLpwb5I= X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM0PR05MB5105 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org In addition to the supported cluster & per-node encryption keys for the en/decryption of TIPC messages, we now introduce one option for user to set a cluster key as 'master key', which is simply a symmetric key like the former but has a longer life cycle. It has two purposes: - Authentication of new member nodes in the cluster. New nodes, having no knowledge of current session keys in the cluster will still be able to join the cluster as long as they know the master key. This is because all neighbor discovery (LINK_CONFIG) messages must be encrypted with this key. - Encryption of session encryption keys during automatic exchange and update of those.This is a feature we will introduce in a later commit in this series. We insert the new key into the currently unused slot 0 in the key array and start using it immediately once the user has set it. After joining, a node only knowing the master key should be fully communicable to existing nodes in the cluster, although those nodes may have their own session keys activated (i.e. not the master one). To support this, we define a 'grace period', starting from the time a node itself reports having no RX keys, so the existing nodes will use the master key for encryption instead. The grace period can be extended but will automatically stop after e.g. 5 seconds without a new report. This is also the basis for later key exchanging feature as the new node will be impossible to decrypt anything without the support from master key. For user to set a master key, we define a new netlink flag - 'TIPC_NLA_NODE_KEY_MASTER', so it can be added to the current 'set key' netlink command to specify the setting key to be a master key. Above all, the traditional cluster/per-node key mechanism is guaranteed to work when user comes not to use this master key option. This is also compatible to legacy nodes without the feature supported. Even this master key can be updated without any interruption of cluster connectivity but is so is needed, this has to be coordinated and set by the user. Acked-by: Jon Maloy Signed-off-by: Tuong Lien --- include/uapi/linux/tipc_netlink.h | 1 + net/tipc/crypto.c | 206 ++++++++++++++++++++++-------- net/tipc/crypto.h | 15 ++- net/tipc/msg.h | 4 +- net/tipc/netlink.c | 1 + net/tipc/node.c | 46 +++---- 6 files changed, 189 insertions(+), 84 deletions(-) diff --git a/include/uapi/linux/tipc_netlink.h b/include/uapi/linux/tipc_netlink.h index dc0d23a50e69..d484baa9d365 100644 --- a/include/uapi/linux/tipc_netlink.h +++ b/include/uapi/linux/tipc_netlink.h @@ -165,6 +165,7 @@ enum { TIPC_NLA_NODE_UP, /* flag */ TIPC_NLA_NODE_ID, /* data */ TIPC_NLA_NODE_KEY, /* data */ + TIPC_NLA_NODE_KEY_MASTER, /* flag */ __TIPC_NLA_NODE_MAX, TIPC_NLA_NODE_MAX = __TIPC_NLA_NODE_MAX - 1 diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c index 53a3b34b3913..b75b817441e5 100644 --- a/net/tipc/crypto.c +++ b/net/tipc/crypto.c @@ -38,6 +38,7 @@ #include #include "crypto.h" +#define TIPC_TX_GRACE_PERIOD msecs_to_jiffies(5000) /* 5s */ #define TIPC_TX_LASTING_TIME msecs_to_jiffies(10000) /* 10s */ #define TIPC_RX_ACTIVE_LIM msecs_to_jiffies(3000) /* 3s */ #define TIPC_RX_PASSIVE_LIM msecs_to_jiffies(15000) /* 15s */ @@ -49,9 +50,9 @@ * TIPC Key ids */ enum { - KEY_UNUSED = 0, - KEY_MIN, - KEY_1 = KEY_MIN, + KEY_MASTER = 0, + KEY_MIN = KEY_MASTER, + KEY_1 = 1, KEY_2, KEY_3, KEY_MAX = KEY_3, @@ -166,27 +167,36 @@ struct tipc_crypto_stats { * @aead: array of pointers to AEAD keys for encryption/decryption * @peer_rx_active: replicated peer RX active key index * @key: the key states - * @working: the crypto is working or not * @stats: the crypto statistics * @name: the crypto name * @sndnxt: the per-peer sndnxt (TX) * @timer1: general timer 1 (jiffies) * @timer2: general timer 2 (jiffies) + * @working: the crypto is working or not + * @key_master: flag indicates if master key exists + * @legacy_user: flag indicates if a peer joins w/o master key (for bwd comp.) * @lock: tipc_key lock */ struct tipc_crypto { struct net *net; struct tipc_node *node; - struct tipc_aead __rcu *aead[KEY_MAX + 1]; /* key[0] is UNUSED */ + struct tipc_aead __rcu *aead[KEY_MAX + 1]; atomic_t peer_rx_active; struct tipc_key key; - u8 working:1; struct tipc_crypto_stats __percpu *stats; char name[48]; atomic64_t sndnxt ____cacheline_aligned; unsigned long timer1; unsigned long timer2; + union { + struct { + u8 working:1; + u8 key_master:1; + u8 legacy_user:1; + }; + u8 flags; + }; spinlock_t lock; /* crypto lock */ } ____cacheline_aligned; @@ -236,13 +246,19 @@ static inline void tipc_crypto_key_set_state(struct tipc_crypto *c, u8 new_active, u8 new_pending); static int tipc_crypto_key_attach(struct tipc_crypto *c, - struct tipc_aead *aead, u8 pos); + struct tipc_aead *aead, u8 pos, + bool master_key); static bool tipc_crypto_key_try_align(struct tipc_crypto *rx, u8 new_pending); static struct tipc_aead *tipc_crypto_key_pick_tx(struct tipc_crypto *tx, struct tipc_crypto *rx, - struct sk_buff *skb); + struct sk_buff *skb, + u8 tx_key); static void tipc_crypto_key_synch(struct tipc_crypto *rx, struct sk_buff *skb); static int tipc_crypto_key_revoke(struct net *net, u8 tx_key); +static inline void tipc_crypto_clone_msg(struct net *net, struct sk_buff *_skb, + struct tipc_bearer *b, + struct tipc_media_addr *dst, + struct tipc_node *__dnode, u8 type); static void tipc_crypto_rcv_complete(struct net *net, struct tipc_aead *aead, struct tipc_bearer *b, struct sk_buff **skb, int err); @@ -939,8 +955,6 @@ bool tipc_ehdr_validate(struct sk_buff *skb) return false; if (unlikely(skb->len <= ehsz + TIPC_AES_GCM_TAG_SIZE)) return false; - if (unlikely(!ehdr->tx_key)) - return false; return true; } @@ -993,6 +1007,8 @@ static int tipc_ehdr_build(struct net *net, struct tipc_aead *aead, ehdr->tx_key = tx_key; ehdr->destined = (__rx) ? 1 : 0; ehdr->rx_key_active = (__rx) ? __rx->key.active : 0; + ehdr->rx_nokey = (__rx) ? !__rx->key.keys : 0; + ehdr->master_key = aead->crypto->key_master; ehdr->reserved_1 = 0; ehdr->reserved_2 = 0; @@ -1035,6 +1051,7 @@ static inline void tipc_crypto_key_set_state(struct tipc_crypto *c, * @c: TIPC crypto to which new key is attached * @ukey: the user key * @mode: the key mode (CLUSTER_KEY or PER_NODE_KEY) + * @master_key: specify this is a cluster master key * * A new TIPC AEAD key will be allocated and initiated with the specified user * key, then attached to the TIPC crypto. @@ -1042,7 +1059,7 @@ static inline void tipc_crypto_key_set_state(struct tipc_crypto *c, * Return: new key id in case of success, otherwise: < 0 */ int tipc_crypto_key_init(struct tipc_crypto *c, struct tipc_aead_key *ukey, - u8 mode) + u8 mode, bool master_key) { struct tipc_aead *aead = NULL; int rc = 0; @@ -1055,7 +1072,7 @@ int tipc_crypto_key_init(struct tipc_crypto *c, struct tipc_aead_key *ukey, } /* Attach it to the crypto */ - rc = tipc_crypto_key_attach(c, aead, 0); + rc = tipc_crypto_key_attach(c, aead, 0, master_key); if (rc < 0) { pr_err("%s: unable to attach key, err %d\n", c->name, rc); tipc_aead_free(&aead->rcu); @@ -1071,11 +1088,13 @@ int tipc_crypto_key_init(struct tipc_crypto *c, struct tipc_aead_key *ukey, * @c: TIPC crypto to which the new AEAD key is attached * @aead: the new AEAD key pointer * @pos: desired slot in the crypto key array, = 0 if any! + * @master_key: specify this is a cluster master key * * Return: new key id in case of success, otherwise: -EBUSY */ static int tipc_crypto_key_attach(struct tipc_crypto *c, - struct tipc_aead *aead, u8 pos) + struct tipc_aead *aead, u8 pos, + bool master_key) { struct tipc_key key; int rc = -EBUSY; @@ -1083,6 +1102,10 @@ static int tipc_crypto_key_attach(struct tipc_crypto *c, spin_lock_bh(&c->lock); key = c->key; + if (master_key) { + new_key = KEY_MASTER; + goto attach; + } if (key.active && key.passive) goto exit; if (key.pending) { @@ -1114,8 +1137,7 @@ static int tipc_crypto_key_attach(struct tipc_crypto *c, tipc_crypto_key_set_state(c, key.passive, key.active, key.pending); c->working = 1; - c->timer1 = jiffies; - c->timer2 = jiffies; + c->key_master |= master_key; rc = new_key; exit: @@ -1128,7 +1150,7 @@ void tipc_crypto_key_flush(struct tipc_crypto *c) int k; spin_lock_bh(&c->lock); - c->working = 0; + c->flags = 0; tipc_crypto_key_set_state(c, 0, 0, 0); for (k = KEY_MIN; k <= KEY_MAX; k++) tipc_crypto_key_detach(c->aead[k], &c->lock); @@ -1204,6 +1226,7 @@ static bool tipc_crypto_key_try_align(struct tipc_crypto *rx, u8 new_pending) * @tx: TX crypto handle * @rx: RX crypto handle (can be NULL) * @skb: the message skb which will be decrypted later + * @tx_key: peer TX key id * * This function looks up the existing TX keys and pick one which is suitable * for the message decryption, that must be a cluster key and not used before @@ -1213,7 +1236,8 @@ static bool tipc_crypto_key_try_align(struct tipc_crypto *rx, u8 new_pending) */ static struct tipc_aead *tipc_crypto_key_pick_tx(struct tipc_crypto *tx, struct tipc_crypto *rx, - struct sk_buff *skb) + struct sk_buff *skb, + u8 tx_key) { struct tipc_skb_cb *skb_cb = TIPC_SKB_CB(skb); struct tipc_aead *aead = NULL; @@ -1232,6 +1256,10 @@ static struct tipc_aead *tipc_crypto_key_pick_tx(struct tipc_crypto *tx, /* Pick one TX key */ spin_lock(&tx->lock); + if (tx_key == KEY_MASTER) { + aead = tipc_aead_rcu_ptr(tx->aead[KEY_MASTER], &tx->lock); + goto done; + } do { k = (i == 0) ? key.pending : ((i == 1) ? key.active : key.passive); @@ -1251,9 +1279,12 @@ static struct tipc_aead *tipc_crypto_key_pick_tx(struct tipc_crypto *tx, skb->next = skb_clone(skb, GFP_ATOMIC); if (unlikely(!skb->next)) pr_warn("Failed to clone skb for next round if any\n"); - WARN_ON(!refcount_inc_not_zero(&aead->refcnt)); break; } while (++i < 3); + +done: + if (likely(aead)) + WARN_ON(!refcount_inc_not_zero(&aead->refcnt)); spin_unlock(&tx->lock); return aead; @@ -1268,6 +1299,9 @@ static struct tipc_aead *tipc_crypto_key_pick_tx(struct tipc_crypto *tx, * has changed, so the number of TX keys' users on this node are increased and * decreased correspondingly. * + * It also considers if peer has no key, then we need to make own master key + * (if any) taking over i.e. starting grace period. + * * The "per-peer" sndnxt is also reset when the peer key has switched. */ static void tipc_crypto_key_synch(struct tipc_crypto *rx, struct sk_buff *skb) @@ -1278,11 +1312,23 @@ static void tipc_crypto_key_synch(struct tipc_crypto *rx, struct sk_buff *skb) u32 self = tipc_own_addr(rx->net); u8 cur, new; - /* Ensure this message is destined to us first */ + /* Update RX 'key_master' flag according to peer, also mark "legacy" if + * a peer has no master key. + */ + rx->key_master = ehdr->master_key; + if (!rx->key_master) + tx->legacy_user = 1; + + /* For later cases, apply only if message is destined to this node */ if (!ehdr->destined || msg_short(hdr) || msg_destnode(hdr) != self) return; - /* Peer RX active key has changed, let's update own TX users */ + /* Case 1: Peer has no keys, let's make master key take over */ + if (ehdr->rx_nokey) + /* Set or extend grace period */ + tx->timer2 = jiffies; + + /* Case 2: Peer RX active key has changed, let's update own TX users */ cur = atomic_read(&rx->peer_rx_active); new = ehdr->rx_key_active; if (tx->key.keys && @@ -1340,7 +1386,7 @@ int tipc_crypto_start(struct tipc_crypto **crypto, struct net *net, return -ENOMEM; } - c->working = 0; + c->flags = 0; c->net = net; c->node = node; tipc_crypto_key_set_state(c, 0, 0, 0); @@ -1475,6 +1521,12 @@ void tipc_crypto_timeout(struct tipc_crypto *rx) s5: spin_unlock(&rx->lock); + /* Relax it here, the flag will be set again if it really is, but only + * when we are not in grace period for safety! + */ + if (time_after(jiffies, tx->timer2 + TIPC_TX_GRACE_PERIOD)) + tx->legacy_user = 0; + /* Limit max_tfms & do debug commands if needed */ if (likely(sysctl_tipc_max_tfms <= TIPC_MAX_TFMS_LIM)) return; @@ -1484,6 +1536,22 @@ void tipc_crypto_timeout(struct tipc_crypto *rx) tipc_crypto_do_cmd(rx->net, cmd); } +static inline void tipc_crypto_clone_msg(struct net *net, struct sk_buff *_skb, + struct tipc_bearer *b, + struct tipc_media_addr *dst, + struct tipc_node *__dnode, u8 type) +{ + struct sk_buff *skb; + + skb = skb_clone(_skb, GFP_ATOMIC); + if (skb) { + TIPC_SKB_CB(skb)->xmit_type = type; + tipc_crypto_xmit(net, &skb, b, dst, __dnode); + if (skb) + b->media->send_msg(net, skb, b, dst); + } +} + /** * tipc_crypto_xmit - Build & encrypt TIPC message for xmit * @net: struct net @@ -1493,7 +1561,8 @@ void tipc_crypto_timeout(struct tipc_crypto *rx) * @__dnode: destination node for reference if any * * First, build an encryption message header on the top of the message, then - * encrypt the original TIPC message by using the active or pending TX key. + * encrypt the original TIPC message by using the pending, master or active + * key with this preference order. * If the encryption is successful, the encrypted skb is returned directly or * via the callback. * Otherwise, the skb is freed! @@ -1516,46 +1585,63 @@ int tipc_crypto_xmit(struct net *net, struct sk_buff **skb, struct tipc_msg *hdr = buf_msg(*skb); struct tipc_key key = tx->key; struct tipc_aead *aead = NULL; - struct sk_buff *_skb; - int rc = -ENOKEY; u32 user = msg_user(hdr); - u8 tx_key; + u32 type = msg_type(hdr); + int rc = -ENOKEY; + u8 tx_key = 0; /* No encryption? */ if (!tx->working) return 0; - /* Try with the pending key if available and: - * 1) This is the only choice (i.e. no active key) or; - * 2) Peer has switched to this key (unicast only) or; - * 3) It is time to do a pending key probe; - */ + /* Pending key if peer has active on it or probing time */ if (unlikely(key.pending)) { tx_key = key.pending; - if (!key.active) + if (!tx->key_master && !key.active) goto encrypt; if (__rx && atomic_read(&__rx->peer_rx_active) == tx_key) goto encrypt; - if (TIPC_SKB_CB(*skb)->probe) { + if (TIPC_SKB_CB(*skb)->xmit_type == SKB_PROBING) { pr_debug("%s: probing for key[%d]\n", tx->name, key.pending); goto encrypt; } - if (user == LINK_CONFIG || user == LINK_PROTOCOL) { - _skb = skb_clone(*skb, GFP_ATOMIC); - if (_skb) { - TIPC_SKB_CB(_skb)->probe = 1; - tipc_crypto_xmit(net, &_skb, b, dst, __dnode); - if (_skb) - b->media->send_msg(net, _skb, b, dst); + if (user == LINK_CONFIG || user == LINK_PROTOCOL) + tipc_crypto_clone_msg(net, *skb, b, dst, __dnode, + SKB_PROBING); + } + + /* Master key if this is a *vital* message or in grace period */ + if (tx->key_master) { + tx_key = KEY_MASTER; + if (!key.active) + goto encrypt; + if (TIPC_SKB_CB(*skb)->xmit_type == SKB_GRACING) { + pr_debug("%s: gracing for msg (%d %d)\n", tx->name, + user, type); + goto encrypt; + } + if (user == LINK_CONFIG || + (user == LINK_PROTOCOL && type == RESET_MSG) || + time_before(jiffies, tx->timer2 + TIPC_TX_GRACE_PERIOD)) { + if (__rx && __rx->key_master && + !atomic_read(&__rx->peer_rx_active)) + goto encrypt; + if (!__rx) { + if (likely(!tx->legacy_user)) + goto encrypt; + tipc_crypto_clone_msg(net, *skb, b, dst, + __dnode, SKB_GRACING); } } } + /* Else, use the active key if any */ if (likely(key.active)) { tx_key = key.active; goto encrypt; } + goto exit; encrypt: @@ -1621,15 +1707,16 @@ int tipc_crypto_rcv(struct net *net, struct tipc_crypto *rx, struct tipc_aead *aead = NULL; struct tipc_key key; int rc = -ENOKEY; - u8 tx_key = 0; + u8 tx_key; + + tx_key = ((struct tipc_ehdr *)(*skb)->data)->tx_key; /* New peer? * Let's try with TX key (i.e. cluster mode) & verify the skb first! */ - if (unlikely(!rx)) + if (unlikely(!rx || tx_key == KEY_MASTER)) goto pick_tx; - tx_key = ((struct tipc_ehdr *)(*skb)->data)->tx_key; /* Pick RX key according to TX key if any */ key = rx->key; if (tx_key == key.active || tx_key == key.pending || @@ -1642,7 +1729,7 @@ int tipc_crypto_rcv(struct net *net, struct tipc_crypto *rx, pick_tx: /* No key suitable? Try to pick one from TX... */ - aead = tipc_crypto_key_pick_tx(tx, rx, *skb); + aead = tipc_crypto_key_pick_tx(tx, rx, *skb, tx_key); if (aead) goto decrypt; goto exit; @@ -1724,9 +1811,12 @@ static void tipc_crypto_rcv_complete(struct net *net, struct tipc_aead *aead, goto free_skb; } + /* Ignore cloning if it was TX master key */ + if (ehdr->tx_key == KEY_MASTER) + goto rcv; if (tipc_aead_clone(&tmp, aead) < 0) goto rcv; - if (tipc_crypto_key_attach(rx, tmp, ehdr->tx_key) < 0) { + if (tipc_crypto_key_attach(rx, tmp, ehdr->tx_key, false) < 0) { tipc_aead_free(&tmp->rcu); goto rcv; } @@ -1742,10 +1832,10 @@ static void tipc_crypto_rcv_complete(struct net *net, struct tipc_aead *aead, /* Set the RX key's user */ tipc_aead_users_set(aead, 1); -rcv: /* Mark this point, RX works */ rx->timer1 = jiffies; +rcv: /* Remove ehdr & auth. tag prior to tipc_rcv() */ ehdr = (struct tipc_ehdr *)(*skb)->data; @@ -1867,14 +1957,24 @@ static char *tipc_crypto_key_dump(struct tipc_crypto *c, char *buf) char *s; for (k = KEY_MIN; k <= KEY_MAX; k++) { - if (k == key.passive) - s = "PAS"; - else if (k == key.active) - s = "ACT"; - else if (k == key.pending) - s = "PEN"; - else - s = "-"; + if (k == KEY_MASTER) { + if (is_rx(c)) + continue; + if (time_before(jiffies, + c->timer2 + TIPC_TX_GRACE_PERIOD)) + s = "ACT"; + else + s = "PAS"; + } else { + if (k == key.passive) + s = "PAS"; + else if (k == key.active) + s = "ACT"; + else if (k == key.pending) + s = "PEN"; + else + s = "-"; + } i += scnprintf(buf + i, 200 - i, "\tKey%d: %s", k, s); rcu_read_lock(); diff --git a/net/tipc/crypto.h b/net/tipc/crypto.h index c3de769f49e8..7fcb80cb0e8a 100644 --- a/net/tipc/crypto.h +++ b/net/tipc/crypto.h @@ -74,7 +74,7 @@ extern int sysctl_tipc_max_tfms __read_mostly; * 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 * 1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * w0:|Ver=7| User |D|TX |RX |K| Rsvd | + * w0:|Ver=7| User |D|TX |RX |K|M|N| Rsvd | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * w1:| Seqno | * w2:| (8 octets) | @@ -101,6 +101,9 @@ extern int sysctl_tipc_max_tfms __read_mostly; * RX : Currently RX active key corresponding to the destination * node's TX key (when the "D" bit is set) * K : Keep-alive bit (for RPS, LINK_PROTOCOL/STATE_MSG only) + * M : Bit indicates if sender has master key + * N : Bit indicates if sender has no RX keys corresponding to the + * receiver's TX (when the "D" bit is set) * Rsvd : Reserved bit, field * Word1-2: * Seqno : The 64-bit sequence number of the encrypted message, also @@ -117,7 +120,9 @@ struct tipc_ehdr { __u8 destined:1, user:4, version:3; - __u8 reserved_1:3, + __u8 reserved_1:1, + rx_nokey:1, + master_key:1, keepalive:1, rx_key_active:2, tx_key:2; @@ -128,7 +133,9 @@ struct tipc_ehdr { __u8 tx_key:2, rx_key_active:2, keepalive:1, - reserved_1:3; + master_key:1, + rx_nokey:1, + reserved_1:1; #else #error "Please fix " #endif @@ -158,7 +165,7 @@ int tipc_crypto_xmit(struct net *net, struct sk_buff **skb, int tipc_crypto_rcv(struct net *net, struct tipc_crypto *rx, struct sk_buff **skb, struct tipc_bearer *b); int tipc_crypto_key_init(struct tipc_crypto *c, struct tipc_aead_key *ukey, - u8 mode); + u8 mode, bool master_key); void tipc_crypto_key_flush(struct tipc_crypto *c); int tipc_aead_key_validate(struct tipc_aead_key *ukey); bool tipc_ehdr_validate(struct sk_buff *skb); diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 1016e96db5c4..25e5c5c8a6ff 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -127,7 +127,9 @@ struct tipc_skb_cb { #ifdef CONFIG_TIPC_CRYPTO u8 encrypted:1; u8 decrypted:1; - u8 probe:1; +#define SKB_PROBING 1 +#define SKB_GRACING 2 + u8 xmit_type:2; u8 tx_clone_deferred:1; #endif }; diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index c4aee6247d55..1ec00fcc26ee 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c @@ -108,6 +108,7 @@ const struct nla_policy tipc_nl_node_policy[TIPC_NLA_NODE_MAX + 1] = { .len = TIPC_NODEID_LEN}, [TIPC_NLA_NODE_KEY] = { .type = NLA_BINARY, .len = TIPC_AEAD_KEY_SIZE_MAX}, + [TIPC_NLA_NODE_KEY_MASTER] = { .type = NLA_FLAG }, }; /* Properties valid for media, bearer and link */ diff --git a/net/tipc/node.c b/net/tipc/node.c index 4edcee3088da..a097eb0350dc 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -2872,11 +2872,11 @@ static int __tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info) { struct nlattr *attrs[TIPC_NLA_NODE_MAX + 1]; struct net *net = sock_net(skb->sk); - struct tipc_net *tn = tipc_net(net); + struct tipc_crypto *tx = tipc_net(net)->crypto_tx, *c = tx; struct tipc_node *n = NULL; struct tipc_aead_key *ukey; - struct tipc_crypto *c; - u8 *id, *own_id; + bool master_key = false; + u8 *id, *own_id, mode; int rc = 0; if (!info->attrs[TIPC_NLA_NODE]) @@ -2886,51 +2886,45 @@ static int __tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info) info->attrs[TIPC_NLA_NODE], tipc_nl_node_policy, info->extack); if (rc) - goto exit; + return rc; own_id = tipc_own_id(net); - if (!own_id) { - rc = -EPERM; - goto exit; - } + if (!own_id) + return -EPERM; rc = tipc_nl_retrieve_key(attrs, &ukey); if (rc) - goto exit; + return rc; rc = tipc_aead_key_validate(ukey); if (rc) - goto exit; + return rc; rc = tipc_nl_retrieve_nodeid(attrs, &id); switch (rc) { case -ENODATA: - /* Cluster key mode */ - rc = tipc_crypto_key_init(tn->crypto_tx, ukey, CLUSTER_KEY); + mode = CLUSTER_KEY; + master_key = !!(attrs[TIPC_NLA_NODE_KEY_MASTER]); break; case 0: - /* Per-node key mode */ - if (!memcmp(id, own_id, NODE_ID_LEN)) { - c = tn->crypto_tx; - } else { + mode = PER_NODE_KEY; + if (memcmp(id, own_id, NODE_ID_LEN)) { n = tipc_node_find_by_id(net, id) ?: tipc_node_create(net, 0, id, 0xffffu, 0, true); - if (unlikely(!n)) { - rc = -ENOMEM; - break; - } + if (unlikely(!n)) + return -ENOMEM; c = n->crypto_rx; } - - rc = tipc_crypto_key_init(c, ukey, PER_NODE_KEY); - if (n) - tipc_node_put(n); break; default: - break; + return rc; } -exit: + /* Initiate the TX/RX key */ + rc = tipc_crypto_key_init(c, ukey, mode, master_key); + if (n) + tipc_node_put(n); + return (rc < 0) ? rc : 0; } From patchwork Sat Aug 29 19:41:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tuong Lien X-Patchwork-Id: 261766 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-11.3 required=3.0 tests=BAYES_00, DATE_IN_PAST_06_12, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MSGID_FROM_MTA_HEADER, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 63825C433E6 for ; Sun, 30 Aug 2020 04:41:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3061120E65 for ; Sun, 30 Aug 2020 04:41:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=dektech.com.au header.i=@dektech.com.au header.b="C2uA5NOv" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726459AbgH3Elj (ORCPT ); Sun, 30 Aug 2020 00:41:39 -0400 Received: from mail-eopbgr60101.outbound.protection.outlook.com ([40.107.6.101]:6823 "EHLO EUR04-DB3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726226AbgH3Elg (ORCPT ); Sun, 30 Aug 2020 00:41:36 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=KIuFamFQ06SENFRprrjUCzctTJPElrq3Jsuer9UaG4L6nzwnhx8vaa6jZ2cAZbZgw1Q1WP3N7ix0X5+tuTNeW9ERQ7gfoETz1BAJJhs3f3atB30arz1ASNj65ubqW25cO29WcXj78puBO9GZALlKC8G/Qdo8/kocpIIN8ds29hAM8lcEp1njV5R9XuCPsD294EifYMr++aBGyoHJAr+zZUpILVg7lbl3pzYqut9FJusYgp2vXO6Susld+iZ1ZfLB250srviLvklyMBZS3/zDShtWY+FC1a1Ssxh/uCNe9DcsZQSKyRR9/q/uTbRkRUO1j8hDTu4dxEjAfy0/UPYUvg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=xzbFH+FMae0G20CT0ek7jXUQxthEO8y5esXNDNE+DZ4=; b=fYL1nGtLRdFjzkQ2FcBGljXAi4xDtclFYn3CgvSpIWx0PQO+iGEuR867E/vbAunQ9WClmb4xe4ouxOzLA2P/LAJygN/YjTJrk3eSDNy4I6zVveSDqAawDYpgPK7LlFzMYXprmdG+fczWRGh5hwF+RKdOAnc5A0mAhRoe+bkOtHcFFfEqA5wpwe2iI0oM+n9oIFmWR55KQZQaCLyBTB3iv3sIdJURfPDKzHivrov8JXgW+0NEqDrXj7X7aIBXWGGebDFCNMlat43R+cpQHw5XizOWBPoSqCQBPxu8Y14sOSNvhR8qkcR+nvIO9gX1o5jU5dxbwEwORIfEu3gJPNqVGQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=dektech.com.au; dmarc=pass action=none header.from=dektech.com.au; dkim=pass header.d=dektech.com.au; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dektech.com.au; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=xzbFH+FMae0G20CT0ek7jXUQxthEO8y5esXNDNE+DZ4=; b=C2uA5NOvGi6Vn9gM361PJ7ZU0WVYTo6+OGz7hO0LQHmB3Vp7B7v2dsDHYWlFNkynltHCKH4MRjAdy+aKMizVinXfU11B+ydSInhW4pZoKcYeX1d6qfsEcjeN3AGqL06SR8mekb02vxZjct1yWCQQ3SF2LLjK6YZp0R9iNlLe0S0= Authentication-Results: davemloft.net; dkim=none (message not signed) header.d=none;davemloft.net; dmarc=none action=none header.from=dektech.com.au; Received: from AM8PR05MB7332.eurprd05.prod.outlook.com (2603:10a6:20b:1db::9) by AM0PR05MB5105.eurprd05.prod.outlook.com (2603:10a6:208:f4::25) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3326.23; Sun, 30 Aug 2020 04:41:12 +0000 Received: from AM8PR05MB7332.eurprd05.prod.outlook.com ([fe80::64de:d33d:e82:b902]) by AM8PR05MB7332.eurprd05.prod.outlook.com ([fe80::64de:d33d:e82:b902%7]) with mapi id 15.20.3326.025; Sun, 30 Aug 2020 04:41:12 +0000 From: Tuong Lien To: davem@davemloft.net, jmaloy@redhat.com, maloy@donjonn.com, ying.xue@windriver.com, netdev@vger.kernel.org Cc: tipc-discussion@lists.sourceforge.net Subject: [net-next 4/4] tipc: add automatic rekeying for encryption key Date: Sun, 30 Aug 2020 02:41:57 +0700 Message-Id: <20200829194157.10273-5-tuong.t.lien@dektech.com.au> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200829194157.10273-1-tuong.t.lien@dektech.com.au> References: <20200829194157.10273-1-tuong.t.lien@dektech.com.au> X-ClientProxiedBy: SG2PR02CA0040.apcprd02.prod.outlook.com (2603:1096:3:18::28) To AM8PR05MB7332.eurprd05.prod.outlook.com (2603:10a6:20b:1db::9) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from dektech.com.au (14.161.14.188) by SG2PR02CA0040.apcprd02.prod.outlook.com (2603:1096:3:18::28) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3326.19 via Frontend Transport; Sun, 30 Aug 2020 04:41:10 +0000 X-Mailer: git-send-email 2.26.2 X-Originating-IP: [14.161.14.188] X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: f92f755d-4aca-4f76-bf34-08d84c9eec1e X-MS-TrafficTypeDiagnostic: AM0PR05MB5105: X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:1775; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: gLyACjZy8y7KzXM9nPfFaHdIGV0Islz0scQGlqhabgNbb/wEi+j8FN9Oq83Xcnmih1/cTdMXDBuGrTlI+ayIyrlFFHTTUeIzskcKdaF51LpUbyBriRjfZAkXZq/CiKG117DZTw2oS9/DOYSAlfFjXb7a+KV1j7ifLuefjTD0YTc369L4DpNN6uriQpE5R/8uvU+uUgFY0fUifyZ0Ty0vdyTj82UqlQ1idG0X99uan3WMoInmjvydSM8w6DHA8xAH1pydi4D2f3/SDz5UGH/63c2t/F0lwIMs/TuANIfSM4H+Mfld+hUTKCV4VToxHWBfxltpKGmew7A26ztBN9OnRw== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:AM8PR05MB7332.eurprd05.prod.outlook.com; PTR:; CAT:NONE; SFS:(396003)(346002)(136003)(376002)(366004)(39830400003)(36756003)(86362001)(16526019)(2906002)(478600001)(26005)(186003)(6666004)(55016002)(316002)(66476007)(66556008)(66946007)(8936002)(8676002)(1076003)(956004)(2616005)(103116003)(5660300002)(52116002)(83380400001)(7696005)(30864003)(4326008); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData: kCpEltdIC6Rvv3DS8IZADFbOcMb3WhP78oCC13+JeK8Y1VQBFcIDUH5UEuR/xXIpTtCStvTSAWBsYP0oekoK3Xah1Qd0jHSK9SQMo3H4YgfrbcGdOjtCRK5NFGXHwsJXwzB7hAXqEFiIOuqOxlL5+JiIu2zMJeVfXX19Hb6kI3DSZnF0EMY2pr0hL9x3yyQZ4EaDtxbp9deF3XUVwb2jlxPqBI9jcQn2JGA/s8LYvKhgUsJg9OKlcrSaNxm9jy6Pigiqo3TYAjrpGLOVxEDhG+PYXFAPVGUMqN8iudWaLxzJJWzHR9sx38Jhikl2ncTC4V3c3ODVWK4hU05euW9a4eN2gZaLTIxv5+IEiA2OPofWxV0+Nmxu7GLJOfwticIH/M/sVpLD0ushI2sPNGdSQI4jl4bu2B81q1MFr9TzAVIC7Hq5aI5yFLMdwJh0DNmpKc69bP3eZr0MXfMahNox3AhQrrohga2Ba630ngQv/oAxWnUVQzeCGi2lXZpqmb45BKwiNYpzuBWOUR5bR1XzapSmeuI/Ys5PqOJuuYI0AVp5Q0DDNtuKFkP+MNRYcpFwQPV52xJkMNeQc+VfRZOBY6GEd3BWQbdY+foMEudIqz9Z5VKoH5gPxiewuL6BYGh8pEzkfig532pa5bUEeL0bNw== X-OriginatorOrg: dektech.com.au X-MS-Exchange-CrossTenant-Network-Message-Id: f92f755d-4aca-4f76-bf34-08d84c9eec1e X-MS-Exchange-CrossTenant-AuthSource: AM8PR05MB7332.eurprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Aug 2020 04:41:12.5943 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 1957ea50-0dd8-4360-8db0-c9530df996b2 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: zmgU4UWSwRvx2zRI/KyKJwudHvYHGLFzUbE15iY1ePooDDtBoN31NcegO1ZOaYjMIlQ3URO40QWEbq7YobVjhW7gpAW4F3PuwykTttKABLk= X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM0PR05MB5105 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 Signed-off-by: Tuong Lien --- include/uapi/linux/tipc.h | 2 + include/uapi/linux/tipc_netlink.h | 1 + net/tipc/crypto.c | 115 +++++++++++++++++++++++++++++- net/tipc/crypto.h | 2 + net/tipc/netlink.c | 1 + net/tipc/node.c | 28 +++++++- 6 files changed, 146 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/tipc.h b/include/uapi/linux/tipc.h index add01db1daef..80ea15e12113 100644 --- a/include/uapi/linux/tipc.h +++ b/include/uapi/linux/tipc.h @@ -254,6 +254,8 @@ static inline int tipc_aead_key_size(struct tipc_aead_key *key) return sizeof(*key) + key->keylen; } +#define TIPC_REKEYING_NOW (~0U) + /* The macros and functions below are deprecated: */ diff --git a/include/uapi/linux/tipc_netlink.h b/include/uapi/linux/tipc_netlink.h index d484baa9d365..d847dd671d79 100644 --- a/include/uapi/linux/tipc_netlink.h +++ b/include/uapi/linux/tipc_netlink.h @@ -166,6 +166,7 @@ enum { TIPC_NLA_NODE_ID, /* data */ TIPC_NLA_NODE_KEY, /* data */ TIPC_NLA_NODE_KEY_MASTER, /* flag */ + TIPC_NLA_NODE_REKEYING, /* u32 */ __TIPC_NLA_NODE_MAX, TIPC_NLA_NODE_MAX = __TIPC_NLA_NODE_MAX - 1 diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c index d29266a9d2ee..9d4ad832572f 100644 --- a/net/tipc/crypto.c +++ b/net/tipc/crypto.c @@ -36,6 +36,7 @@ #include #include +#include #include "crypto.h" #include "msg.h" #include "bcast.h" @@ -48,6 +49,8 @@ #define TIPC_MAX_TFMS_DEF 10 #define TIPC_MAX_TFMS_LIM 1000 +#define TIPC_REKEYING_INTV_DEF (60 * 24) /* default: 1 day */ + /** * TIPC Key ids */ @@ -181,6 +184,7 @@ struct tipc_crypto_stats { * @wq: common workqueue on TX crypto * @work: delayed work sched for TX/RX * @key_distr: key distributing state + * @rekeying_intv: rekeying interval (in minutes) * @stats: the crypto statistics * @name: the crypto name * @sndnxt: the per-peer sndnxt (TX) @@ -206,6 +210,7 @@ struct tipc_crypto { #define KEY_DISTR_SCHED 1 #define KEY_DISTR_COMPL 2 atomic_t key_distr; + u32 rekeying_intv; struct tipc_crypto_stats __percpu *stats; char name[48]; @@ -294,7 +299,9 @@ static char *tipc_key_change_dump(struct tipc_key old, struct tipc_key new, static int tipc_crypto_key_xmit(struct net *net, struct tipc_aead_key *skey, u16 gen, u8 mode, u32 dnode); static bool tipc_crypto_key_rcv(struct tipc_crypto *rx, struct tipc_msg *hdr); +static void tipc_crypto_work_tx(struct work_struct *work); static void tipc_crypto_work_rx(struct work_struct *work); +static int tipc_aead_key_generate(struct tipc_aead_key *skey); #define is_tx(crypto) (!(crypto)->node) #define is_rx(crypto) (!is_tx(crypto)) @@ -342,6 +349,27 @@ int tipc_aead_key_validate(struct tipc_aead_key *ukey) return 0; } +/** + * tipc_aead_key_generate - Generate new session key + * @skey: input/output key with new content + * + * Return: 0 in case of success, otherwise < 0 + */ +static int tipc_aead_key_generate(struct tipc_aead_key *skey) +{ + int rc = 0; + + /* Fill the key's content with a random value via RNG cipher */ + rc = crypto_get_default_rng(); + if (likely(!rc)) { + rc = crypto_rng_get_bytes(crypto_default_rng, skey->key, + skey->keylen); + crypto_put_default_rng(); + } + + return rc; +} + static struct tipc_aead *tipc_aead_get(struct tipc_aead __rcu *aead) { struct tipc_aead *tmp; @@ -1473,6 +1501,7 @@ int tipc_crypto_start(struct tipc_crypto **crypto, struct net *net, atomic64_set(&c->sndnxt, 0); c->timer1 = jiffies; c->timer2 = jiffies; + c->rekeying_intv = TIPC_REKEYING_INTV_DEF; spin_lock_init(&c->lock); scnprintf(c->name, 48, "%s(%s)", (is_rx(c)) ? "RX" : "TX", (is_rx(c)) ? tipc_node_get_id_str(c->node) : @@ -1480,6 +1509,8 @@ int tipc_crypto_start(struct tipc_crypto **crypto, struct net *net, if (is_rx(c)) INIT_DELAYED_WORK(&c->work, tipc_crypto_work_rx); + else + INIT_DELAYED_WORK(&c->work, tipc_crypto_work_tx); *crypto = c; return 0; @@ -1494,8 +1525,11 @@ void tipc_crypto_stop(struct tipc_crypto **crypto) return; /* Flush any queued works & destroy wq */ - if (is_tx(c)) + if (is_tx(c)) { + c->rekeying_intv = 0; + cancel_delayed_work_sync(&c->work); destroy_workqueue(c->wq); + } /* Release AEAD keys */ rcu_read_lock(); @@ -2348,3 +2382,82 @@ static void tipc_crypto_work_rx(struct work_struct *work) tipc_node_put(rx->node); } + +/** + * tipc_crypto_rekeying_sched - (Re)schedule rekeying w/o new interval + * @tx: TX crypto + * @changed: if the rekeying needs to be rescheduled with new interval + * @new_intv: new rekeying interval (when "changed" = true) + */ +void tipc_crypto_rekeying_sched(struct tipc_crypto *tx, bool changed, + u32 new_intv) +{ + unsigned long delay; + bool now = false; + + if (changed) { + if (new_intv == TIPC_REKEYING_NOW) + now = true; + else + tx->rekeying_intv = new_intv; + cancel_delayed_work_sync(&tx->work); + } + + if (tx->rekeying_intv || now) { + delay = (now) ? 0 : tx->rekeying_intv * 60 * 1000; + queue_delayed_work(tx->wq, &tx->work, msecs_to_jiffies(delay)); + } +} + +/** + * tipc_crypto_work_tx - Scheduled TX works handler + * @work: the struct TX work + * + * The function processes the previous scheduled work, i.e. key rekeying, by + * generating a new session key based on current one, then attaching it to the + * TX crypto and finally distributing it to peers. It also re-schedules the + * rekeying if needed. + */ +static void tipc_crypto_work_tx(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct tipc_crypto *tx = container_of(dwork, struct tipc_crypto, work); + struct tipc_aead_key *skey = NULL; + struct tipc_key key = tx->key; + struct tipc_aead *aead; + int rc = -ENOMEM; + + if (unlikely(key.pending)) + goto resched; + + /* Take current key as a template */ + rcu_read_lock(); + aead = rcu_dereference(tx->aead[key.active ?: KEY_MASTER]); + if (unlikely(!aead)) { + rcu_read_unlock(); + /* At least one key should exist for securing */ + return; + } + + /* Lets duplicate it first */ + skey = kmemdup(aead->key, tipc_aead_key_size(aead->key), GFP_ATOMIC); + rcu_read_unlock(); + + /* Now, generate new key, initiate & distribute it */ + if (likely(skey)) { + rc = tipc_aead_key_generate(skey) ?: + tipc_crypto_key_init(tx, skey, PER_NODE_KEY, false); + if (likely(rc > 0)) + rc = tipc_crypto_key_distr(tx, rc, NULL); + kzfree(skey); + } + + if (likely(!rc)) + pr_info("%s: rekeying has been done\n", tx->name); + else + pr_warn_ratelimited("%s: rekeying returns %d\n", tx->name, rc); + +resched: + /* Re-schedule rekeying if any */ + tipc_crypto_rekeying_sched(tx, false, 0); +} diff --git a/net/tipc/crypto.h b/net/tipc/crypto.h index 70bda3d7e174..e1f4e8fb5c10 100644 --- a/net/tipc/crypto.h +++ b/net/tipc/crypto.h @@ -171,6 +171,8 @@ void tipc_crypto_key_flush(struct tipc_crypto *c); int tipc_crypto_key_distr(struct tipc_crypto *tx, u8 key, struct tipc_node *dest); void tipc_crypto_msg_rcv(struct net *net, struct sk_buff *skb); +void tipc_crypto_rekeying_sched(struct tipc_crypto *tx, bool changed, + u32 new_intv); int tipc_aead_key_validate(struct tipc_aead_key *ukey); bool tipc_ehdr_validate(struct sk_buff *skb); diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index 1ec00fcc26ee..c447cb5f879e 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c @@ -109,6 +109,7 @@ const struct nla_policy tipc_nl_node_policy[TIPC_NLA_NODE_MAX + 1] = { [TIPC_NLA_NODE_KEY] = { .type = NLA_BINARY, .len = TIPC_AEAD_KEY_SIZE_MAX}, [TIPC_NLA_NODE_KEY_MASTER] = { .type = NLA_FLAG }, + [TIPC_NLA_NODE_REKEYING] = { .type = NLA_U32 }, }; /* Properties valid for media, bearer and link */ diff --git a/net/tipc/node.c b/net/tipc/node.c index 4f822a5d82d8..c981ef2ad410 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -2877,6 +2877,17 @@ static int tipc_nl_retrieve_nodeid(struct nlattr **attrs, u8 **node_id) return 0; } +static int tipc_nl_retrieve_rekeying(struct nlattr **attrs, u32 *intv) +{ + struct nlattr *attr = attrs[TIPC_NLA_NODE_REKEYING]; + + if (!attr) + return -ENODATA; + + *intv = nla_get_u32(attr); + return 0; +} + static int __tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info) { struct nlattr *attrs[TIPC_NLA_NODE_MAX + 1]; @@ -2884,8 +2895,9 @@ static int __tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info) struct tipc_crypto *tx = tipc_net(net)->crypto_tx, *c = tx; struct tipc_node *n = NULL; struct tipc_aead_key *ukey; - bool master_key = false; + bool rekeying = true, master_key = false; u8 *id, *own_id, mode; + u32 intv = 0; int rc = 0; if (!info->attrs[TIPC_NLA_NODE]) @@ -2901,9 +2913,17 @@ static int __tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info) if (!own_id) return -EPERM; + rc = tipc_nl_retrieve_rekeying(attrs, &intv); + if (rc == -ENODATA) + rekeying = false; + rc = tipc_nl_retrieve_key(attrs, &ukey); - if (rc) + if (rc == -ENODATA && rekeying) { + rc = 0; + goto rekeying; + } else if (rc) { return rc; + } rc = tipc_aead_key_validate(ukey); if (rc) @@ -2938,6 +2958,10 @@ static int __tipc_nl_node_set_key(struct sk_buff *skb, struct genl_info *info) if (!master_key) tipc_crypto_key_distr(tx, rc, NULL); +rekeying: + /* Schedule TX rekeying if needed */ + tipc_crypto_rekeying_sched(tx, rekeying, intv); + exit: if (n) tipc_node_put(n);