From: David Howells <dhowells@redhat.com>
To: netdev@vger.kernel.org, Herbert Xu <herbert@gondor.apana.org.au>
Cc: David Howells <dhowells@redhat.com>,
Marc Dionne <marc.dionne@auristor.com>,
Jakub Kicinski <kuba@kernel.org>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Paolo Abeni <pabeni@redhat.com>, Simon Horman <horms@kernel.org>,
Trond Myklebust <trond.myklebust@hammerspace.com>,
Chuck Lever <chuck.lever@oracle.com>,
Eric Biggers <ebiggers@kernel.org>,
Ard Biesheuvel <ardb@kernel.org>,
linux-crypto@vger.kernel.org, linux-afs@lists.infradead.org,
linux-nfs@vger.kernel.org, linux-fsdevel@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH net 24/24] rxrpc: rxgk: Implement connection rekeying
Date: Mon, 3 Feb 2025 14:23:40 +0000 [thread overview]
Message-ID: <20250203142343.248839-25-dhowells@redhat.com> (raw)
In-Reply-To: <20250203142343.248839-1-dhowells@redhat.com>
Implement rekeying of connections with the RxGK security class. This
involves regenerating the keys with a different key number as part of the
input data after a certain amount of time or a certain amount of bytes
encrypted. Rekeying may be triggered by either end.
The LSW of the key number is inserted into the security-specific field in
the RX header, and we try and expand it to 32-bits to make it last longer.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: "David S. Miller" <davem@davemloft.net>
cc: Chuck Lever <chuck.lever@oracle.com>
cc: Eric Dumazet <edumazet@google.com>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: linux-crypto@vger.kernel.org
cc: netdev@vger.kernel.org
---
net/rxrpc/ar-internal.h | 5 +-
net/rxrpc/conn_object.c | 1 +
net/rxrpc/rxgk.c | 156 ++++++++++++++++++++++++++++++++++++++--
3 files changed, 155 insertions(+), 7 deletions(-)
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 7d5a28c8131d..d44883570f0b 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -553,12 +553,15 @@ struct rxrpc_connection {
u32 nonce; /* response re-use preventer */
} rxkad;
struct {
- struct rxgk_context *keys[1];
+ struct rxgk_context *keys[4]; /* (Re-)keying buffer */
u64 start_time; /* The start time for TK derivation */
u8 nonce[20]; /* Response re-use preventer */
+ u32 key_number; /* Current key number */
} rxgk;
};
+ rwlock_t security_use_lock; /* Security use/modification lock */
struct sk_buff *tx_response; /* Response packet to be transmitted */
+
unsigned long flags;
unsigned long events;
unsigned long idle_timestamp; /* Time at which last became idle */
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c
index f1e36cba9f4c..6733a7692443 100644
--- a/net/rxrpc/conn_object.c
+++ b/net/rxrpc/conn_object.c
@@ -73,6 +73,7 @@ struct rxrpc_connection *rxrpc_alloc_connection(struct rxrpc_net *rxnet,
skb_queue_head_init(&conn->rx_queue);
conn->rxnet = rxnet;
conn->security = &rxrpc_no_security;
+ rwlock_init(&conn->security_use_lock);
spin_lock_init(&conn->state_lock);
conn->debug_id = atomic_inc_return(&rxrpc_debug_id);
conn->idle_timestamp = jiffies;
diff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c
index d8f15e145a82..76847cdf323d 100644
--- a/net/rxrpc/rxgk.c
+++ b/net/rxrpc/rxgk.c
@@ -76,11 +76,153 @@ static void rxgk_describe_server_key(const struct key *key, struct seq_file *m)
seq_printf(m, ": %s", krb5->name);
}
+/*
+ * Handle rekeying the connection when we see our limits overrun or when the
+ * far side decided to rekey.
+ *
+ * Returns a ref on the context if successful or -ESTALE if the key is out of
+ * date.
+ */
+static struct rxgk_context *rxgk_rekey(struct rxrpc_connection *conn,
+ const u16 *specific_key_number)
+{
+ struct rxgk_context *gk, *dead = NULL;
+ unsigned int key_number, current_key, mask = ARRAY_SIZE(conn->rxgk.keys) - 1;
+ bool crank = false;
+
+ _enter("%d", specific_key_number ? *specific_key_number : -1);
+
+ mutex_lock(&conn->security_lock);
+
+ current_key = conn->rxgk.key_number;
+ if (!specific_key_number) {
+ key_number = current_key;
+ } else {
+ if (*specific_key_number == (u16)current_key)
+ key_number = current_key;
+ else if (*specific_key_number == (u16)(current_key - 1))
+ key_number = current_key - 1;
+ else if (*specific_key_number == (u16)(current_key + 1))
+ goto crank_window;
+ else
+ goto bad_key;
+ }
+
+ gk = conn->rxgk.keys[key_number & mask];
+ if (!gk)
+ goto generate_key;
+ if (!specific_key_number &&
+ test_bit(RXGK_TK_NEEDS_REKEY, &gk->flags))
+ goto crank_window;
+
+grab:
+ refcount_inc(&gk->usage);
+ mutex_unlock(&conn->security_lock);
+ rxgk_put(dead);
+ return gk;
+
+crank_window:
+ if (current_key == UINT_MAX)
+ goto bad_key;
+ if (current_key + 1 == UINT_MAX)
+ set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
+
+ key_number = current_key + 1;
+ if (WARN_ON(conn->rxgk.keys[key_number & mask]))
+ goto bad_key;
+ crank = true;
+
+generate_key:
+ gk = conn->rxgk.keys[current_key & mask];
+ gk = rxgk_generate_transport_key(conn, gk->key, key_number, GFP_NOFS);
+ if (IS_ERR(gk)) {
+ mutex_unlock(&conn->security_lock);
+ return gk;
+ }
+
+ write_lock(&conn->security_use_lock);
+ if (crank) {
+ current_key++;
+ conn->rxgk.key_number = current_key;
+ dead = conn->rxgk.keys[(current_key - 2) & mask];
+ conn->rxgk.keys[(current_key - 2) & mask] = NULL;
+ }
+ conn->rxgk.keys[current_key & mask] = gk;
+ write_unlock(&conn->security_use_lock);
+ goto grab;
+
+bad_key:
+ mutex_unlock(&conn->security_lock);
+ return ERR_PTR(-ESTALE);
+}
+
+/*
+ * Get the specified keying context.
+ *
+ * Returns a ref on the context if successful or -ESTALE if the key is out of
+ * date.
+ */
static struct rxgk_context *rxgk_get_key(struct rxrpc_connection *conn,
- u16 *specific_key_number)
+ const u16 *specific_key_number)
{
- refcount_inc(&conn->rxgk.keys[0]->usage);
- return conn->rxgk.keys[0];
+ struct rxgk_context *gk;
+ unsigned int key_number, current_key, mask = ARRAY_SIZE(conn->rxgk.keys) - 1;
+
+ _enter("{%u},%d",
+ conn->rxgk.key_number, specific_key_number ? *specific_key_number : -1);
+
+ read_lock(&conn->security_use_lock);
+
+ current_key = conn->rxgk.key_number;
+ if (!specific_key_number) {
+ key_number = current_key;
+ } else {
+ /* Only the bottom 16 bits of the key number are exposed in the
+ * header, so we try and keep the upper 16 bits in step. The
+ * whole 32 bits are used to generate the TK.
+ */
+ if (*specific_key_number == (u16)current_key)
+ key_number = current_key;
+ else if (*specific_key_number == (u16)(current_key - 1))
+ key_number = current_key - 1;
+ else if (*specific_key_number == (u16)(current_key + 1))
+ goto rekey;
+ else
+ goto bad_key;
+ }
+
+ gk = conn->rxgk.keys[key_number & mask];
+ if (!gk)
+ goto slow_path;
+ if (!specific_key_number &&
+ key_number < UINT_MAX) {
+ if (time_after(jiffies, gk->expiry) ||
+ gk->bytes_remaining < 0) {
+ set_bit(RXGK_TK_NEEDS_REKEY, &gk->flags);
+ goto slow_path;
+ }
+
+ if (test_bit(RXGK_TK_NEEDS_REKEY, &gk->flags))
+ goto slow_path;
+ }
+
+ refcount_inc(&gk->usage);
+ read_unlock(&conn->security_use_lock);
+ return gk;
+
+rekey:
+ _debug("rekey");
+ if (current_key == UINT_MAX)
+ goto bad_key;
+ gk = conn->rxgk.keys[current_key & mask];
+ if (gk)
+ set_bit(RXGK_TK_NEEDS_REKEY, &gk->flags);
+slow_path:
+ read_unlock(&conn->security_use_lock);
+ return rxgk_rekey(conn, specific_key_number);
+bad_key:
+ read_unlock(&conn->security_use_lock);
+ return ERR_PTR(-ESTALE);
}
/*
@@ -92,7 +234,8 @@ static int rxgk_init_connection_security(struct rxrpc_connection *conn,
struct rxgk_context *gk;
int ret;
- _enter("{%d},{%x}", conn->debug_id, key_serial(conn->key));
+ _enter("{%d,%u},{%x}",
+ conn->debug_id, conn->rxgk.key_number, key_serial(conn->key));
conn->security_ix = token->security_index;
conn->security_level = token->rxgk->level;
@@ -102,10 +245,11 @@ static int rxgk_init_connection_security(struct rxrpc_connection *conn,
do_div(conn->rxgk.start_time, 100);
}
- gk = rxgk_generate_transport_key(conn, token->rxgk, 0, GFP_NOFS);
+ gk = rxgk_generate_transport_key(conn, token->rxgk, conn->rxgk.key_number,
+ GFP_NOFS);
if (IS_ERR(gk))
return PTR_ERR(gk);
- conn->rxgk.keys[0] = gk;
+ conn->rxgk.keys[gk->key_number & 3] = gk;
switch (conn->security_level) {
case RXRPC_SECURITY_PLAIN:
next prev parent reply other threads:[~2025-02-03 14:26 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-03 14:23 [PATCH net 00/24] net/rxrpc, crypto: Add Kerberos crypto lib and AF_RXRPC GSSAPI security class David Howells
2025-02-03 14:23 ` [PATCH net 01/24] crypto/krb5: Add API Documentation David Howells
2025-02-03 14:23 ` [PATCH net 02/24] crypto/krb5: Add some constants out of sunrpc headers David Howells
2025-02-03 14:23 ` [PATCH net 03/24] crypto: Add 'krb5enc' hash and cipher AEAD algorithm David Howells
2025-02-07 8:56 ` Herbert Xu
2025-02-09 17:53 ` David Howells
2025-02-07 20:04 ` Eric Biggers
2025-02-09 18:37 ` David Howells
2025-02-09 19:05 ` Eric Biggers
2025-02-10 8:10 ` Herbert Xu
2025-03-18 10:51 ` Geert Uytterhoeven
2025-03-18 11:09 ` David Howells
2025-02-03 14:23 ` [PATCH net 04/24] crypto/krb5: Test manager data David Howells
2025-02-03 14:23 ` [PATCH net 05/24] crypto/krb5: Implement Kerberos crypto core David Howells
2025-02-03 14:23 ` [PATCH net 06/24] crypto/krb5: Add an API to query the layout of the crypto section David Howells
2025-02-03 14:23 ` [PATCH net 07/24] crypto/krb5: Add an API to alloc and prepare a crypto object David Howells
2025-02-03 14:23 ` [PATCH net 08/24] crypto/krb5: Add an API to perform requests David Howells
2025-02-03 14:23 ` [PATCH net 09/24] crypto/krb5: Provide infrastructure and key derivation David Howells
2025-02-03 14:23 ` [PATCH net 10/24] crypto/krb5: Implement the Kerberos5 rfc3961 " David Howells
2025-02-03 14:23 ` [PATCH net 11/24] crypto/krb5: Provide RFC3961 setkey packaging functions David Howells
2025-02-03 14:23 ` [PATCH net 12/24] crypto/krb5: Implement the Kerberos5 rfc3961 encrypt and decrypt functions David Howells
2025-02-03 14:23 ` [PATCH net 13/24] crypto/krb5: Implement the Kerberos5 rfc3961 get_mic and verify_mic David Howells
2025-02-03 14:23 ` [PATCH net 14/24] crypto/krb5: Implement the AES enctypes from rfc3962 David Howells
2025-02-03 14:23 ` [PATCH net 15/24] crypto/krb5: Implement the AES enctypes from rfc8009 David Howells
2025-02-03 14:23 ` [PATCH net 16/24] crypto/krb5: Implement the Camellia enctypes from rfc6803 David Howells
2025-02-03 14:23 ` [PATCH net 17/24] crypto/krb5: Implement crypto self-testing David Howells
2025-02-03 14:23 ` [PATCH net 18/24] rxrpc: Pull out certain app callback funcs into an ops table David Howells
2025-02-03 14:23 ` [PATCH net 19/24] rxrpc: Pass CHALLENGE packets to the call for recvmsg() to respond to David Howells
2025-02-03 14:23 ` [PATCH net 20/24] rxrpc: Add the security index for yfs-rxgk David Howells
2025-02-06 9:54 ` Jeffrey Altman
2025-02-03 14:23 ` [PATCH net 21/24] rxrpc: Add YFS RxGK (GSSAPI) security class David Howells
2025-02-03 14:23 ` [PATCH net 22/24] rxrpc: rxgk: Provide infrastructure and key derivation David Howells
2025-02-03 14:23 ` [PATCH net 23/24] rxrpc: rxgk: Implement the yfs-rxgk security class (GSSAPI) David Howells
2025-02-03 14:23 ` David Howells [this message]
2025-02-03 14:51 ` [PATCH net 00/24] net/rxrpc, crypto: Add Kerberos crypto lib and AF_RXRPC GSSAPI security class David Howells
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250203142343.248839-25-dhowells@redhat.com \
--to=dhowells@redhat.com \
--cc=ardb@kernel.org \
--cc=chuck.lever@oracle.com \
--cc=davem@davemloft.net \
--cc=ebiggers@kernel.org \
--cc=edumazet@google.com \
--cc=herbert@gondor.apana.org.au \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-afs@lists.infradead.org \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=marc.dionne@auristor.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=trond.myklebust@hammerspace.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox