public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
From: Chuck Lever <cel@kernel.org>
To: Trond Myklebust <trondmy@kernel.org>,
	Anna Schumaker <anna@kernel.org>,
	 Chuck Lever <chuck.lever@oracle.com>,
	Jeff Layton <jlayton@kernel.org>,  NeilBrown <neil@brown.name>,
	Olga Kornievskaia <okorniev@redhat.com>,
	 Dai Ngo <Dai.Ngo@oracle.com>, Tom Talpey <tom@talpey.com>,
	 "David S. Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	 Jakub Kicinski <kuba@kernel.org>,
	Paolo Abeni <pabeni@redhat.com>,  Simon Horman <horms@kernel.org>
Cc: linux-nfs@vger.kernel.org, netdev@vger.kernel.org,
	 linux-kernel@vger.kernel.org,
	Herbert Xu <herbert@gondor.apana.org.au>,
	 David Howells <dhowells@redhat.com>,
	Simo Sorce <simo@redhat.com>
Subject: [PATCH 09/18] SUNRPC: Switch MIC token generation to crypto/krb5
Date: Mon, 27 Apr 2026 09:50:53 -0400	[thread overview]
Message-ID: <20260427-crypto-krb5-api-v1-9-1fc1253b64c0@oracle.com> (raw)
In-Reply-To: <20260427-crypto-krb5-api-v1-0-1fc1253b64c0@oracle.com>

From: Chuck Lever <chuck.lever@oracle.com>

gss_krb5_get_mic_v2() currently computes the MIC checksum by
driving a crypto_ahash directly, calling gss_krb5_checksum()
with the message body and GSS token header. Replace this with
a call to crypto_krb5_get_mic(), which performs the same keyed
hash operation through the crypto/krb5 library.

RFC 4121 Section 4.2.4 specifies that the checksum covers the
message body followed by the token header. Because the
crypto/krb5 metadata parameter is hashed before the data, the
GSS header cannot be passed as metadata. Instead, the header
is appended to the scatterlist after the body data, producing
the correct hash input ordering without using the metadata
parameter.

The scatterlist layout is:
  [checksum_output | message_body | gss_header]

The first scatterlist entry points directly into the
token buffer, so the checksum is written in place.

A shared helper, gss_krb5_mic_build_sg(), is introduced in
gss_krb5_crypto.c to construct this scatterlist layout. The
helper handles overflow allocation and scatterlist chaining
for large xdr_buf page arrays. It is reused by the verify_mic
counterpart in the following commit.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 net/sunrpc/auth_gss/gss_krb5_crypto.c   | 82 +++++++++++++++++++++++++++++++++
 net/sunrpc/auth_gss/gss_krb5_internal.h |  6 +++
 net/sunrpc/auth_gss/gss_krb5_seal.c     | 45 +++++++++++++-----
 3 files changed, 121 insertions(+), 12 deletions(-)

diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 31c2c86b873f..3a8e6710a51b 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -1103,3 +1103,85 @@ gss_krb5_aead_decrypt(struct krb5_ctx *kctx, u32 offset, u32 len,
 	*tailskip = sec_len - data_offset - data_len;
 	return GSS_S_COMPLETE;
 }
+
+/**
+ * gss_krb5_mic_build_sg - Build scatterlist for MIC token operations
+ * @body: xdr_buf containing the message body
+ * @cksum: pointer to checksum area in the token buffer
+ * @cksum_len: length of checksum area
+ * @hdr: pointer to GSS token header
+ * @sg_head: caller-provided scatterlist array; if more than
+ *	XDR_BUF_TO_SG_NENTS entries are needed, an overflow
+ *	scatterlist is allocated and chained automatically
+ * @sg_overflow: OUT: overflow scatterlist, caller must kfree
+ *
+ * Per RFC 4121 Section 4.2.4, MIC token checksums cover the
+ * message body followed by the token header. The checksum
+ * output or received checksum occupies the first scatterlist
+ * entry.  This layout cannot be constructed by
+ * xdr_buf_to_sg_alloc() because the checksum area and the GSS
+ * header lie outside the xdr_buf.
+ *
+ * Returns the number of scatterlist entries on success, or a
+ * negative errno on failure.
+ */
+int gss_krb5_mic_build_sg(const struct xdr_buf *body,
+			  void *cksum, unsigned int cksum_len,
+			  void *hdr,
+			  struct scatterlist *sg_head,
+			  struct scatterlist **sg_overflow)
+{
+	struct scatterlist *entry;
+	int body_max, body_nsg, nsg;
+
+	*sg_overflow = NULL;
+
+	body_max = 2;
+	if (body->page_len)
+		body_max += DIV_ROUND_UP(body->page_len +
+					 offset_in_page(body->page_base),
+					 PAGE_SIZE);
+	nsg = 1 + body_max + 1;
+	if (nsg <= XDR_BUF_TO_SG_NENTS) {
+		sg_init_table(sg_head, nsg);
+	} else {
+		unsigned int overflow_nents =
+			nsg - XDR_BUF_TO_SG_NENTS + 1;
+
+		*sg_overflow = kmalloc_array(overflow_nents,
+					     sizeof(**sg_overflow),
+					     GFP_NOFS);
+		if (!*sg_overflow)
+			return -ENOMEM;
+
+		sg_init_table(sg_head, XDR_BUF_TO_SG_NENTS);
+		sg_init_table(*sg_overflow, overflow_nents);
+		sg_chain(sg_head, XDR_BUF_TO_SG_NENTS, *sg_overflow);
+	}
+
+	sg_set_buf(&sg_head[0], cksum, cksum_len);
+	body_nsg = xdr_buf_to_sg(body, 0, body->len,
+				 sg_next(&sg_head[0]), body_max);
+	if (body_nsg < 0)
+		goto out_err;
+
+	/*
+	 * xdr_buf_to_sg marks the last body entry as end-of-list;
+	 * clear it so the trailing header entry is reachable.
+	 */
+	if (body_nsg > 0) {
+		entry = sg_last(sg_next(&sg_head[0]), body_nsg);
+		sg_unmark_end(entry);
+		entry = sg_next(entry);
+	} else {
+		entry = sg_next(&sg_head[0]);
+	}
+	sg_set_buf(entry, hdr, GSS_KRB5_TOK_HDR_LEN);
+	sg_mark_end(entry);
+	return 1 + body_nsg + 1;
+
+out_err:
+	kfree(*sg_overflow);
+	*sg_overflow = NULL;
+	return body_nsg;
+}
diff --git a/net/sunrpc/auth_gss/gss_krb5_internal.h b/net/sunrpc/auth_gss/gss_krb5_internal.h
index ce43e1be7577..83e969494b54 100644
--- a/net/sunrpc/auth_gss/gss_krb5_internal.h
+++ b/net/sunrpc/auth_gss/gss_krb5_internal.h
@@ -186,6 +186,12 @@ u32 krb5_etm_decrypt(struct krb5_ctx *kctx, u32 offset, u32 len,
 
 u32 gss_krb5_errno_to_status(int err);
 
+int gss_krb5_mic_build_sg(const struct xdr_buf *body,
+			  void *cksum, unsigned int cksum_len,
+			  void *hdr,
+			  struct scatterlist *sg_head,
+			  struct scatterlist **sg_overflow);
+
 u32 gss_krb5_aead_encrypt(struct krb5_ctx *kctx, u32 offset,
 			  struct xdr_buf *buf, struct page **pages);
 u32 gss_krb5_aead_decrypt(struct krb5_ctx *kctx, u32 offset, u32 len,
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index ce540df9bce4..66c179337029 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -64,6 +64,8 @@
 #include <linux/random.h>
 #include <linux/crypto.h>
 #include <linux/atomic.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
 
 #include "gss_krb5_internal.h"
 
@@ -78,10 +80,10 @@ setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token)
 	void *krb5_hdr;
 	u8 *p, flags = 0x00;
 
-	if ((ctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0)
-		flags |= 0x01;
+	if (!ctx->initiate)
+		flags |= KG2_TOKEN_FLAG_SENTBYACCEPTOR;
 	if (ctx->flags & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY)
-		flags |= 0x04;
+		flags |= KG2_TOKEN_FLAG_ACCEPTORSUBKEY;
 
 	/* Per rfc 4121, sec 4.2.6.1, there is no header,
 	 * just start the token.
@@ -97,7 +99,7 @@ setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token)
 	*ptr++ = 0xffff;
 	*ptr = 0xffff;
 
-	token->len = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength;
+	token->len = GSS_KRB5_TOK_HDR_LEN + ctx->krb5e->cksum_len;
 	return krb5_hdr;
 }
 
@@ -105,14 +107,17 @@ u32
 gss_krb5_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
 		    struct xdr_netobj *token)
 {
-	struct crypto_ahash *tfm = ctx->initiate ?
-				   ctx->initiator_sign : ctx->acceptor_sign;
-	struct xdr_netobj cksumobj = {
-		.len =	ctx->gk5e->cksumlength,
-	};
+	const struct krb5_enctype *krb5 = ctx->krb5e;
+	struct crypto_shash *shash = ctx->initiate ?
+		ctx->initiator_sign_shash : ctx->acceptor_sign_shash;
+	unsigned int cksum_len = krb5->cksum_len;
+	struct scatterlist sg_head[XDR_BUF_TO_SG_NENTS];
+	struct scatterlist *sg_overflow;
 	__be64 seq_send_be64;
 	void *krb5_hdr;
 	time64_t now;
+	ssize_t ret;
+	int nsg;
 
 	dprintk("RPC:       %s\n", __func__);
 
@@ -123,9 +128,25 @@ gss_krb5_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
 	seq_send_be64 = cpu_to_be64(atomic64_fetch_inc(&ctx->seq_send64));
 	memcpy(krb5_hdr + 8, (char *) &seq_send_be64, 8);
 
-	cksumobj.data = krb5_hdr + GSS_KRB5_TOK_HDR_LEN;
-	if (gss_krb5_checksum(tfm, krb5_hdr, GSS_KRB5_TOK_HDR_LEN,
-			      text, 0, &cksumobj))
+	/*
+	 * The checksum is written directly into the token buffer.
+	 * This is safe: crypto_krb5_get_mic uses shash (software
+	 * hash), so the scatterlist is never DMA-mapped.
+	 */
+	nsg = gss_krb5_mic_build_sg(text,
+				    krb5_hdr + GSS_KRB5_TOK_HDR_LEN,
+				    cksum_len, krb5_hdr,
+				    sg_head, &sg_overflow);
+	if (nsg < 0)
+		return GSS_S_FAILURE;
+
+	ret = crypto_krb5_get_mic(krb5, shash, NULL, sg_head, nsg,
+				  cksum_len + text->len +
+					GSS_KRB5_TOK_HDR_LEN,
+				  cksum_len,
+				  text->len + GSS_KRB5_TOK_HDR_LEN);
+	kfree(sg_overflow);
+	if (ret < 0)
 		return GSS_S_FAILURE;
 
 	now = ktime_get_real_seconds();

-- 
2.53.0


  parent reply	other threads:[~2026-04-27 13:51 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-27 13:50 [PATCH 00/18] Migrate rpcsec_gss_krb5 to the crypto/krb5 library Chuck Lever
2026-04-27 13:50 ` [PATCH 01/18] SUNRPC: Add Kconfig dependency on CRYPTO_KRB5 Chuck Lever
2026-04-27 13:50 ` [PATCH 02/18] SUNRPC: Add crypto/krb5 enctype lookup to krb5_ctx Chuck Lever
2026-04-27 13:50 ` [PATCH 03/18] SUNRPC: Add helpers to convert xdr_buf byte ranges to scatterlists Chuck Lever
2026-04-27 13:50 ` [PATCH 04/18] SUNRPC: Add errno-to-GSS status conversion helper Chuck Lever
2026-04-27 13:50 ` [PATCH 05/18] SUNRPC: Prepare crypto/krb5 encryption and checksum handles Chuck Lever
2026-04-27 13:50 ` [PATCH 06/18] SUNRPC: Switch wrap token encryption to crypto/krb5 Chuck Lever
2026-04-27 13:50 ` [PATCH 07/18] SUNRPC: Switch wrap token decryption " Chuck Lever
2026-04-27 13:50 ` [PATCH 08/18] SUNRPC: Switch Camellia decrypt " Chuck Lever
2026-04-27 13:50 ` Chuck Lever [this message]
2026-04-27 13:50 ` [PATCH 10/18] SUNRPC: Switch MIC token verification " Chuck Lever
2026-04-27 13:50 ` [PATCH 11/18] SUNRPC: Remove get_mic/verify_mic function pointers from enctype table Chuck Lever
2026-04-27 13:50 ` [PATCH 12/18] SUNRPC: Remove wrap/unwrap " Chuck Lever
2026-04-27 13:50 ` [PATCH 13/18] SUNRPC: Remove encrypt/decrypt " Chuck Lever
2026-04-27 13:50 ` [PATCH 14/18] SUNRPC: Remove legacy skcipher/ahash handles from krb5_ctx Chuck Lever
2026-04-27 13:50 ` [PATCH 15/18] SUNRPC: Remove dead code from rpcsec_gss_krb5 Chuck Lever
2026-04-27 13:51 ` [PATCH 16/18] SUNRPC: Remove per-enctype Kconfig options Chuck Lever
2026-04-27 13:51 ` [PATCH 17/18] SUNRPC: Remove redundant crypto Kconfig dependencies Chuck Lever
2026-04-27 13:51 ` [PATCH 18/18] SUNRPC: Remove dead rpcsec_gss_krb5 definitions Chuck Lever
2026-04-29  6:39 ` [PATCH 00/18] Migrate rpcsec_gss_krb5 to the crypto/krb5 library Jeff Layton
2026-04-29 15:17   ` Chuck Lever

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=20260427-crypto-krb5-api-v1-9-1fc1253b64c0@oracle.com \
    --to=cel@kernel.org \
    --cc=Dai.Ngo@oracle.com \
    --cc=anna@kernel.org \
    --cc=chuck.lever@oracle.com \
    --cc=davem@davemloft.net \
    --cc=dhowells@redhat.com \
    --cc=edumazet@google.com \
    --cc=herbert@gondor.apana.org.au \
    --cc=horms@kernel.org \
    --cc=jlayton@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=neil@brown.name \
    --cc=netdev@vger.kernel.org \
    --cc=okorniev@redhat.com \
    --cc=pabeni@redhat.com \
    --cc=simo@redhat.com \
    --cc=tom@talpey.com \
    --cc=trondmy@kernel.org \
    /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