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>
pull/1112/head
parent
01af642697
commit
0ca100ff4d
|
|
@ -9,6 +9,7 @@
|
||||||
#define _KEYS_RXRPC_TYPE_H
|
#define _KEYS_RXRPC_TYPE_H
|
||||||
|
|
||||||
#include <linux/key.h>
|
#include <linux/key.h>
|
||||||
|
#include <crypto/krb5.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* key type for AF_RXRPC keys
|
* key type for AF_RXRPC keys
|
||||||
|
|
@ -31,6 +32,21 @@ struct rxkad_key {
|
||||||
u8 ticket[]; /* the encrypted ticket */
|
u8 ticket[]; /* the encrypted ticket */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
* 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 */
|
struct rxrpc_key_token *next; /* the next token in the list */
|
||||||
union {
|
union {
|
||||||
struct rxkad_key *kad;
|
struct rxkad_key *kad;
|
||||||
|
struct rxgk_key *rxgk;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
185
net/rxrpc/key.c
185
net/rxrpc/key.c
|
|
@ -129,6 +129,160 @@ static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 = false;
|
||||||
|
u64 tmp = time_in_100ns;
|
||||||
|
|
||||||
|
if (time_in_100ns < 0) {
|
||||||
|
tmp = -time_in_100ns;
|
||||||
|
neg = 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 = xdr + (6 * 2 + 1);
|
||||||
|
keylen = ntohl(key[-1]);
|
||||||
|
_debug("keylen: %x", keylen);
|
||||||
|
keylen = round_up(keylen, 4);
|
||||||
|
if ((6 * 2 + 2) * 4 + keylen > toklen)
|
||||||
|
goto reject;
|
||||||
|
|
||||||
|
ticket = xdr + (6 * 2 + 1 + (keylen / 4) + 1);
|
||||||
|
tktlen = ntohl(ticket[-1]);
|
||||||
|
_debug("tktlen: %x", tktlen);
|
||||||
|
tktlen = round_up(tktlen, 4);
|
||||||
|
if ((6 * 2 + 2) * 4 + keylen + tktlen != toklen) {
|
||||||
|
kleave(" = -EKEYREJECTED [%x!=%x, %x,%x]",
|
||||||
|
(6 * 2 + 2) * 4 + keylen + tktlen, toklen,
|
||||||
|
keylen, tktlen);
|
||||||
|
goto reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
plen = sizeof(*token) + sizeof(*token->rxgk) + tktlen + keylen;
|
||||||
|
prep->quotalen = datalen + plen;
|
||||||
|
|
||||||
|
plen -= sizeof(*token);
|
||||||
|
token = kzalloc(sizeof(*token), GFP_KERNEL);
|
||||||
|
if (!token)
|
||||||
|
goto nomem;
|
||||||
|
|
||||||
|
token->rxgk = kzalloc(sizeof(*token->rxgk) + keylen, GFP_KERNEL);
|
||||||
|
if (!token->rxgk)
|
||||||
|
goto nomem_token;
|
||||||
|
|
||||||
|
token->security_index = RXRPC_SECURITY_YFS_RXGK;
|
||||||
|
token->rxgk->begintime = xdr_dec64(xdr + 0 * 2);
|
||||||
|
token->rxgk->endtime = xdr_dec64(xdr + 1 * 2);
|
||||||
|
token->rxgk->level = tmp = xdr_dec64(xdr + 2 * 2);
|
||||||
|
if (tmp < -1LL || tmp > RXRPC_SECURITY_ENCRYPT)
|
||||||
|
goto reject_token;
|
||||||
|
token->rxgk->lifetime = xdr_dec64(xdr + 3 * 2);
|
||||||
|
token->rxgk->bytelife = xdr_dec64(xdr + 4 * 2);
|
||||||
|
token->rxgk->enctype = tmp = xdr_dec64(xdr + 5 * 2);
|
||||||
|
if (tmp < 0 || tmp > UINT_MAX)
|
||||||
|
goto reject_token;
|
||||||
|
token->rxgk->key.len = ntohl(key[-1]);
|
||||||
|
token->rxgk->key.data = token->rxgk->_key;
|
||||||
|
token->rxgk->ticket.len = ntohl(ticket[-1]);
|
||||||
|
|
||||||
|
if (token->rxgk->endtime != 0) {
|
||||||
|
expiry = rxrpc_s64_to_time64(token->rxgk->endtime);
|
||||||
|
if (expiry < 0)
|
||||||
|
goto expired;
|
||||||
|
if (expiry < prep->expiry)
|
||||||
|
prep->expiry = 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 = 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] = (void *)((unsigned long)prep->payload.data[1] + 1);
|
||||||
|
|
||||||
|
/* attach the data */
|
||||||
|
for (pptoken = (struct rxrpc_key_token **)&prep->payload.data[0];
|
||||||
|
*pptoken;
|
||||||
|
pptoken = &(*pptoken)->next)
|
||||||
|
continue;
|
||||||
|
*pptoken = token;
|
||||||
|
|
||||||
|
_leave(" = 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
|
* attempt to parse the data as the XDR format
|
||||||
* - the caller guarantees we have more than 7 words
|
* - the caller guarantees we have more than 7 words
|
||||||
|
|
@ -228,6 +382,9 @@ static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)
|
||||||
case RXRPC_SECURITY_RXKAD:
|
case RXRPC_SECURITY_RXKAD:
|
||||||
ret2 = rxrpc_preparse_xdr_rxkad(prep, datalen, token, toklen);
|
ret2 = rxrpc_preparse_xdr_rxkad(prep, datalen, token, toklen);
|
||||||
break;
|
break;
|
||||||
|
case RXRPC_SECURITY_YFS_RXGK:
|
||||||
|
ret2 = rxrpc_preparse_xdr_yfs_rxgk(prep, datalen, token, toklen);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ret2 = -EPROTONOSUPPORT;
|
ret2 = -EPROTONOSUPPORT;
|
||||||
break;
|
break;
|
||||||
|
|
@ -390,6 +547,10 @@ static void rxrpc_free_token_list(struct rxrpc_key_token *token)
|
||||||
case RXRPC_SECURITY_RXKAD:
|
case RXRPC_SECURITY_RXKAD:
|
||||||
kfree(token->kad);
|
kfree(token->kad);
|
||||||
break;
|
break;
|
||||||
|
case RXRPC_SECURITY_YFS_RXGK:
|
||||||
|
kfree(token->rxgk->ticket.data);
|
||||||
|
kfree(token->rxgk);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
pr_err("Unknown token type %x on rxrpc key\n",
|
pr_err("Unknown token type %x on rxrpc key\n",
|
||||||
token->security_index);
|
token->security_index);
|
||||||
|
|
@ -433,6 +594,9 @@ static void rxrpc_describe(const struct key *key, struct seq_file *m)
|
||||||
case RXRPC_SECURITY_RXKAD:
|
case RXRPC_SECURITY_RXKAD:
|
||||||
seq_puts(m, "ka");
|
seq_puts(m, "ka");
|
||||||
break;
|
break;
|
||||||
|
case RXRPC_SECURITY_YFS_RXGK:
|
||||||
|
seq_puts(m, "ygk");
|
||||||
|
break;
|
||||||
default: /* we have a ticket we can't encode */
|
default: /* we have a ticket we can't encode */
|
||||||
seq_printf(m, "%u", token->security_index);
|
seq_printf(m, "%u", token->security_index);
|
||||||
break;
|
break;
|
||||||
|
|
@ -597,6 +761,13 @@ static long rxrpc_read(const struct key *key,
|
||||||
toksize += RND(token->kad->ticket_len);
|
toksize += RND(token->kad->ticket_len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case RXRPC_SECURITY_YFS_RXGK:
|
||||||
|
toksize += 6 * 8 + 2 * 4;
|
||||||
|
if (!token->no_leak_key)
|
||||||
|
toksize += RND(token->rxgk->key.len);
|
||||||
|
toksize += RND(token->rxgk->ticket.len);
|
||||||
|
break;
|
||||||
|
|
||||||
default: /* we have a ticket we can't encode */
|
default: /* we have a ticket we can't encode */
|
||||||
pr_err("Unsupported key token type (%u)\n",
|
pr_err("Unsupported key token type (%u)\n",
|
||||||
token->security_index);
|
token->security_index);
|
||||||
|
|
@ -676,6 +847,20 @@ static long rxrpc_read(const struct key *key,
|
||||||
ENCODE_DATA(token->kad->ticket_len, token->kad->ticket);
|
ENCODE_DATA(token->kad->ticket_len, token->kad->ticket);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
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:
|
default:
|
||||||
pr_err("Unsupported key token type (%u)\n",
|
pr_err("Unsupported key token type (%u)\n",
|
||||||
token->security_index);
|
token->security_index);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue