File Index
Files and directories
Sign in
FILE

key.c

File preview with syntax highlighting.

linux-6.19.14/net/rxrpc/key.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/* RxRPC key management
  3 *
  4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
  5 * Written by David Howells (dhowells@redhat.com)
  6 *
  7 * RxRPC keys should have a description of describing their purpose:
  8 *	"afs@example.com"
  9 */
 10
 11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 12
 13#include <crypto/skcipher.h>
 14#include <linux/module.h>
 15#include <linux/net.h>
 16#include <linux/overflow.h>
 17#include <linux/skbuff.h>
 18#include <linux/key-type.h>
 19#include <linux/ctype.h>
 20#include <linux/slab.h>
 21#include <net/sock.h>
 22#include <net/af_rxrpc.h>
 23#include <keys/rxrpc-type.h>
 24#include <keys/user-type.h>
 25#include "ar-internal.h"
 26
 27static int rxrpc_preparse(struct key_preparsed_payload *);
 28static void rxrpc_free_preparse(struct key_preparsed_payload *);
 29static void rxrpc_destroy(struct key *);
 30static void rxrpc_describe(const struct key *, struct seq_file *);
 31static long rxrpc_read(const struct key *, char *, size_t);
 32
 33/*
 34 * rxrpc defined keys take an arbitrary string as the description and an
 35 * arbitrary blob of data as the payload
 36 */
 37struct key_type key_type_rxrpc = {
 38	.name		= "rxrpc",
 39	.flags		= KEY_TYPE_NET_DOMAIN,
 40	.preparse	= rxrpc_preparse,
 41	.free_preparse	= rxrpc_free_preparse,
 42	.instantiate	= generic_key_instantiate,
 43	.destroy	= rxrpc_destroy,
 44	.describe	= rxrpc_describe,
 45	.read		= rxrpc_read,
 46};
 47EXPORT_SYMBOL(key_type_rxrpc);
 48
 49/*
 50 * parse an RxKAD type XDR format token
 51 * - the caller guarantees we have at least 4 words
 52 */
 53static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
 54				    size_t datalen,
 55				    const __be32 *xdr, unsigned int toklen)
 56{
 57	struct rxrpc_key_token *token, **pptoken;
 58	time64_t expiry;
 59	size_t plen;
 60	u32 tktlen;
 61
 62	_enter(",{%x,%x,%x,%x},%u",
 63	       ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
 64	       toklen);
 65
 66	if (toklen <= 8 * 4)
 67		return -EKEYREJECTED;
 68	tktlen = ntohl(xdr[7]);
 69	_debug("tktlen: %x", tktlen);
 70	if (tktlen > AFSTOKEN_RK_TIX_MAX)
 71		return -EKEYREJECTED;
 72	if (toklen < 8 * 4 + tktlen)
 73		return -EKEYREJECTED;
 74
 75	plen = sizeof(*token) + sizeof(*token->kad) + tktlen;
 76	prep->quotalen += datalen + plen;
 77
 78	plen -= sizeof(*token);
 79	token = kzalloc(sizeof(*token), GFP_KERNEL);
 80	if (!token)
 81		return -ENOMEM;
 82
 83	token->kad = kzalloc(plen, GFP_KERNEL);
 84	if (!token->kad) {
 85		kfree(token);
 86		return -ENOMEM;
 87	}
 88
 89	token->security_index	= RXRPC_SECURITY_RXKAD;
 90	token->kad->ticket_len	= tktlen;
 91	token->kad->vice_id	= ntohl(xdr[0]);
 92	token->kad->kvno	= ntohl(xdr[1]);
 93	token->kad->start	= ntohl(xdr[4]);
 94	token->kad->expiry	= ntohl(xdr[5]);
 95	token->kad->primary_flag = ntohl(xdr[6]);
 96	memcpy(&token->kad->session_key, &xdr[2], 8);
 97	memcpy(&token->kad->ticket, &xdr[8], tktlen);
 98
 99	_debug("SCIX: %u", token->security_index);
100	_debug("TLEN: %u", token->kad->ticket_len);
101	_debug("EXPY: %x", token->kad->expiry);
102	_debug("KVNO: %u", token->kad->kvno);
103	_debug("PRIM: %u", token->kad->primary_flag);
104	_debug("SKEY: %02x%02x%02x%02x%02x%02x%02x%02x",
105	       token->kad->session_key[0], token->kad->session_key[1],
106	       token->kad->session_key[2], token->kad->session_key[3],
107	       token->kad->session_key[4], token->kad->session_key[5],
108	       token->kad->session_key[6], token->kad->session_key[7]);
109	if (token->kad->ticket_len >= 8)
110		_debug("TCKT: %02x%02x%02x%02x%02x%02x%02x%02x",
111		       token->kad->ticket[0], token->kad->ticket[1],
112		       token->kad->ticket[2], token->kad->ticket[3],
113		       token->kad->ticket[4], token->kad->ticket[5],
114		       token->kad->ticket[6], token->kad->ticket[7]);
115
116	/* count the number of tokens attached */
117	prep->payload.data[1] = (void *)((unsigned long)prep->payload.data[1] + 1);
118
119	/* attach the data */
120	for (pptoken = (struct rxrpc_key_token **)&prep->payload.data[0];
121	     *pptoken;
122	     pptoken = &(*pptoken)->next)
123		continue;
124	*pptoken = token;
125	expiry = rxrpc_u32_to_time64(token->kad->expiry);
126	if (expiry < prep->expiry)
127		prep->expiry = expiry;
128
129	_leave(" = 0");
130	return 0;
131}
132
133static u64 xdr_dec64(const __be32 *xdr)
134{
135	return (u64)ntohl(xdr[0]) << 32 | (u64)ntohl(xdr[1]);
136}
137
138static time64_t rxrpc_s64_to_time64(s64 time_in_100ns)
139{
140	bool neg = false;
141	u64 tmp = time_in_100ns;
142
143	if (time_in_100ns < 0) {
144		tmp = -time_in_100ns;
145		neg = true;
146	}
147	do_div(tmp, 10000000);
148	return neg ? -tmp : tmp;
149}
150
151/*
152 * Parse a YFS-RxGK type XDR format token
153 * - the caller guarantees we have at least 4 words
154 *
155 * struct token_rxgk {
156 *	opr_time begintime;
157 *	opr_time endtime;
158 *	afs_int64 level;
159 *	afs_int64 lifetime;
160 *	afs_int64 bytelife;
161 *	afs_int64 enctype;
162 *	opaque key<>;
163 *	opaque ticket<>;
164 * };
165 */
166static int rxrpc_preparse_xdr_yfs_rxgk(struct key_preparsed_payload *prep,
167				       size_t datalen,
168				       const __be32 *xdr, unsigned int toklen)
169{
170	struct rxrpc_key_token *token, **pptoken;
171	time64_t expiry;
172	size_t plen;
173	const __be32 *ticket, *key;
174	s64 tmp;
175	size_t raw_keylen, raw_tktlen, keylen, tktlen;
176
177	_enter(",{%x,%x,%x,%x},%x",
178	       ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
179	       toklen);
180
181	if (6 * 2 + 2 > toklen / 4)
182		goto reject;
183
184	key = xdr + (6 * 2 + 1);
185	raw_keylen = ntohl(key[-1]);
186	_debug("keylen: %zx", raw_keylen);
187	if (raw_keylen > AFSTOKEN_GK_KEY_MAX)
188		goto reject;
189	keylen = round_up(raw_keylen, 4);
190	if ((6 * 2 + 2) * 4 + keylen > toklen)
191		goto reject;
192
193	ticket = xdr + (6 * 2 + 1 + (keylen / 4) + 1);
194	raw_tktlen = ntohl(ticket[-1]);
195	_debug("tktlen: %zx", raw_tktlen);
196	if (raw_tktlen > AFSTOKEN_GK_TOKEN_MAX)
197		goto reject;
198	tktlen = round_up(raw_tktlen, 4);
199	if ((6 * 2 + 2) * 4 + keylen + tktlen != toklen) {
200		kleave(" = -EKEYREJECTED [%zx!=%x, %zx,%zx]",
201		       (6 * 2 + 2) * 4 + keylen + tktlen, toklen,
202		       keylen, tktlen);
203		goto reject;
204	}
205
206	plen = sizeof(*token) + sizeof(*token->rxgk) + tktlen + keylen;
207	prep->quotalen += datalen + plen;
208
209	plen -= sizeof(*token);
210	token = kzalloc(sizeof(*token), GFP_KERNEL);
211	if (!token)
212		goto nomem;
213
214	token->rxgk = kzalloc(struct_size_t(struct rxgk_key, _key, raw_keylen), GFP_KERNEL);
215	if (!token->rxgk)
216		goto nomem_token;
217
218	token->security_index	= RXRPC_SECURITY_YFS_RXGK;
219	token->rxgk->begintime	= xdr_dec64(xdr + 0 * 2);
220	token->rxgk->endtime	= xdr_dec64(xdr + 1 * 2);
221	token->rxgk->level	= tmp = xdr_dec64(xdr + 2 * 2);
222	if (tmp < -1LL || tmp > RXRPC_SECURITY_ENCRYPT)
223		goto reject_token;
224	token->rxgk->lifetime	= xdr_dec64(xdr + 3 * 2);
225	token->rxgk->bytelife	= xdr_dec64(xdr + 4 * 2);
226	token->rxgk->enctype	= tmp = xdr_dec64(xdr + 5 * 2);
227	if (tmp < 0 || tmp > UINT_MAX)
228		goto reject_token;
229	token->rxgk->key.len	= raw_keylen;
230	token->rxgk->key.data	= token->rxgk->_key;
231	token->rxgk->ticket.len = raw_tktlen;
232
233	if (token->rxgk->endtime != 0) {
234		expiry = rxrpc_s64_to_time64(token->rxgk->endtime);
235		if (expiry < 0)
236			goto expired;
237		if (expiry < prep->expiry)
238			prep->expiry = expiry;
239	}
240
241	memcpy(token->rxgk->key.data, key, token->rxgk->key.len);
242
243	/* Pad the ticket so that we can use it directly in XDR */
244	token->rxgk->ticket.data = kzalloc(tktlen, GFP_KERNEL);
245	if (!token->rxgk->ticket.data)
246		goto nomem_yrxgk;
247	memcpy(token->rxgk->ticket.data, ticket, token->rxgk->ticket.len);
248
249	_debug("SCIX: %u",	token->security_index);
250	_debug("EXPY: %llx",	token->rxgk->endtime);
251	_debug("LIFE: %llx",	token->rxgk->lifetime);
252	_debug("BYTE: %llx",	token->rxgk->bytelife);
253	_debug("ENC : %u",	token->rxgk->enctype);
254	_debug("LEVL: %u",	token->rxgk->level);
255	_debug("KLEN: %u",	token->rxgk->key.len);
256	_debug("TLEN: %u",	token->rxgk->ticket.len);
257	_debug("KEY0: %*phN",	token->rxgk->key.len, token->rxgk->key.data);
258	_debug("TICK: %*phN",
259	       min_t(u32, token->rxgk->ticket.len, 32), token->rxgk->ticket.data);
260
261	/* count the number of tokens attached */
262	prep->payload.data[1] = (void *)((unsigned long)prep->payload.data[1] + 1);
263
264	/* attach the data */
265	for (pptoken = (struct rxrpc_key_token **)&prep->payload.data[0];
266	     *pptoken;
267	     pptoken = &(*pptoken)->next)
268		continue;
269	*pptoken = token;
270
271	_leave(" = 0");
272	return 0;
273
274nomem_yrxgk:
275	kfree(token->rxgk);
276nomem_token:
277	kfree(token);
278nomem:
279	return -ENOMEM;
280reject_token:
281	kfree(token->rxgk);
282	kfree(token);
283reject:
284	return -EKEYREJECTED;
285expired:
286	kfree(token->rxgk);
287	kfree(token);
288	return -EKEYEXPIRED;
289}
290
291/*
292 * attempt to parse the data as the XDR format
293 * - the caller guarantees we have more than 7 words
294 */
295static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)
296{
297	const __be32 *xdr = prep->data, *token, *p;
298	const char *cp;
299	unsigned int len, paddedlen, loop, ntoken, toklen, sec_ix;
300	size_t datalen = prep->datalen;
301	int ret, ret2;
302
303	_enter(",{%x,%x,%x,%x},%zu",
304	       ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
305	       prep->datalen);
306
307	if (datalen > AFSTOKEN_LENGTH_MAX)
308		goto not_xdr;
309
310	/* XDR is an array of __be32's */
311	if (datalen & 3)
312		goto not_xdr;
313
314	/* the flags should be 0 (the setpag bit must be handled by
315	 * userspace) */
316	if (ntohl(*xdr++) != 0)
317		goto not_xdr;
318	datalen -= 4;
319
320	/* check the cell name */
321	len = ntohl(*xdr++);
322	if (len < 1 || len > AFSTOKEN_CELL_MAX)
323		goto not_xdr;
324	datalen -= 4;
325	paddedlen = (len + 3) & ~3;
326	if (paddedlen > datalen)
327		goto not_xdr;
328
329	cp = (const char *) xdr;
330	for (loop = 0; loop < len; loop++)
331		if (!isprint(cp[loop]))
332			goto not_xdr;
333	for (; loop < paddedlen; loop++)
334		if (cp[loop])
335			goto not_xdr;
336	_debug("cellname: [%u/%u] '%*.*s'",
337	       len, paddedlen, len, len, (const char *) xdr);
338	datalen -= paddedlen;
339	xdr += paddedlen >> 2;
340
341	/* get the token count */
342	if (datalen < 12)
343		goto not_xdr;
344	ntoken = ntohl(*xdr++);
345	datalen -= 4;
346	_debug("ntoken: %x", ntoken);
347	if (ntoken < 1 || ntoken > AFSTOKEN_MAX)
348		goto not_xdr;
349
350	/* check each token wrapper */
351	p = xdr;
352	loop = ntoken;
353	do {
354		if (datalen < 8)
355			goto not_xdr;
356		toklen = ntohl(*p++);
357		sec_ix = ntohl(*p);
358		datalen -= 4;
359		_debug("token: [%x/%zx] %x", toklen, datalen, sec_ix);
360		paddedlen = (toklen + 3) & ~3;
361		if (toklen < 20 || toklen > datalen || paddedlen > datalen)
362			goto not_xdr;
363		datalen -= paddedlen;
364		p += paddedlen >> 2;
365
366	} while (--loop > 0);
367
368	_debug("remainder: %zu", datalen);
369	if (datalen != 0)
370		goto not_xdr;
371
372	/* okay: we're going to assume it's valid XDR format
373	 * - we ignore the cellname, relying on the key to be correctly named
374	 */
375	ret = -EPROTONOSUPPORT;
376	do {
377		toklen = ntohl(*xdr++);
378		token = xdr;
379		xdr += (toklen + 3) / 4;
380
381		sec_ix = ntohl(*token++);
382		toklen -= 4;
383
384		_debug("TOKEN type=%x len=%x", sec_ix, toklen);
385
386		switch (sec_ix) {
387		case RXRPC_SECURITY_RXKAD:
388			ret2 = rxrpc_preparse_xdr_rxkad(prep, datalen, token, toklen);
389			break;
390		case RXRPC_SECURITY_YFS_RXGK:
391			ret2 = rxrpc_preparse_xdr_yfs_rxgk(prep, datalen, token, toklen);
392			break;
393		default:
394			ret2 = -EPROTONOSUPPORT;
395			break;
396		}
397
398		switch (ret2) {
399		case 0:
400			ret = 0;
401			break;
402		case -EPROTONOSUPPORT:
403			break;
404		case -ENOPKG:
405			if (ret != 0)
406				ret = -ENOPKG;
407			break;
408		default:
409			ret = ret2;
410			goto error;
411		}
412
413	} while (--ntoken > 0);
414
415error:
416	_leave(" = %d", ret);
417	return ret;
418
419not_xdr:
420	_leave(" = -EPROTO");
421	return -EPROTO;
422}
423
424/*
425 * Preparse an rxrpc defined key.
426 *
427 * Data should be of the form:
428 *	OFFSET	LEN	CONTENT
429 *	0	4	key interface version number
430 *	4	2	security index (type)
431 *	6	2	ticket length
432 *	8	4	key expiry time (time_t)
433 *	12	4	kvno
434 *	16	8	session key
435 *	24	[len]	ticket
436 *
437 * if no data is provided, then a no-security key is made
438 */
439static int rxrpc_preparse(struct key_preparsed_payload *prep)
440{
441	const struct rxrpc_key_data_v1 *v1;
442	struct rxrpc_key_token *token, **pp;
443	time64_t expiry;
444	size_t plen;
445	u32 kver;
446	int ret;
447
448	_enter("%zu", prep->datalen);
449
450	/* handle a no-security key */
451	if (!prep->data && prep->datalen == 0)
452		return 0;
453
454	/* determine if the XDR payload format is being used */
455	if (prep->datalen > 7 * 4) {
456		ret = rxrpc_preparse_xdr(prep);
457		if (ret != -EPROTO)
458			return ret;
459	}
460
461	/* get the key interface version number */
462	ret = -EINVAL;
463	if (prep->datalen <= 4 || !prep->data)
464		goto error;
465	memcpy(&kver, prep->data, sizeof(kver));
466	prep->data += sizeof(kver);
467	prep->datalen -= sizeof(kver);
468	prep->quotalen = 0;
469
470	_debug("KEY I/F VERSION: %u", kver);
471
472	ret = -EKEYREJECTED;
473	if (kver != 1)
474		goto error;
475
476	/* deal with a version 1 key */
477	ret = -EINVAL;
478	if (prep->datalen < sizeof(*v1))
479		goto error;
480
481	v1 = prep->data;
482	if (prep->datalen != sizeof(*v1) + v1->ticket_length)
483		goto error;
484
485	_debug("SCIX: %u", v1->security_index);
486	_debug("TLEN: %u", v1->ticket_length);
487	_debug("EXPY: %x", v1->expiry);
488	_debug("KVNO: %u", v1->kvno);
489	_debug("SKEY: %02x%02x%02x%02x%02x%02x%02x%02x",
490	       v1->session_key[0], v1->session_key[1],
491	       v1->session_key[2], v1->session_key[3],
492	       v1->session_key[4], v1->session_key[5],
493	       v1->session_key[6], v1->session_key[7]);
494	if (v1->ticket_length >= 8)
495		_debug("TCKT: %02x%02x%02x%02x%02x%02x%02x%02x",
496		       v1->ticket[0], v1->ticket[1],
497		       v1->ticket[2], v1->ticket[3],
498		       v1->ticket[4], v1->ticket[5],
499		       v1->ticket[6], v1->ticket[7]);
500
501	ret = -EPROTONOSUPPORT;
502	if (v1->security_index != RXRPC_SECURITY_RXKAD)
503		goto error;
504
505	plen = sizeof(*token->kad) + v1->ticket_length;
506	prep->quotalen += plen + sizeof(*token);
507
508	ret = -ENOMEM;
509	token = kzalloc(sizeof(*token), GFP_KERNEL);
510	if (!token)
511		goto error;
512	token->kad = kzalloc(plen, GFP_KERNEL);
513	if (!token->kad)
514		goto error_free;
515
516	token->security_index		= RXRPC_SECURITY_RXKAD;
517	token->kad->ticket_len		= v1->ticket_length;
518	token->kad->expiry		= v1->expiry;
519	token->kad->kvno		= v1->kvno;
520	memcpy(&token->kad->session_key, &v1->session_key, 8);
521	memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length);
522
523	/* count the number of tokens attached */
524	prep->payload.data[1] = (void *)((unsigned long)prep->payload.data[1] + 1);
525
526	/* attach the data */
527	pp = (struct rxrpc_key_token **)&prep->payload.data[0];
528	while (*pp)
529		pp = &(*pp)->next;
530	*pp = token;
531	expiry = rxrpc_u32_to_time64(token->kad->expiry);
532	if (expiry < prep->expiry)
533		prep->expiry = expiry;
534	token = NULL;
535	ret = 0;
536
537error_free:
538	kfree(token);
539error:
540	return ret;
541}
542
543/*
544 * Free token list.
545 */
546static void rxrpc_free_token_list(struct rxrpc_key_token *token)
547{
548	struct rxrpc_key_token *next;
549
550	for (; token; token = next) {
551		next = token->next;
552		switch (token->security_index) {
553		case RXRPC_SECURITY_RXKAD:
554			kfree(token->kad);
555			break;
556		case RXRPC_SECURITY_YFS_RXGK:
557			kfree(token->rxgk->ticket.data);
558			kfree(token->rxgk);
559			break;
560		default:
561			pr_err("Unknown token type %x on rxrpc key\n",
562			       token->security_index);
563			BUG();
564		}
565
566		kfree(token);
567	}
568}
569
570/*
571 * Clean up preparse data.
572 */
573static void rxrpc_free_preparse(struct key_preparsed_payload *prep)
574{
575	rxrpc_free_token_list(prep->payload.data[0]);
576}
577
578/*
579 * dispose of the data dangling from the corpse of a rxrpc key
580 */
581static void rxrpc_destroy(struct key *key)
582{
583	rxrpc_free_token_list(key->payload.data[0]);
584}
585
586/*
587 * describe the rxrpc key
588 */
589static void rxrpc_describe(const struct key *key, struct seq_file *m)
590{
591	const struct rxrpc_key_token *token;
592	const char *sep = ": ";
593
594	seq_puts(m, key->description);
595
596	for (token = key->payload.data[0]; token; token = token->next) {
597		seq_puts(m, sep);
598
599		switch (token->security_index) {
600		case RXRPC_SECURITY_RXKAD:
601			seq_puts(m, "ka");
602			break;
603		case RXRPC_SECURITY_YFS_RXGK:
604			seq_puts(m, "ygk");
605			break;
606		default: /* we have a ticket we can't encode */
607			seq_printf(m, "%u", token->security_index);
608			break;
609		}
610
611		sep = " ";
612	}
613}
614
615/*
616 * grab the security key for a socket
617 */
618int rxrpc_request_key(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
619{
620	struct key *key;
621	char *description;
622
623	_enter("");
624
625	if (optlen <= 0 || optlen > PAGE_SIZE - 1 || rx->key)
626		return -EINVAL;
627
628	description = memdup_sockptr_nul(optval, optlen);
629	if (IS_ERR(description))
630		return PTR_ERR(description);
631
632	key = request_key_net(&key_type_rxrpc, description, sock_net(&rx->sk), NULL);
633	if (IS_ERR(key)) {
634		kfree(description);
635		_leave(" = %ld", PTR_ERR(key));
636		return PTR_ERR(key);
637	}
638
639	rx->key = key;
640	kfree(description);
641	_leave(" = 0 [key %x]", key->serial);
642	return 0;
643}
644
645/*
646 * generate a server data key
647 */
648int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
649			      const void *session_key,
650			      time64_t expiry,
651			      u32 kvno)
652{
653	const struct cred *cred = current_cred();
654	struct key *key;
655	int ret;
656
657	struct {
658		u32 kver;
659		struct rxrpc_key_data_v1 v1;
660	} data;
661
662	_enter("");
663
664	key = key_alloc(&key_type_rxrpc, "x",
665			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 0,
666			KEY_ALLOC_NOT_IN_QUOTA, NULL);
667	if (IS_ERR(key)) {
668		_leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
669		return -ENOMEM;
670	}
671
672	_debug("key %d", key_serial(key));
673
674	data.kver = 1;
675	data.v1.security_index = RXRPC_SECURITY_RXKAD;
676	data.v1.ticket_length = 0;
677	data.v1.expiry = rxrpc_time64_to_u32(expiry);
678	data.v1.kvno = 0;
679
680	memcpy(&data.v1.session_key, session_key, sizeof(data.v1.session_key));
681
682	ret = key_instantiate_and_link(key, &data, sizeof(data), NULL, NULL);
683	if (ret < 0)
684		goto error;
685
686	conn->key = key;
687	_leave(" = 0 [%d]", key_serial(key));
688	return 0;
689
690error:
691	key_revoke(key);
692	key_put(key);
693	_leave(" = -ENOMEM [ins %d]", ret);
694	return -ENOMEM;
695}
696EXPORT_SYMBOL(rxrpc_get_server_data_key);
697
698/**
699 * rxrpc_get_null_key - Generate a null RxRPC key
700 * @keyname: The name to give the key.
701 *
702 * Generate a null RxRPC key that can be used to indicate anonymous security is
703 * required for a particular domain.
704 *
705 * Return: The new key or a negative error code.
706 */
707struct key *rxrpc_get_null_key(const char *keyname)
708{
709	const struct cred *cred = current_cred();
710	struct key *key;
711	int ret;
712
713	key = key_alloc(&key_type_rxrpc, keyname,
714			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
715			KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA, NULL);
716	if (IS_ERR(key))
717		return key;
718
719	ret = key_instantiate_and_link(key, NULL, 0, NULL, NULL);
720	if (ret < 0) {
721		key_revoke(key);
722		key_put(key);
723		return ERR_PTR(ret);
724	}
725
726	return key;
727}
728EXPORT_SYMBOL(rxrpc_get_null_key);
729
730/*
731 * read the contents of an rxrpc key
732 * - this returns the result in XDR form
733 */
734static long rxrpc_read(const struct key *key,
735		       char *buffer, size_t buflen)
736{
737	const struct rxrpc_key_token *token;
738	size_t size;
739	__be32 *xdr, *oldxdr;
740	u32 cnlen, toksize, ntoks, tok, zero;
741	u16 toksizes[AFSTOKEN_MAX];
742
743	_enter("");
744
745	/* we don't know what form we should return non-AFS keys in */
746	if (memcmp(key->description, "afs@", 4) != 0)
747		return -EOPNOTSUPP;
748	cnlen = strlen(key->description + 4);
749
750#define RND(X) (((X) + 3) & ~3)
751
752	/* AFS keys we return in XDR form, so we need to work out the size of
753	 * the XDR */
754	size = 2 * 4;	/* flags, cellname len */
755	size += RND(cnlen);	/* cellname */
756	size += 1 * 4;	/* token count */
757
758	ntoks = 0;
759	for (token = key->payload.data[0]; token; token = token->next) {
760		toksize = 4;	/* sec index */
761
762		switch (token->security_index) {
763		case RXRPC_SECURITY_RXKAD:
764			toksize += 8 * 4;	/* viceid, kvno, key*2, begin,
765						 * end, primary, tktlen */
766			if (!token->no_leak_key)
767				toksize += RND(token->kad->ticket_len);
768			break;
769
770		case RXRPC_SECURITY_YFS_RXGK:
771			toksize += 6 * 8 + 2 * 4;
772			if (!token->no_leak_key)
773				toksize += RND(token->rxgk->key.len);
774			toksize += RND(token->rxgk->ticket.len);
775			break;
776
777		default: /* we have a ticket we can't encode */
778			pr_err("Unsupported key token type (%u)\n",
779			       token->security_index);
780			return -ENOPKG;
781		}
782
783		_debug("token[%u]: toksize=%u", ntoks, toksize);
784		if (WARN_ON(toksize > AFSTOKEN_LENGTH_MAX))
785			return -EIO;
786
787		toksizes[ntoks++] = toksize;
788		size += toksize + 4; /* each token has a length word */
789	}
790
791#undef RND
792
793	if (!buffer || buflen < size)
794		return size;
795
796	xdr = (__be32 *)buffer;
797	zero = 0;
798#define ENCODE(x)				\
799	do {					\
800		*xdr++ = htonl(x);		\
801	} while(0)
802#define ENCODE_DATA(l, s)						\
803	do {								\
804		u32 _l = (l);						\
805		ENCODE(l);						\
806		memcpy(xdr, (s), _l);					\
807		if (_l & 3)						\
808			memcpy((u8 *)xdr + _l, &zero, 4 - (_l & 3));	\
809		xdr += (_l + 3) >> 2;					\
810	} while(0)
811#define ENCODE_BYTES(l, s)						\
812	do {								\
813		u32 _l = (l);						\
814		memcpy(xdr, (s), _l);					\
815		if (_l & 3)						\
816			memcpy((u8 *)xdr + _l, &zero, 4 - (_l & 3));	\
817		xdr += (_l + 3) >> 2;					\
818	} while(0)
819#define ENCODE64(x)					\
820	do {						\
821		__be64 y = cpu_to_be64(x);		\
822		memcpy(xdr, &y, 8);			\
823		xdr += 8 >> 2;				\
824	} while(0)
825#define ENCODE_STR(s)				\
826	do {					\
827		const char *_s = (s);		\
828		ENCODE_DATA(strlen(_s), _s);	\
829	} while(0)
830
831	ENCODE(0);					/* flags */
832	ENCODE_DATA(cnlen, key->description + 4);	/* cellname */
833	ENCODE(ntoks);
834
835	tok = 0;
836	for (token = key->payload.data[0]; token; token = token->next) {
837		toksize = toksizes[tok++];
838		ENCODE(toksize);
839		oldxdr = xdr;
840		ENCODE(token->security_index);
841
842		switch (token->security_index) {
843		case RXRPC_SECURITY_RXKAD:
844			ENCODE(token->kad->vice_id);
845			ENCODE(token->kad->kvno);
846			ENCODE_BYTES(8, token->kad->session_key);
847			ENCODE(token->kad->start);
848			ENCODE(token->kad->expiry);
849			ENCODE(token->kad->primary_flag);
850			if (token->no_leak_key)
851				ENCODE(0);
852			else
853				ENCODE_DATA(token->kad->ticket_len, token->kad->ticket);
854			break;
855
856		case RXRPC_SECURITY_YFS_RXGK:
857			ENCODE64(token->rxgk->begintime);
858			ENCODE64(token->rxgk->endtime);
859			ENCODE64(token->rxgk->level);
860			ENCODE64(token->rxgk->lifetime);
861			ENCODE64(token->rxgk->bytelife);
862			ENCODE64(token->rxgk->enctype);
863			if (token->no_leak_key)
864				ENCODE(0);
865			else
866				ENCODE_DATA(token->rxgk->key.len, token->rxgk->key.data);
867			ENCODE_DATA(token->rxgk->ticket.len, token->rxgk->ticket.data);
868			break;
869
870		default:
871			pr_err("Unsupported key token type (%u)\n",
872			       token->security_index);
873			return -ENOPKG;
874		}
875
876		if (WARN_ON((unsigned long)xdr - (unsigned long)oldxdr !=
877			    toksize))
878			return -EIO;
879	}
880
881#undef ENCODE_STR
882#undef ENCODE_DATA
883#undef ENCODE64
884#undef ENCODE
885
886	if (WARN_ON(tok != ntoks))
887		return -EIO;
888	if (WARN_ON((unsigned long)xdr - (unsigned long)buffer != size))
889		return -EIO;
890	_leave(" = %zu", size);
891	return size;
892}
~/ Read-only file preview.