From nobody Sun Feb 8 22:05:36 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DD82522FF2B for ; Mon, 7 Apr 2025 09:15:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744017332; cv=none; b=k8E35dYOqkssN5Q7SEvPYBWTf2WOto7BHMDaxuQrMyGJZdNeoF+pQuZVtHOTn5iJITeA83vBS/2se4AuHOrzsrpxnyaWk98ps6+M/GDoqM9VFPNu6ZUjkJ0cYcjoZ1o47J1K8++2zuS96gt80JEFQxQvUPAf6+yMDtPekR5MysU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744017332; c=relaxed/simple; bh=iZWCDAHUUGCA/JC7Qs7jmKn+3Awjn2LXOrrf/z0CCiA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cyZ6gnfttBFVQE3JFwXEyweUq4v3mrBoFouiGZsEVArMPoj1kJv+68Qnkgjs8VrZoRwCC2n7sWpJjsWGiC1FUpRhgK0sPoe709iDhO5Hq19ln23FexxQqQHYn4Ty+8IEKiTM7RubacPDMlm2tpnC4d9xaD+cRqZKfqqTy/0aUA4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=AEDuULYG; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="AEDuULYG" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1744017328; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=WGwmgmW/+shFRbnx+od3Kr11Qj+FLnW32UsJYmL4KkY=; b=AEDuULYGsuv34rqOcFeNNFt9btOSgIxUNQTkVd4eYvp1C5dbvWt+yVKKUQVhAnfU2vhQBn C0uWaaV9U3cgbEasCepbDsu7tpAxJQ2PJZ3lMSDw+R5LJ+97AY13UbvelF7hczg8F4QLBU zDwtSecaI+FHQWWlprYJCXppFMWjZpY= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-398-oq54W84QOUaBBZGjmjceYA-1; Mon, 07 Apr 2025 05:15:23 -0400 X-MC-Unique: oq54W84QOUaBBZGjmjceYA-1 X-Mimecast-MFC-AGG-ID: oq54W84QOUaBBZGjmjceYA_1744017322 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id DE2241800361; Mon, 7 Apr 2025 09:15:21 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.42.28.40]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id ED3BE1828ABF; Mon, 7 Apr 2025 09:15:16 +0000 (UTC) From: David Howells To: netdev@vger.kernel.org Cc: David Howells , Marc Dionne , Jakub Kicinski , "David S. Miller" , Eric Dumazet , Paolo Abeni , Simon Horman , Christian Brauner , Chuck Lever , linux-afs@lists.infradead.org, openafs-devel@openafs.org, linux-kernel@vger.kernel.org, Herbert Xu , linux-crypto@vger.kernel.org Subject: [PATCH net-next 04/12] rxrpc: Add YFS RxGK (GSSAPI) security class Date: Mon, 7 Apr 2025 10:14:35 +0100 Message-ID: <20250407091451.1174056-5-dhowells@redhat.com> In-Reply-To: <20250407091451.1174056-1-dhowells@redhat.com> References: <20250407091451.1174056-1-dhowells@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Content-Type: text/plain; charset="utf-8" Add support for the YFS-variant RxGK security class to support GSSAPI-derived authentication. This also allows the use of better crypto over the rxkad security class. The key payload is XDR encoded of the form: typedef int64_t opr_time; const AFSTOKEN_RK_TIX_MAX =3D 12000; /* Matches entry in rxkad.h */ struct token_rxkad { afs_int32 viceid; afs_int32 kvno; afs_int64 key; afs_int32 begintime; afs_int32 endtime; afs_int32 primary_flag; opaque ticket; }; struct token_rxgk { opr_time begintime; opr_time endtime; afs_int64 level; afs_int64 lifetime; afs_int64 bytelife; afs_int64 enctype; opaque key<>; opaque ticket<>; }; const AFSTOKEN_UNION_NOAUTH =3D 0; const AFSTOKEN_UNION_KAD =3D 2; const AFSTOKEN_UNION_YFSGK =3D 6; union ktc_tokenUnion switch (afs_int32 type) { case AFSTOKEN_UNION_KAD: token_rxkad kad; case AFSTOKEN_UNION_YFSGK: token_rxgk gk; }; const AFSTOKEN_LENGTH_MAX =3D 16384; typedef opaque token_opaque; const AFSTOKEN_MAX =3D 8; const AFSTOKEN_CELL_MAX =3D 64; struct ktc_setTokenData { afs_int32 flags; string cell; token_opaque tokens; }; The parser for the basic token struct is already present, as is the rxkad token type. This adds a parser for the rxgk token type. Signed-off-by: David Howells cc: Marc Dionne cc: Herbert Xu cc: "David S. Miller" cc: Chuck Lever cc: Eric Dumazet cc: Jakub Kicinski cc: Paolo Abeni cc: Simon Horman cc: linux-afs@lists.infradead.org cc: linux-crypto@vger.kernel.org cc: netdev@vger.kernel.org --- include/keys/rxrpc-type.h | 17 ++++ net/rxrpc/key.c | 185 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 202 insertions(+) diff --git a/include/keys/rxrpc-type.h b/include/keys/rxrpc-type.h index 333c0f49a9cd..0ddbe197a261 100644 --- a/include/keys/rxrpc-type.h +++ b/include/keys/rxrpc-type.h @@ -9,6 +9,7 @@ #define _KEYS_RXRPC_TYPE_H =20 #include +#include =20 /* * key type for AF_RXRPC keys @@ -31,6 +32,21 @@ struct rxkad_key { u8 ticket[]; /* the encrypted ticket */ }; =20 +/* + * RxRPC key for YFS-RxGK (type-6 security) + */ +struct rxgk_key { + s64 begintime; /* Time at which the ticket starts */ + s64 endtime; /* Time at which the ticket ends */ + u64 lifetime; /* Maximum lifespan of a connection (seconds) */ + u64 bytelife; /* Maximum number of bytes on a connection */ + unsigned int enctype; /* Encoding type */ + s8 level; /* Negotiated security RXRPC_SECURITY_PLAIN/AUTH/ENCRYPT */ + struct krb5_buffer key; /* Master key, K0 */ + struct krb5_buffer ticket; /* Ticket to be passed to server */ + u8 _key[]; /* Key storage */ +}; + /* * list of tokens attached to an rxrpc key */ @@ -40,6 +56,7 @@ struct rxrpc_key_token { struct rxrpc_key_token *next; /* the next token in the list */ union { struct rxkad_key *kad; + struct rxgk_key *rxgk; }; }; =20 diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c index 33e8302a79e3..155cd1d60910 100644 --- a/net/rxrpc/key.c +++ b/net/rxrpc/key.c @@ -129,6 +129,160 @@ static int rxrpc_preparse_xdr_rxkad(struct key_prepar= sed_payload *prep, return 0; } =20 +static u64 xdr_dec64(const __be32 *xdr) +{ + return (u64)ntohl(xdr[0]) << 32 | (u64)ntohl(xdr[1]); +} + +static time64_t rxrpc_s64_to_time64(s64 time_in_100ns) +{ + bool neg =3D false; + u64 tmp =3D time_in_100ns; + + if (time_in_100ns < 0) { + tmp =3D -time_in_100ns; + neg =3D true; + } + do_div(tmp, 10000000); + return neg ? -tmp : tmp; +} + +/* + * Parse a YFS-RxGK type XDR format token + * - the caller guarantees we have at least 4 words + * + * struct token_rxgk { + * opr_time begintime; + * opr_time endtime; + * afs_int64 level; + * afs_int64 lifetime; + * afs_int64 bytelife; + * afs_int64 enctype; + * opaque key<>; + * opaque ticket<>; + * }; + */ +static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep, + size_t datalen, + const __be32 *xdr, unsigned int toklen) +{ + struct rxrpc_key_token *token, **pptoken; + time64_t expiry; + size_t plen; + const __be32 *ticket, *key; + s64 tmp; + u32 tktlen, keylen; + + _enter(",{%x,%x,%x,%x},%x", + ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), + toklen); + + if (6 * 2 + 2 > toklen / 4) + goto reject; + + key =3D xdr + (6 * 2 + 1); + keylen =3D ntohl(key[-1]); + _debug("keylen: %x", keylen); + keylen =3D round_up(keylen, 4); + if ((6 * 2 + 2) * 4 + keylen > toklen) + goto reject; + + ticket =3D xdr + (6 * 2 + 1 + (keylen / 4) + 1); + tktlen =3D ntohl(ticket[-1]); + _debug("tktlen: %x", tktlen); + tktlen =3D round_up(tktlen, 4); + if ((6 * 2 + 2) * 4 + keylen + tktlen !=3D toklen) { + kleave(" =3D -EKEYREJECTED [%x!=3D%x, %x,%x]", + (6 * 2 + 2) * 4 + keylen + tktlen, toklen, + keylen, tktlen); + goto reject; + } + + plen =3D sizeof(*token) + sizeof(*token->rxgk) + tktlen + keylen; + prep->quotalen =3D datalen + plen; + + plen -=3D sizeof(*token); + token =3D kzalloc(sizeof(*token), GFP_KERNEL); + if (!token) + goto nomem; + + token->rxgk =3D kzalloc(sizeof(*token->rxgk) + keylen, GFP_KERNEL); + if (!token->rxgk) + goto nomem_token; + + token->security_index =3D RXRPC_SECURITY_YFS_RXGK; + token->rxgk->begintime =3D xdr_dec64(xdr + 0 * 2); + token->rxgk->endtime =3D xdr_dec64(xdr + 1 * 2); + token->rxgk->level =3D tmp =3D xdr_dec64(xdr + 2 * 2); + if (tmp < -1LL || tmp > RXRPC_SECURITY_ENCRYPT) + goto reject_token; + token->rxgk->lifetime =3D xdr_dec64(xdr + 3 * 2); + token->rxgk->bytelife =3D xdr_dec64(xdr + 4 * 2); + token->rxgk->enctype =3D tmp =3D xdr_dec64(xdr + 5 * 2); + if (tmp < 0 || tmp > UINT_MAX) + goto reject_token; + token->rxgk->key.len =3D ntohl(key[-1]); + token->rxgk->key.data =3D token->rxgk->_key; + token->rxgk->ticket.len =3D ntohl(ticket[-1]); + + if (token->rxgk->endtime !=3D 0) { + expiry =3D rxrpc_s64_to_time64(token->rxgk->endtime); + if (expiry < 0) + goto expired; + if (expiry < prep->expiry) + prep->expiry =3D expiry; + } + + memcpy(token->rxgk->key.data, key, token->rxgk->key.len); + + /* Pad the ticket so that we can use it directly in XDR */ + token->rxgk->ticket.data =3D kzalloc(round_up(token->rxgk->ticket.len, 4), + GFP_KERNEL); + if (!token->rxgk->ticket.data) + goto nomem_yrxgk; + memcpy(token->rxgk->ticket.data, ticket, token->rxgk->ticket.len); + + _debug("SCIX: %u", token->security_index); + _debug("EXPY: %llx", token->rxgk->endtime); + _debug("LIFE: %llx", token->rxgk->lifetime); + _debug("BYTE: %llx", token->rxgk->bytelife); + _debug("ENC : %u", token->rxgk->enctype); + _debug("LEVL: %u", token->rxgk->level); + _debug("KLEN: %u", token->rxgk->key.len); + _debug("TLEN: %u", token->rxgk->ticket.len); + _debug("KEY0: %*phN", token->rxgk->key.len, token->rxgk->key.data); + _debug("TICK: %*phN", + min_t(u32, token->rxgk->ticket.len, 32), token->rxgk->ticket.data); + + /* count the number of tokens attached */ + prep->payload.data[1] =3D (void *)((unsigned long)prep->payload.data[1] += 1); + + /* attach the data */ + for (pptoken =3D (struct rxrpc_key_token **)&prep->payload.data[0]; + *pptoken; + pptoken =3D &(*pptoken)->next) + continue; + *pptoken =3D token; + + _leave(" =3D 0"); + return 0; + +nomem_yrxgk: + kfree(token->rxgk); +nomem_token: + kfree(token); +nomem: + return -ENOMEM; +reject_token: + kfree(token); +reject: + return -EKEYREJECTED; +expired: + kfree(token->rxgk); + kfree(token); + return -EKEYEXPIRED; +} + /* * attempt to parse the data as the XDR format * - the caller guarantees we have more than 7 words @@ -228,6 +382,9 @@ static int rxrpc_preparse_xdr(struct key_preparsed_payl= oad *prep) case RXRPC_SECURITY_RXKAD: ret2 =3D rxrpc_preparse_xdr_rxkad(prep, datalen, token, toklen); break; + case RXRPC_SECURITY_YFS_RXGK: + ret2 =3D rxrpc_preparse_xdr_yfs_rxgk(prep, datalen, token, toklen); + break; default: ret2 =3D -EPROTONOSUPPORT; break; @@ -390,6 +547,10 @@ static void rxrpc_free_token_list(struct rxrpc_key_tok= en *token) case RXRPC_SECURITY_RXKAD: kfree(token->kad); break; + case RXRPC_SECURITY_YFS_RXGK: + kfree(token->rxgk->ticket.data); + kfree(token->rxgk); + break; default: pr_err("Unknown token type %x on rxrpc key\n", token->security_index); @@ -433,6 +594,9 @@ static void rxrpc_describe(const struct key *key, struc= t seq_file *m) case RXRPC_SECURITY_RXKAD: seq_puts(m, "ka"); break; + case RXRPC_SECURITY_YFS_RXGK: + seq_puts(m, "ygk"); + break; default: /* we have a ticket we can't encode */ seq_printf(m, "%u", token->security_index); break; @@ -595,6 +759,13 @@ static long rxrpc_read(const struct key *key, toksize +=3D RND(token->kad->ticket_len); break; =20 + case RXRPC_SECURITY_YFS_RXGK: + toksize +=3D 6 * 8 + 2 * 4; + if (!token->no_leak_key) + toksize +=3D RND(token->rxgk->key.len); + toksize +=3D RND(token->rxgk->ticket.len); + break; + default: /* we have a ticket we can't encode */ pr_err("Unsupported key token type (%u)\n", token->security_index); @@ -674,6 +845,20 @@ static long rxrpc_read(const struct key *key, ENCODE_DATA(token->kad->ticket_len, token->kad->ticket); break; =20 + case RXRPC_SECURITY_YFS_RXGK: + ENCODE64(token->rxgk->begintime); + ENCODE64(token->rxgk->endtime); + ENCODE64(token->rxgk->level); + ENCODE64(token->rxgk->lifetime); + ENCODE64(token->rxgk->bytelife); + ENCODE64(token->rxgk->enctype); + if (token->no_leak_key) + ENCODE(0); + else + ENCODE_DATA(token->rxgk->key.len, token->rxgk->key.data); + ENCODE_DATA(token->rxgk->ticket.len, token->rxgk->ticket.data); + break; + default: pr_err("Unsupported key token type (%u)\n", token->security_index);