SUNRPC: Switch MIC token verification to crypto/krb5

gss_krb5_verify_mic_v2() currently recomputes a checksum using
gss_krb5_checksum() and then compares it against the received
checksum with memcmp(). Replace this with a call to
crypto_krb5_verify_mic(), which performs the hash, comparison,
and offset/length adjustment in a single operation through the
crypto/krb5 library.

The scatterlist layout required by RFC 4121 Section 4.2.4 is
constructed via gss_krb5_mic_build_sg(), the shared helper
introduced in the preceding commit. The received checksum
occupies the first scatterlist entry, pointing directly into
the token buffer.

The errno result from crypto_krb5_verify_mic() is mapped to a
GSS major status code via gss_krb5_errno_to_status(), which
returns GSS_S_BAD_SIG for -EBADMSG (checksum mismatch).

Assisted-by: Claude:claude-opus-4-6
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Acked-by: Anna Schumaker <anna.schumaker@hammerspace.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
Chuck Lever 2026-04-27 09:50:54 -04:00 committed by Chuck Lever
parent a9b9eb0858
commit d4f6bd01c5

View File

@ -60,6 +60,8 @@
#include <linux/types.h>
#include <linux/jiffies.h>
#include <linux/sunrpc/gss_krb5.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include "gss_krb5_internal.h"
@ -71,18 +73,19 @@ u32
gss_krb5_verify_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *message_buffer,
struct xdr_netobj *read_token)
{
struct crypto_ahash *tfm = ctx->initiate ?
ctx->acceptor_sign : ctx->initiator_sign;
char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
struct xdr_netobj cksumobj = {
.len = ctx->gk5e->cksumlength,
.data = cksumdata,
};
const struct krb5_enctype *krb5 = ctx->krb5e;
struct crypto_shash *shash = ctx->initiate ?
ctx->acceptor_sign_shash : ctx->initiator_sign_shash;
unsigned int cksum_len = krb5->cksum_len;
struct scatterlist sg_head[XDR_BUF_TO_SG_NENTS];
struct scatterlist *sg_overflow;
size_t mic_offset, mic_len;
u8 *ptr = read_token->data;
__be16 be16_ptr;
time64_t now;
u8 flags;
int i;
int nsg, i;
int ret;
dprintk("RPC: %s\n", __func__);
@ -104,13 +107,20 @@ gss_krb5_verify_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *message_buffer,
if (ptr[i] != 0xff)
return GSS_S_DEFECTIVE_TOKEN;
if (gss_krb5_checksum(tfm, ptr, GSS_KRB5_TOK_HDR_LEN,
message_buffer, 0, &cksumobj))
nsg = gss_krb5_mic_build_sg(message_buffer,
ptr + GSS_KRB5_TOK_HDR_LEN,
cksum_len, ptr,
sg_head, &sg_overflow);
if (nsg < 0)
return GSS_S_FAILURE;
if (memcmp(cksumobj.data, ptr + GSS_KRB5_TOK_HDR_LEN,
ctx->gk5e->cksumlength))
return GSS_S_BAD_SIG;
mic_offset = 0;
mic_len = cksum_len + message_buffer->len + GSS_KRB5_TOK_HDR_LEN;
ret = crypto_krb5_verify_mic(krb5, shash, NULL, sg_head, nsg,
&mic_offset, &mic_len);
kfree(sg_overflow);
if (ret)
return gss_krb5_errno_to_status(ret);
/* it got through unscathed. Make sure the context is unexpired */
now = ktime_get_real_seconds();