Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rxrpc: Add YFS RxGK (GSSAPI) security class

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 = 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<AFSTOKEN_RK_TIX_MAX>;
};

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 = 0;
const AFSTOKEN_UNION_KAD = 2;
const AFSTOKEN_UNION_YFSGK = 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 = 16384;
typedef opaque token_opaque<AFSTOKEN_LENGTH_MAX>;

const AFSTOKEN_MAX = 8;
const AFSTOKEN_CELL_MAX = 64;

struct ktc_setTokenData {
afs_int32 flags;
string cell<AFSTOKEN_CELL_MAX>;
token_opaque tokens<AFSTOKEN_MAX>;
};

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 <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: Chuck Lever <chuck.lever@oracle.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
Link: https://patch.msgid.link/20250411095303.2316168-7-dhowells@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

David Howells and committed by
Jakub Kicinski
0ca100ff 01af6426

+202
+17
include/keys/rxrpc-type.h
··· 9 9 #define _KEYS_RXRPC_TYPE_H 10 10 11 11 #include <linux/key.h> 12 + #include <crypto/krb5.h> 12 13 13 14 /* 14 15 * key type for AF_RXRPC keys ··· 33 32 }; 34 33 35 34 /* 35 + * RxRPC key for YFS-RxGK (type-6 security) 36 + */ 37 + struct rxgk_key { 38 + s64 begintime; /* Time at which the ticket starts */ 39 + s64 endtime; /* Time at which the ticket ends */ 40 + u64 lifetime; /* Maximum lifespan of a connection (seconds) */ 41 + u64 bytelife; /* Maximum number of bytes on a connection */ 42 + unsigned int enctype; /* Encoding type */ 43 + s8 level; /* Negotiated security RXRPC_SECURITY_PLAIN/AUTH/ENCRYPT */ 44 + struct krb5_buffer key; /* Master key, K0 */ 45 + struct krb5_buffer ticket; /* Ticket to be passed to server */ 46 + u8 _key[]; /* Key storage */ 47 + }; 48 + 49 + /* 36 50 * list of tokens attached to an rxrpc key 37 51 */ 38 52 struct rxrpc_key_token { ··· 56 40 struct rxrpc_key_token *next; /* the next token in the list */ 57 41 union { 58 42 struct rxkad_key *kad; 43 + struct rxgk_key *rxgk; 59 44 }; 60 45 }; 61 46
+185
net/rxrpc/key.c
··· 129 129 return 0; 130 130 } 131 131 132 + static u64 xdr_dec64(const __be32 *xdr) 133 + { 134 + return (u64)ntohl(xdr[0]) << 32 | (u64)ntohl(xdr[1]); 135 + } 136 + 137 + static time64_t rxrpc_s64_to_time64(s64 time_in_100ns) 138 + { 139 + bool neg = false; 140 + u64 tmp = time_in_100ns; 141 + 142 + if (time_in_100ns < 0) { 143 + tmp = -time_in_100ns; 144 + neg = true; 145 + } 146 + do_div(tmp, 10000000); 147 + return neg ? -tmp : tmp; 148 + } 149 + 150 + /* 151 + * Parse a YFS-RxGK type XDR format token 152 + * - the caller guarantees we have at least 4 words 153 + * 154 + * struct token_rxgk { 155 + * opr_time begintime; 156 + * opr_time endtime; 157 + * afs_int64 level; 158 + * afs_int64 lifetime; 159 + * afs_int64 bytelife; 160 + * afs_int64 enctype; 161 + * opaque key<>; 162 + * opaque ticket<>; 163 + * }; 164 + */ 165 + static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep, 166 + size_t datalen, 167 + const __be32 *xdr, unsigned int toklen) 168 + { 169 + struct rxrpc_key_token *token, **pptoken; 170 + time64_t expiry; 171 + size_t plen; 172 + const __be32 *ticket, *key; 173 + s64 tmp; 174 + u32 tktlen, keylen; 175 + 176 + _enter(",{%x,%x,%x,%x},%x", 177 + ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]), 178 + toklen); 179 + 180 + if (6 * 2 + 2 > toklen / 4) 181 + goto reject; 182 + 183 + key = xdr + (6 * 2 + 1); 184 + keylen = ntohl(key[-1]); 185 + _debug("keylen: %x", keylen); 186 + keylen = round_up(keylen, 4); 187 + if ((6 * 2 + 2) * 4 + keylen > toklen) 188 + goto reject; 189 + 190 + ticket = xdr + (6 * 2 + 1 + (keylen / 4) + 1); 191 + tktlen = ntohl(ticket[-1]); 192 + _debug("tktlen: %x", tktlen); 193 + tktlen = round_up(tktlen, 4); 194 + if ((6 * 2 + 2) * 4 + keylen + tktlen != toklen) { 195 + kleave(" = -EKEYREJECTED [%x!=%x, %x,%x]", 196 + (6 * 2 + 2) * 4 + keylen + tktlen, toklen, 197 + keylen, tktlen); 198 + goto reject; 199 + } 200 + 201 + plen = sizeof(*token) + sizeof(*token->rxgk) + tktlen + keylen; 202 + prep->quotalen = datalen + plen; 203 + 204 + plen -= sizeof(*token); 205 + token = kzalloc(sizeof(*token), GFP_KERNEL); 206 + if (!token) 207 + goto nomem; 208 + 209 + token->rxgk = kzalloc(sizeof(*token->rxgk) + keylen, GFP_KERNEL); 210 + if (!token->rxgk) 211 + goto nomem_token; 212 + 213 + token->security_index = RXRPC_SECURITY_YFS_RXGK; 214 + token->rxgk->begintime = xdr_dec64(xdr + 0 * 2); 215 + token->rxgk->endtime = xdr_dec64(xdr + 1 * 2); 216 + token->rxgk->level = tmp = xdr_dec64(xdr + 2 * 2); 217 + if (tmp < -1LL || tmp > RXRPC_SECURITY_ENCRYPT) 218 + goto reject_token; 219 + token->rxgk->lifetime = xdr_dec64(xdr + 3 * 2); 220 + token->rxgk->bytelife = xdr_dec64(xdr + 4 * 2); 221 + token->rxgk->enctype = tmp = xdr_dec64(xdr + 5 * 2); 222 + if (tmp < 0 || tmp > UINT_MAX) 223 + goto reject_token; 224 + token->rxgk->key.len = ntohl(key[-1]); 225 + token->rxgk->key.data = token->rxgk->_key; 226 + token->rxgk->ticket.len = ntohl(ticket[-1]); 227 + 228 + if (token->rxgk->endtime != 0) { 229 + expiry = rxrpc_s64_to_time64(token->rxgk->endtime); 230 + if (expiry < 0) 231 + goto expired; 232 + if (expiry < prep->expiry) 233 + prep->expiry = expiry; 234 + } 235 + 236 + memcpy(token->rxgk->key.data, key, token->rxgk->key.len); 237 + 238 + /* Pad the ticket so that we can use it directly in XDR */ 239 + token->rxgk->ticket.data = kzalloc(round_up(token->rxgk->ticket.len, 4), 240 + GFP_KERNEL); 241 + if (!token->rxgk->ticket.data) 242 + goto nomem_yrxgk; 243 + memcpy(token->rxgk->ticket.data, ticket, token->rxgk->ticket.len); 244 + 245 + _debug("SCIX: %u", token->security_index); 246 + _debug("EXPY: %llx", token->rxgk->endtime); 247 + _debug("LIFE: %llx", token->rxgk->lifetime); 248 + _debug("BYTE: %llx", token->rxgk->bytelife); 249 + _debug("ENC : %u", token->rxgk->enctype); 250 + _debug("LEVL: %u", token->rxgk->level); 251 + _debug("KLEN: %u", token->rxgk->key.len); 252 + _debug("TLEN: %u", token->rxgk->ticket.len); 253 + _debug("KEY0: %*phN", token->rxgk->key.len, token->rxgk->key.data); 254 + _debug("TICK: %*phN", 255 + min_t(u32, token->rxgk->ticket.len, 32), token->rxgk->ticket.data); 256 + 257 + /* count the number of tokens attached */ 258 + prep->payload.data[1] = (void *)((unsigned long)prep->payload.data[1] + 1); 259 + 260 + /* attach the data */ 261 + for (pptoken = (struct rxrpc_key_token **)&prep->payload.data[0]; 262 + *pptoken; 263 + pptoken = &(*pptoken)->next) 264 + continue; 265 + *pptoken = token; 266 + 267 + _leave(" = 0"); 268 + return 0; 269 + 270 + nomem_yrxgk: 271 + kfree(token->rxgk); 272 + nomem_token: 273 + kfree(token); 274 + nomem: 275 + return -ENOMEM; 276 + reject_token: 277 + kfree(token); 278 + reject: 279 + return -EKEYREJECTED; 280 + expired: 281 + kfree(token->rxgk); 282 + kfree(token); 283 + return -EKEYEXPIRED; 284 + } 285 + 132 286 /* 133 287 * attempt to parse the data as the XDR format 134 288 * - the caller guarantees we have more than 7 words ··· 381 227 switch (sec_ix) { 382 228 case RXRPC_SECURITY_RXKAD: 383 229 ret2 = rxrpc_preparse_xdr_rxkad(prep, datalen, token, toklen); 230 + break; 231 + case RXRPC_SECURITY_YFS_RXGK: 232 + ret2 = rxrpc_preparse_xdr_yfs_rxgk(prep, datalen, token, toklen); 384 233 break; 385 234 default: 386 235 ret2 = -EPROTONOSUPPORT; ··· 547 390 case RXRPC_SECURITY_RXKAD: 548 391 kfree(token->kad); 549 392 break; 393 + case RXRPC_SECURITY_YFS_RXGK: 394 + kfree(token->rxgk->ticket.data); 395 + kfree(token->rxgk); 396 + break; 550 397 default: 551 398 pr_err("Unknown token type %x on rxrpc key\n", 552 399 token->security_index); ··· 593 432 switch (token->security_index) { 594 433 case RXRPC_SECURITY_RXKAD: 595 434 seq_puts(m, "ka"); 435 + break; 436 + case RXRPC_SECURITY_YFS_RXGK: 437 + seq_puts(m, "ygk"); 596 438 break; 597 439 default: /* we have a ticket we can't encode */ 598 440 seq_printf(m, "%u", token->security_index); ··· 761 597 toksize += RND(token->kad->ticket_len); 762 598 break; 763 599 600 + case RXRPC_SECURITY_YFS_RXGK: 601 + toksize += 6 * 8 + 2 * 4; 602 + if (!token->no_leak_key) 603 + toksize += RND(token->rxgk->key.len); 604 + toksize += RND(token->rxgk->ticket.len); 605 + break; 606 + 764 607 default: /* we have a ticket we can't encode */ 765 608 pr_err("Unsupported key token type (%u)\n", 766 609 token->security_index); ··· 845 674 ENCODE(0); 846 675 else 847 676 ENCODE_DATA(token->kad->ticket_len, token->kad->ticket); 677 + break; 678 + 679 + case RXRPC_SECURITY_YFS_RXGK: 680 + ENCODE64(token->rxgk->begintime); 681 + ENCODE64(token->rxgk->endtime); 682 + ENCODE64(token->rxgk->level); 683 + ENCODE64(token->rxgk->lifetime); 684 + ENCODE64(token->rxgk->bytelife); 685 + ENCODE64(token->rxgk->enctype); 686 + if (token->no_leak_key) 687 + ENCODE(0); 688 + else 689 + ENCODE_DATA(token->rxgk->key.len, token->rxgk->key.data); 690 + ENCODE_DATA(token->rxgk->ticket.len, token->rxgk->ticket.data); 848 691 break; 849 692 850 693 default: