blob: 83e3357a65a6966f4e16f9f791f3c97bfe334656 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
David Howells17926a72007-04-26 15:48:28 -07002/* RxRPC key management
3 *
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 *
David Howells17926a72007-04-26 15:48:28 -07007 * RxRPC keys should have a description of describing their purpose:
8 * "afs@CAMBRIDGE.REDHAT.COM>
9 */
10
Joe Perches9b6d5392016-06-02 12:08:52 -070011#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12
Herbert Xu1afe5932016-01-24 21:19:01 +080013#include <crypto/skcipher.h>
David Howells17926a72007-04-26 15:48:28 -070014#include <linux/module.h>
15#include <linux/net.h>
16#include <linux/skbuff.h>
David Howells76181c12007-10-16 23:29:46 -070017#include <linux/key-type.h>
David Howells33941282009-09-14 01:17:35 +000018#include <linux/ctype.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090019#include <linux/slab.h>
David Howells17926a72007-04-26 15:48:28 -070020#include <net/sock.h>
21#include <net/af_rxrpc.h>
22#include <keys/rxrpc-type.h>
23#include <keys/user-type.h>
24#include "ar-internal.h"
25
David Howellsb9fffa32011-03-07 15:05:59 +000026static int rxrpc_vet_description_s(const char *);
David Howells8a7a3eb2014-07-18 18:56:36 +010027static int rxrpc_preparse(struct key_preparsed_payload *);
28static int rxrpc_preparse_s(struct key_preparsed_payload *);
29static void rxrpc_free_preparse(struct key_preparsed_payload *);
30static void rxrpc_free_preparse_s(struct key_preparsed_payload *);
David Howells17926a72007-04-26 15:48:28 -070031static void rxrpc_destroy(struct key *);
32static void rxrpc_destroy_s(struct key *);
33static void rxrpc_describe(const struct key *, struct seq_file *);
David Howellsed6dd182009-09-14 01:17:40 +000034static long rxrpc_read(const struct key *, char __user *, size_t);
David Howells17926a72007-04-26 15:48:28 -070035
36/*
37 * rxrpc defined keys take an arbitrary string as the description and an
38 * arbitrary blob of data as the payload
39 */
40struct key_type key_type_rxrpc = {
41 .name = "rxrpc",
David Howells8a7a3eb2014-07-18 18:56:36 +010042 .preparse = rxrpc_preparse,
43 .free_preparse = rxrpc_free_preparse,
44 .instantiate = generic_key_instantiate,
David Howells17926a72007-04-26 15:48:28 -070045 .destroy = rxrpc_destroy,
46 .describe = rxrpc_describe,
David Howellsed6dd182009-09-14 01:17:40 +000047 .read = rxrpc_read,
David Howells17926a72007-04-26 15:48:28 -070048};
David Howells17926a72007-04-26 15:48:28 -070049EXPORT_SYMBOL(key_type_rxrpc);
50
51/*
52 * rxrpc server defined keys take "<serviceId>:<securityIndex>" as the
53 * description and an 8-byte decryption key as the payload
54 */
55struct key_type key_type_rxrpc_s = {
56 .name = "rxrpc_s",
David Howellsb9fffa32011-03-07 15:05:59 +000057 .vet_description = rxrpc_vet_description_s,
David Howells8a7a3eb2014-07-18 18:56:36 +010058 .preparse = rxrpc_preparse_s,
59 .free_preparse = rxrpc_free_preparse_s,
60 .instantiate = generic_key_instantiate,
David Howells17926a72007-04-26 15:48:28 -070061 .destroy = rxrpc_destroy_s,
62 .describe = rxrpc_describe,
63};
64
65/*
David Howellsb9fffa32011-03-07 15:05:59 +000066 * Vet the description for an RxRPC server key
67 */
68static int rxrpc_vet_description_s(const char *desc)
69{
70 unsigned long num;
71 char *p;
72
73 num = simple_strtoul(desc, &p, 10);
74 if (*p != ':' || num > 65535)
75 return -EINVAL;
76 num = simple_strtoul(p + 1, &p, 10);
77 if (*p || num < 1 || num > 255)
78 return -EINVAL;
79 return 0;
80}
81
82/*
David Howells33941282009-09-14 01:17:35 +000083 * parse an RxKAD type XDR format token
84 * - the caller guarantees we have at least 4 words
85 */
David Howells8a7a3eb2014-07-18 18:56:36 +010086static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
87 size_t datalen,
88 const __be32 *xdr, unsigned int toklen)
David Howells33941282009-09-14 01:17:35 +000089{
David Howells994551532009-09-14 01:17:46 +000090 struct rxrpc_key_token *token, **pptoken;
Baolin Wang10674a02017-08-29 10:15:40 +010091 time64_t expiry;
David Howells33941282009-09-14 01:17:35 +000092 size_t plen;
93 u32 tktlen;
David Howells33941282009-09-14 01:17:35 +000094
95 _enter(",{%x,%x,%x,%x},%u",
96 ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
97 toklen);
98
99 if (toklen <= 8 * 4)
100 return -EKEYREJECTED;
101 tktlen = ntohl(xdr[7]);
102 _debug("tktlen: %x", tktlen);
103 if (tktlen > AFSTOKEN_RK_TIX_MAX)
104 return -EKEYREJECTED;
Nathaniel W Filardofde01332014-05-15 15:51:22 +0100105 if (toklen < 8 * 4 + tktlen)
David Howells33941282009-09-14 01:17:35 +0000106 return -EKEYREJECTED;
107
108 plen = sizeof(*token) + sizeof(*token->kad) + tktlen;
David Howells8a7a3eb2014-07-18 18:56:36 +0100109 prep->quotalen = datalen + plen;
David Howells33941282009-09-14 01:17:35 +0000110
111 plen -= sizeof(*token);
Anton Blanchard0a93ea22011-02-25 15:33:17 +0000112 token = kzalloc(sizeof(*token), GFP_KERNEL);
David Howells33941282009-09-14 01:17:35 +0000113 if (!token)
114 return -ENOMEM;
115
Anton Blanchard0a93ea22011-02-25 15:33:17 +0000116 token->kad = kzalloc(plen, GFP_KERNEL);
David Howells33941282009-09-14 01:17:35 +0000117 if (!token->kad) {
118 kfree(token);
119 return -ENOMEM;
120 }
121
122 token->security_index = RXRPC_SECURITY_RXKAD;
123 token->kad->ticket_len = tktlen;
124 token->kad->vice_id = ntohl(xdr[0]);
125 token->kad->kvno = ntohl(xdr[1]);
126 token->kad->start = ntohl(xdr[4]);
127 token->kad->expiry = ntohl(xdr[5]);
128 token->kad->primary_flag = ntohl(xdr[6]);
129 memcpy(&token->kad->session_key, &xdr[2], 8);
130 memcpy(&token->kad->ticket, &xdr[8], tktlen);
131
132 _debug("SCIX: %u", token->security_index);
133 _debug("TLEN: %u", token->kad->ticket_len);
134 _debug("EXPY: %x", token->kad->expiry);
135 _debug("KVNO: %u", token->kad->kvno);
136 _debug("PRIM: %u", token->kad->primary_flag);
137 _debug("SKEY: %02x%02x%02x%02x%02x%02x%02x%02x",
138 token->kad->session_key[0], token->kad->session_key[1],
139 token->kad->session_key[2], token->kad->session_key[3],
140 token->kad->session_key[4], token->kad->session_key[5],
141 token->kad->session_key[6], token->kad->session_key[7]);
142 if (token->kad->ticket_len >= 8)
143 _debug("TCKT: %02x%02x%02x%02x%02x%02x%02x%02x",
144 token->kad->ticket[0], token->kad->ticket[1],
145 token->kad->ticket[2], token->kad->ticket[3],
146 token->kad->ticket[4], token->kad->ticket[5],
147 token->kad->ticket[6], token->kad->ticket[7]);
148
149 /* count the number of tokens attached */
David Howells146aa8b2015-10-21 14:04:48 +0100150 prep->payload.data[1] = (void *)((unsigned long)prep->payload.data[1] + 1);
David Howells33941282009-09-14 01:17:35 +0000151
152 /* attach the data */
David Howells146aa8b2015-10-21 14:04:48 +0100153 for (pptoken = (struct rxrpc_key_token **)&prep->payload.data[0];
David Howells994551532009-09-14 01:17:46 +0000154 *pptoken;
155 pptoken = &(*pptoken)->next)
156 continue;
157 *pptoken = token;
Baolin Wang10674a02017-08-29 10:15:40 +0100158 expiry = rxrpc_u32_to_time64(token->kad->expiry);
159 if (expiry < prep->expiry)
160 prep->expiry = expiry;
David Howells33941282009-09-14 01:17:35 +0000161
162 _leave(" = 0");
163 return 0;
164}
165
David Howells994551532009-09-14 01:17:46 +0000166static void rxrpc_free_krb5_principal(struct krb5_principal *princ)
167{
168 int loop;
169
170 if (princ->name_parts) {
171 for (loop = princ->n_name_parts - 1; loop >= 0; loop--)
172 kfree(princ->name_parts[loop]);
173 kfree(princ->name_parts);
174 }
175 kfree(princ->realm);
176}
177
178static void rxrpc_free_krb5_tagged(struct krb5_tagged_data *td)
179{
180 kfree(td->data);
181}
182
183/*
184 * free up an RxK5 token
185 */
186static void rxrpc_rxk5_free(struct rxk5_key *rxk5)
187{
188 int loop;
189
190 rxrpc_free_krb5_principal(&rxk5->client);
191 rxrpc_free_krb5_principal(&rxk5->server);
192 rxrpc_free_krb5_tagged(&rxk5->session);
193
194 if (rxk5->addresses) {
195 for (loop = rxk5->n_addresses - 1; loop >= 0; loop--)
196 rxrpc_free_krb5_tagged(&rxk5->addresses[loop]);
197 kfree(rxk5->addresses);
198 }
199 if (rxk5->authdata) {
200 for (loop = rxk5->n_authdata - 1; loop >= 0; loop--)
201 rxrpc_free_krb5_tagged(&rxk5->authdata[loop]);
202 kfree(rxk5->authdata);
203 }
204
205 kfree(rxk5->ticket);
206 kfree(rxk5->ticket2);
207 kfree(rxk5);
208}
209
210/*
211 * extract a krb5 principal
212 */
213static int rxrpc_krb5_decode_principal(struct krb5_principal *princ,
214 const __be32 **_xdr,
Eric Dumazet95c96172012-04-15 05:58:06 +0000215 unsigned int *_toklen)
David Howells994551532009-09-14 01:17:46 +0000216{
217 const __be32 *xdr = *_xdr;
David Howells5f2f9762017-06-15 00:12:24 +0100218 unsigned int toklen = *_toklen, n_parts, loop, tmp, paddedlen;
David Howells994551532009-09-14 01:17:46 +0000219
220 /* there must be at least one name, and at least #names+1 length
221 * words */
222 if (toklen <= 12)
223 return -EINVAL;
224
225 _enter(",{%x,%x,%x},%u",
226 ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), toklen);
227
228 n_parts = ntohl(*xdr++);
229 toklen -= 4;
230 if (n_parts <= 0 || n_parts > AFSTOKEN_K5_COMPONENTS_MAX)
231 return -EINVAL;
232 princ->n_name_parts = n_parts;
233
234 if (toklen <= (n_parts + 1) * 4)
235 return -EINVAL;
236
Axel Linf65bd5e2012-02-13 20:19:14 +0000237 princ->name_parts = kcalloc(n_parts, sizeof(char *), GFP_KERNEL);
David Howells994551532009-09-14 01:17:46 +0000238 if (!princ->name_parts)
239 return -ENOMEM;
240
241 for (loop = 0; loop < n_parts; loop++) {
242 if (toklen < 4)
243 return -EINVAL;
244 tmp = ntohl(*xdr++);
245 toklen -= 4;
246 if (tmp <= 0 || tmp > AFSTOKEN_STRING_MAX)
247 return -EINVAL;
David Howells5f2f9762017-06-15 00:12:24 +0100248 paddedlen = (tmp + 3) & ~3;
249 if (paddedlen > toklen)
David Howells994551532009-09-14 01:17:46 +0000250 return -EINVAL;
251 princ->name_parts[loop] = kmalloc(tmp + 1, GFP_KERNEL);
252 if (!princ->name_parts[loop])
253 return -ENOMEM;
254 memcpy(princ->name_parts[loop], xdr, tmp);
255 princ->name_parts[loop][tmp] = 0;
David Howells5f2f9762017-06-15 00:12:24 +0100256 toklen -= paddedlen;
257 xdr += paddedlen >> 2;
David Howells994551532009-09-14 01:17:46 +0000258 }
259
260 if (toklen < 4)
261 return -EINVAL;
262 tmp = ntohl(*xdr++);
263 toklen -= 4;
264 if (tmp <= 0 || tmp > AFSTOKEN_K5_REALM_MAX)
265 return -EINVAL;
David Howells5f2f9762017-06-15 00:12:24 +0100266 paddedlen = (tmp + 3) & ~3;
267 if (paddedlen > toklen)
David Howells994551532009-09-14 01:17:46 +0000268 return -EINVAL;
269 princ->realm = kmalloc(tmp + 1, GFP_KERNEL);
270 if (!princ->realm)
271 return -ENOMEM;
272 memcpy(princ->realm, xdr, tmp);
273 princ->realm[tmp] = 0;
David Howells5f2f9762017-06-15 00:12:24 +0100274 toklen -= paddedlen;
275 xdr += paddedlen >> 2;
David Howells994551532009-09-14 01:17:46 +0000276
277 _debug("%s/...@%s", princ->name_parts[0], princ->realm);
278
279 *_xdr = xdr;
280 *_toklen = toklen;
281 _leave(" = 0 [toklen=%u]", toklen);
282 return 0;
283}
284
285/*
286 * extract a piece of krb5 tagged data
287 */
288static int rxrpc_krb5_decode_tagged_data(struct krb5_tagged_data *td,
289 size_t max_data_size,
290 const __be32 **_xdr,
Eric Dumazet95c96172012-04-15 05:58:06 +0000291 unsigned int *_toklen)
David Howells994551532009-09-14 01:17:46 +0000292{
293 const __be32 *xdr = *_xdr;
David Howells5f2f9762017-06-15 00:12:24 +0100294 unsigned int toklen = *_toklen, len, paddedlen;
David Howells994551532009-09-14 01:17:46 +0000295
296 /* there must be at least one tag and one length word */
297 if (toklen <= 8)
298 return -EINVAL;
299
300 _enter(",%zu,{%x,%x},%u",
301 max_data_size, ntohl(xdr[0]), ntohl(xdr[1]), toklen);
302
303 td->tag = ntohl(*xdr++);
304 len = ntohl(*xdr++);
305 toklen -= 8;
306 if (len > max_data_size)
307 return -EINVAL;
David Howells5f2f9762017-06-15 00:12:24 +0100308 paddedlen = (len + 3) & ~3;
309 if (paddedlen > toklen)
310 return -EINVAL;
David Howells994551532009-09-14 01:17:46 +0000311 td->data_len = len;
312
313 if (len > 0) {
Thomas Meyer65d9d2c2011-11-17 12:43:40 +0000314 td->data = kmemdup(xdr, len, GFP_KERNEL);
David Howells994551532009-09-14 01:17:46 +0000315 if (!td->data)
316 return -ENOMEM;
David Howells5f2f9762017-06-15 00:12:24 +0100317 toklen -= paddedlen;
318 xdr += paddedlen >> 2;
David Howells994551532009-09-14 01:17:46 +0000319 }
320
321 _debug("tag %x len %x", td->tag, td->data_len);
322
323 *_xdr = xdr;
324 *_toklen = toklen;
325 _leave(" = 0 [toklen=%u]", toklen);
326 return 0;
327}
328
329/*
330 * extract an array of tagged data
331 */
332static int rxrpc_krb5_decode_tagged_array(struct krb5_tagged_data **_td,
333 u8 *_n_elem,
334 u8 max_n_elem,
335 size_t max_elem_size,
336 const __be32 **_xdr,
Eric Dumazet95c96172012-04-15 05:58:06 +0000337 unsigned int *_toklen)
David Howells994551532009-09-14 01:17:46 +0000338{
339 struct krb5_tagged_data *td;
340 const __be32 *xdr = *_xdr;
Eric Dumazet95c96172012-04-15 05:58:06 +0000341 unsigned int toklen = *_toklen, n_elem, loop;
David Howells994551532009-09-14 01:17:46 +0000342 int ret;
343
344 /* there must be at least one count */
345 if (toklen < 4)
346 return -EINVAL;
347
348 _enter(",,%u,%zu,{%x},%u",
349 max_n_elem, max_elem_size, ntohl(xdr[0]), toklen);
350
351 n_elem = ntohl(*xdr++);
352 toklen -= 4;
Andrey Utkinfa4eff42014-07-18 18:31:57 +0300353 if (n_elem > max_n_elem)
David Howells994551532009-09-14 01:17:46 +0000354 return -EINVAL;
355 *_n_elem = n_elem;
356 if (n_elem > 0) {
357 if (toklen <= (n_elem + 1) * 4)
358 return -EINVAL;
359
360 _debug("n_elem %d", n_elem);
361
Axel Linf65bd5e2012-02-13 20:19:14 +0000362 td = kcalloc(n_elem, sizeof(struct krb5_tagged_data),
David Howells994551532009-09-14 01:17:46 +0000363 GFP_KERNEL);
364 if (!td)
365 return -ENOMEM;
366 *_td = td;
367
368 for (loop = 0; loop < n_elem; loop++) {
369 ret = rxrpc_krb5_decode_tagged_data(&td[loop],
370 max_elem_size,
371 &xdr, &toklen);
372 if (ret < 0)
373 return ret;
374 }
375 }
376
377 *_xdr = xdr;
378 *_toklen = toklen;
379 _leave(" = 0 [toklen=%u]", toklen);
380 return 0;
381}
382
383/*
384 * extract a krb5 ticket
385 */
David Howells4e36a952009-09-16 00:01:13 -0700386static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen,
Eric Dumazet95c96172012-04-15 05:58:06 +0000387 const __be32 **_xdr, unsigned int *_toklen)
David Howells994551532009-09-14 01:17:46 +0000388{
389 const __be32 *xdr = *_xdr;
David Howells5f2f9762017-06-15 00:12:24 +0100390 unsigned int toklen = *_toklen, len, paddedlen;
David Howells994551532009-09-14 01:17:46 +0000391
392 /* there must be at least one length word */
393 if (toklen <= 4)
394 return -EINVAL;
395
396 _enter(",{%x},%u", ntohl(xdr[0]), toklen);
397
398 len = ntohl(*xdr++);
399 toklen -= 4;
400 if (len > AFSTOKEN_K5_TIX_MAX)
401 return -EINVAL;
David Howells5f2f9762017-06-15 00:12:24 +0100402 paddedlen = (len + 3) & ~3;
403 if (paddedlen > toklen)
404 return -EINVAL;
David Howells994551532009-09-14 01:17:46 +0000405 *_tktlen = len;
406
407 _debug("ticket len %u", len);
408
409 if (len > 0) {
Thomas Meyer65d9d2c2011-11-17 12:43:40 +0000410 *_ticket = kmemdup(xdr, len, GFP_KERNEL);
David Howells994551532009-09-14 01:17:46 +0000411 if (!*_ticket)
412 return -ENOMEM;
David Howells5f2f9762017-06-15 00:12:24 +0100413 toklen -= paddedlen;
414 xdr += paddedlen >> 2;
David Howells994551532009-09-14 01:17:46 +0000415 }
416
417 *_xdr = xdr;
418 *_toklen = toklen;
419 _leave(" = 0 [toklen=%u]", toklen);
420 return 0;
421}
422
423/*
424 * parse an RxK5 type XDR format token
425 * - the caller guarantees we have at least 4 words
426 */
David Howells8a7a3eb2014-07-18 18:56:36 +0100427static int rxrpc_preparse_xdr_rxk5(struct key_preparsed_payload *prep,
428 size_t datalen,
429 const __be32 *xdr, unsigned int toklen)
David Howells994551532009-09-14 01:17:46 +0000430{
431 struct rxrpc_key_token *token, **pptoken;
432 struct rxk5_key *rxk5;
433 const __be32 *end_xdr = xdr + (toklen >> 2);
Baolin Wang10674a02017-08-29 10:15:40 +0100434 time64_t expiry;
David Howells994551532009-09-14 01:17:46 +0000435 int ret;
436
437 _enter(",{%x,%x,%x,%x},%u",
438 ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
439 toklen);
440
441 /* reserve some payload space for this subkey - the length of the token
442 * is a reasonable approximation */
David Howells8a7a3eb2014-07-18 18:56:36 +0100443 prep->quotalen = datalen + toklen;
David Howells994551532009-09-14 01:17:46 +0000444
445 token = kzalloc(sizeof(*token), GFP_KERNEL);
446 if (!token)
447 return -ENOMEM;
448
449 rxk5 = kzalloc(sizeof(*rxk5), GFP_KERNEL);
450 if (!rxk5) {
451 kfree(token);
452 return -ENOMEM;
453 }
454
455 token->security_index = RXRPC_SECURITY_RXK5;
456 token->k5 = rxk5;
457
458 /* extract the principals */
459 ret = rxrpc_krb5_decode_principal(&rxk5->client, &xdr, &toklen);
460 if (ret < 0)
461 goto error;
462 ret = rxrpc_krb5_decode_principal(&rxk5->server, &xdr, &toklen);
463 if (ret < 0)
464 goto error;
465
466 /* extract the session key and the encoding type (the tag field ->
467 * ENCTYPE_xxx) */
468 ret = rxrpc_krb5_decode_tagged_data(&rxk5->session, AFSTOKEN_DATA_MAX,
469 &xdr, &toklen);
470 if (ret < 0)
471 goto error;
472
473 if (toklen < 4 * 8 + 2 * 4)
474 goto inval;
475 rxk5->authtime = be64_to_cpup((const __be64 *) xdr);
476 xdr += 2;
477 rxk5->starttime = be64_to_cpup((const __be64 *) xdr);
478 xdr += 2;
479 rxk5->endtime = be64_to_cpup((const __be64 *) xdr);
480 xdr += 2;
481 rxk5->renew_till = be64_to_cpup((const __be64 *) xdr);
482 xdr += 2;
483 rxk5->is_skey = ntohl(*xdr++);
484 rxk5->flags = ntohl(*xdr++);
485 toklen -= 4 * 8 + 2 * 4;
486
487 _debug("times: a=%llx s=%llx e=%llx rt=%llx",
488 rxk5->authtime, rxk5->starttime, rxk5->endtime,
489 rxk5->renew_till);
490 _debug("is_skey=%x flags=%x", rxk5->is_skey, rxk5->flags);
491
492 /* extract the permitted client addresses */
493 ret = rxrpc_krb5_decode_tagged_array(&rxk5->addresses,
494 &rxk5->n_addresses,
495 AFSTOKEN_K5_ADDRESSES_MAX,
496 AFSTOKEN_DATA_MAX,
497 &xdr, &toklen);
498 if (ret < 0)
499 goto error;
500
501 ASSERTCMP((end_xdr - xdr) << 2, ==, toklen);
502
503 /* extract the tickets */
504 ret = rxrpc_krb5_decode_ticket(&rxk5->ticket, &rxk5->ticket_len,
505 &xdr, &toklen);
506 if (ret < 0)
507 goto error;
508 ret = rxrpc_krb5_decode_ticket(&rxk5->ticket2, &rxk5->ticket2_len,
509 &xdr, &toklen);
510 if (ret < 0)
511 goto error;
512
513 ASSERTCMP((end_xdr - xdr) << 2, ==, toklen);
514
515 /* extract the typed auth data */
516 ret = rxrpc_krb5_decode_tagged_array(&rxk5->authdata,
517 &rxk5->n_authdata,
518 AFSTOKEN_K5_AUTHDATA_MAX,
519 AFSTOKEN_BDATALN_MAX,
520 &xdr, &toklen);
521 if (ret < 0)
522 goto error;
523
524 ASSERTCMP((end_xdr - xdr) << 2, ==, toklen);
525
526 if (toklen != 0)
527 goto inval;
528
David Howells8a7a3eb2014-07-18 18:56:36 +0100529 /* attach the payload */
David Howells146aa8b2015-10-21 14:04:48 +0100530 for (pptoken = (struct rxrpc_key_token **)&prep->payload.data[0];
David Howells994551532009-09-14 01:17:46 +0000531 *pptoken;
532 pptoken = &(*pptoken)->next)
533 continue;
534 *pptoken = token;
David Howells0a378582017-08-29 10:15:40 +0100535 expiry = rxrpc_u32_to_time64(token->k5->endtime);
Baolin Wang10674a02017-08-29 10:15:40 +0100536 if (expiry < prep->expiry)
537 prep->expiry = expiry;
David Howells994551532009-09-14 01:17:46 +0000538
539 _leave(" = 0");
540 return 0;
541
542inval:
543 ret = -EINVAL;
544error:
545 rxrpc_rxk5_free(rxk5);
546 kfree(token);
547 _leave(" = %d", ret);
548 return ret;
549}
550
David Howells33941282009-09-14 01:17:35 +0000551/*
552 * attempt to parse the data as the XDR format
553 * - the caller guarantees we have more than 7 words
554 */
David Howells8a7a3eb2014-07-18 18:56:36 +0100555static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)
David Howells33941282009-09-14 01:17:35 +0000556{
David Howells8a7a3eb2014-07-18 18:56:36 +0100557 const __be32 *xdr = prep->data, *token;
David Howells33941282009-09-14 01:17:35 +0000558 const char *cp;
David Howells5f2f9762017-06-15 00:12:24 +0100559 unsigned int len, paddedlen, loop, ntoken, toklen, sec_ix;
David Howells8a7a3eb2014-07-18 18:56:36 +0100560 size_t datalen = prep->datalen;
David Howells33941282009-09-14 01:17:35 +0000561 int ret;
562
563 _enter(",{%x,%x,%x,%x},%zu",
564 ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
David Howells8a7a3eb2014-07-18 18:56:36 +0100565 prep->datalen);
David Howells33941282009-09-14 01:17:35 +0000566
567 if (datalen > AFSTOKEN_LENGTH_MAX)
568 goto not_xdr;
569
570 /* XDR is an array of __be32's */
571 if (datalen & 3)
572 goto not_xdr;
573
574 /* the flags should be 0 (the setpag bit must be handled by
575 * userspace) */
576 if (ntohl(*xdr++) != 0)
577 goto not_xdr;
578 datalen -= 4;
579
580 /* check the cell name */
581 len = ntohl(*xdr++);
582 if (len < 1 || len > AFSTOKEN_CELL_MAX)
583 goto not_xdr;
584 datalen -= 4;
David Howells5f2f9762017-06-15 00:12:24 +0100585 paddedlen = (len + 3) & ~3;
586 if (paddedlen > datalen)
David Howells33941282009-09-14 01:17:35 +0000587 goto not_xdr;
588
589 cp = (const char *) xdr;
590 for (loop = 0; loop < len; loop++)
591 if (!isprint(cp[loop]))
592 goto not_xdr;
David Howells5f2f9762017-06-15 00:12:24 +0100593 for (; loop < paddedlen; loop++)
594 if (cp[loop])
595 goto not_xdr;
David Howells33941282009-09-14 01:17:35 +0000596 _debug("cellname: [%u/%u] '%*.*s'",
David Howells5f2f9762017-06-15 00:12:24 +0100597 len, paddedlen, len, len, (const char *) xdr);
598 datalen -= paddedlen;
599 xdr += paddedlen >> 2;
David Howells33941282009-09-14 01:17:35 +0000600
601 /* get the token count */
602 if (datalen < 12)
603 goto not_xdr;
604 ntoken = ntohl(*xdr++);
605 datalen -= 4;
606 _debug("ntoken: %x", ntoken);
607 if (ntoken < 1 || ntoken > AFSTOKEN_MAX)
608 goto not_xdr;
609
610 /* check each token wrapper */
611 token = xdr;
612 loop = ntoken;
613 do {
614 if (datalen < 8)
615 goto not_xdr;
616 toklen = ntohl(*xdr++);
617 sec_ix = ntohl(*xdr);
618 datalen -= 4;
619 _debug("token: [%x/%zx] %x", toklen, datalen, sec_ix);
David Howells5f2f9762017-06-15 00:12:24 +0100620 paddedlen = (toklen + 3) & ~3;
621 if (toklen < 20 || toklen > datalen || paddedlen > datalen)
David Howells33941282009-09-14 01:17:35 +0000622 goto not_xdr;
David Howells5f2f9762017-06-15 00:12:24 +0100623 datalen -= paddedlen;
624 xdr += paddedlen >> 2;
David Howells33941282009-09-14 01:17:35 +0000625
626 } while (--loop > 0);
627
628 _debug("remainder: %zu", datalen);
629 if (datalen != 0)
630 goto not_xdr;
631
632 /* okay: we're going to assume it's valid XDR format
633 * - we ignore the cellname, relying on the key to be correctly named
634 */
635 do {
636 xdr = token;
637 toklen = ntohl(*xdr++);
638 token = xdr + ((toklen + 3) >> 2);
639 sec_ix = ntohl(*xdr++);
640 toklen -= 4;
641
David Howells994551532009-09-14 01:17:46 +0000642 _debug("TOKEN type=%u [%p-%p]", sec_ix, xdr, token);
643
David Howells33941282009-09-14 01:17:35 +0000644 switch (sec_ix) {
645 case RXRPC_SECURITY_RXKAD:
David Howells8a7a3eb2014-07-18 18:56:36 +0100646 ret = rxrpc_preparse_xdr_rxkad(prep, datalen, xdr, toklen);
David Howells33941282009-09-14 01:17:35 +0000647 if (ret != 0)
648 goto error;
649 break;
650
David Howells994551532009-09-14 01:17:46 +0000651 case RXRPC_SECURITY_RXK5:
David Howells8a7a3eb2014-07-18 18:56:36 +0100652 ret = rxrpc_preparse_xdr_rxk5(prep, datalen, xdr, toklen);
David Howells994551532009-09-14 01:17:46 +0000653 if (ret != 0)
654 goto error;
655 break;
656
David Howells33941282009-09-14 01:17:35 +0000657 default:
658 ret = -EPROTONOSUPPORT;
659 goto error;
660 }
661
662 } while (--ntoken > 0);
663
664 _leave(" = 0");
665 return 0;
666
667not_xdr:
668 _leave(" = -EPROTO");
669 return -EPROTO;
670error:
671 _leave(" = %d", ret);
672 return ret;
673}
674
675/*
David Howells8a7a3eb2014-07-18 18:56:36 +0100676 * Preparse an rxrpc defined key.
677 *
678 * Data should be of the form:
David Howells17926a72007-04-26 15:48:28 -0700679 * OFFSET LEN CONTENT
680 * 0 4 key interface version number
681 * 4 2 security index (type)
682 * 6 2 ticket length
683 * 8 4 key expiry time (time_t)
684 * 12 4 kvno
685 * 16 8 session key
686 * 24 [len] ticket
687 *
688 * if no data is provided, then a no-security key is made
689 */
David Howells8a7a3eb2014-07-18 18:56:36 +0100690static int rxrpc_preparse(struct key_preparsed_payload *prep)
David Howells17926a72007-04-26 15:48:28 -0700691{
David Howells33941282009-09-14 01:17:35 +0000692 const struct rxrpc_key_data_v1 *v1;
693 struct rxrpc_key_token *token, **pp;
Baolin Wang10674a02017-08-29 10:15:40 +0100694 time64_t expiry;
David Howells17926a72007-04-26 15:48:28 -0700695 size_t plen;
696 u32 kver;
697 int ret;
698
David Howells8a7a3eb2014-07-18 18:56:36 +0100699 _enter("%zu", prep->datalen);
David Howells17926a72007-04-26 15:48:28 -0700700
701 /* handle a no-security key */
David Howellscf7f6012012-09-13 13:06:29 +0100702 if (!prep->data && prep->datalen == 0)
David Howells17926a72007-04-26 15:48:28 -0700703 return 0;
704
David Howells33941282009-09-14 01:17:35 +0000705 /* determine if the XDR payload format is being used */
David Howellscf7f6012012-09-13 13:06:29 +0100706 if (prep->datalen > 7 * 4) {
David Howells8a7a3eb2014-07-18 18:56:36 +0100707 ret = rxrpc_preparse_xdr(prep);
David Howells33941282009-09-14 01:17:35 +0000708 if (ret != -EPROTO)
709 return ret;
710 }
711
David Howells17926a72007-04-26 15:48:28 -0700712 /* get the key interface version number */
713 ret = -EINVAL;
David Howellscf7f6012012-09-13 13:06:29 +0100714 if (prep->datalen <= 4 || !prep->data)
David Howells17926a72007-04-26 15:48:28 -0700715 goto error;
David Howellscf7f6012012-09-13 13:06:29 +0100716 memcpy(&kver, prep->data, sizeof(kver));
717 prep->data += sizeof(kver);
718 prep->datalen -= sizeof(kver);
David Howells17926a72007-04-26 15:48:28 -0700719
720 _debug("KEY I/F VERSION: %u", kver);
721
722 ret = -EKEYREJECTED;
723 if (kver != 1)
724 goto error;
725
726 /* deal with a version 1 key */
727 ret = -EINVAL;
David Howellscf7f6012012-09-13 13:06:29 +0100728 if (prep->datalen < sizeof(*v1))
David Howells17926a72007-04-26 15:48:28 -0700729 goto error;
730
David Howellscf7f6012012-09-13 13:06:29 +0100731 v1 = prep->data;
732 if (prep->datalen != sizeof(*v1) + v1->ticket_length)
David Howells17926a72007-04-26 15:48:28 -0700733 goto error;
734
David Howells33941282009-09-14 01:17:35 +0000735 _debug("SCIX: %u", v1->security_index);
736 _debug("TLEN: %u", v1->ticket_length);
737 _debug("EXPY: %x", v1->expiry);
738 _debug("KVNO: %u", v1->kvno);
David Howells17926a72007-04-26 15:48:28 -0700739 _debug("SKEY: %02x%02x%02x%02x%02x%02x%02x%02x",
David Howells33941282009-09-14 01:17:35 +0000740 v1->session_key[0], v1->session_key[1],
741 v1->session_key[2], v1->session_key[3],
742 v1->session_key[4], v1->session_key[5],
743 v1->session_key[6], v1->session_key[7]);
744 if (v1->ticket_length >= 8)
David Howells17926a72007-04-26 15:48:28 -0700745 _debug("TCKT: %02x%02x%02x%02x%02x%02x%02x%02x",
David Howells33941282009-09-14 01:17:35 +0000746 v1->ticket[0], v1->ticket[1],
747 v1->ticket[2], v1->ticket[3],
748 v1->ticket[4], v1->ticket[5],
749 v1->ticket[6], v1->ticket[7]);
David Howells17926a72007-04-26 15:48:28 -0700750
751 ret = -EPROTONOSUPPORT;
David Howells33941282009-09-14 01:17:35 +0000752 if (v1->security_index != RXRPC_SECURITY_RXKAD)
David Howells17926a72007-04-26 15:48:28 -0700753 goto error;
754
David Howells33941282009-09-14 01:17:35 +0000755 plen = sizeof(*token->kad) + v1->ticket_length;
David Howells8a7a3eb2014-07-18 18:56:36 +0100756 prep->quotalen = plen + sizeof(*token);
David Howells17926a72007-04-26 15:48:28 -0700757
758 ret = -ENOMEM;
Anton Blanchard0a93ea22011-02-25 15:33:17 +0000759 token = kzalloc(sizeof(*token), GFP_KERNEL);
David Howells33941282009-09-14 01:17:35 +0000760 if (!token)
David Howells17926a72007-04-26 15:48:28 -0700761 goto error;
Anton Blanchard0a93ea22011-02-25 15:33:17 +0000762 token->kad = kzalloc(plen, GFP_KERNEL);
David Howells33941282009-09-14 01:17:35 +0000763 if (!token->kad)
764 goto error_free;
765
766 token->security_index = RXRPC_SECURITY_RXKAD;
767 token->kad->ticket_len = v1->ticket_length;
768 token->kad->expiry = v1->expiry;
769 token->kad->kvno = v1->kvno;
770 memcpy(&token->kad->session_key, &v1->session_key, 8);
771 memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length);
David Howells17926a72007-04-26 15:48:28 -0700772
David Howells8a7a3eb2014-07-18 18:56:36 +0100773 /* count the number of tokens attached */
David Howells146aa8b2015-10-21 14:04:48 +0100774 prep->payload.data[1] = (void *)((unsigned long)prep->payload.data[1] + 1);
David Howells33941282009-09-14 01:17:35 +0000775
David Howells8a7a3eb2014-07-18 18:56:36 +0100776 /* attach the data */
David Howells146aa8b2015-10-21 14:04:48 +0100777 pp = (struct rxrpc_key_token **)&prep->payload.data[0];
David Howells33941282009-09-14 01:17:35 +0000778 while (*pp)
779 pp = &(*pp)->next;
780 *pp = token;
Baolin Wang10674a02017-08-29 10:15:40 +0100781 expiry = rxrpc_u32_to_time64(token->kad->expiry);
782 if (expiry < prep->expiry)
783 prep->expiry = expiry;
David Howells33941282009-09-14 01:17:35 +0000784 token = NULL;
David Howells17926a72007-04-26 15:48:28 -0700785 ret = 0;
786
David Howells33941282009-09-14 01:17:35 +0000787error_free:
788 kfree(token);
David Howells17926a72007-04-26 15:48:28 -0700789error:
790 return ret;
791}
792
793/*
David Howells8a7a3eb2014-07-18 18:56:36 +0100794 * Free token list.
David Howells17926a72007-04-26 15:48:28 -0700795 */
David Howells8a7a3eb2014-07-18 18:56:36 +0100796static void rxrpc_free_token_list(struct rxrpc_key_token *token)
David Howells17926a72007-04-26 15:48:28 -0700797{
David Howells8a7a3eb2014-07-18 18:56:36 +0100798 struct rxrpc_key_token *next;
David Howells17926a72007-04-26 15:48:28 -0700799
David Howells8a7a3eb2014-07-18 18:56:36 +0100800 for (; token; token = next) {
801 next = token->next;
David Howells33941282009-09-14 01:17:35 +0000802 switch (token->security_index) {
803 case RXRPC_SECURITY_RXKAD:
804 kfree(token->kad);
805 break;
David Howells994551532009-09-14 01:17:46 +0000806 case RXRPC_SECURITY_RXK5:
807 if (token->k5)
808 rxrpc_rxk5_free(token->k5);
809 break;
David Howells33941282009-09-14 01:17:35 +0000810 default:
Joe Perches9b6d5392016-06-02 12:08:52 -0700811 pr_err("Unknown token type %x on rxrpc key\n",
David Howells33941282009-09-14 01:17:35 +0000812 token->security_index);
813 BUG();
814 }
815
816 kfree(token);
817 }
David Howells17926a72007-04-26 15:48:28 -0700818}
819
820/*
David Howells8a7a3eb2014-07-18 18:56:36 +0100821 * Clean up preparse data.
822 */
823static void rxrpc_free_preparse(struct key_preparsed_payload *prep)
824{
David Howells146aa8b2015-10-21 14:04:48 +0100825 rxrpc_free_token_list(prep->payload.data[0]);
David Howells8a7a3eb2014-07-18 18:56:36 +0100826}
827
828/*
829 * Preparse a server secret key.
830 *
831 * The data should be the 8-byte secret key.
832 */
833static int rxrpc_preparse_s(struct key_preparsed_payload *prep)
834{
Herbert Xu1afe5932016-01-24 21:19:01 +0800835 struct crypto_skcipher *ci;
David Howells8a7a3eb2014-07-18 18:56:36 +0100836
837 _enter("%zu", prep->datalen);
838
839 if (prep->datalen != 8)
840 return -EINVAL;
841
David Howells146aa8b2015-10-21 14:04:48 +0100842 memcpy(&prep->payload.data[2], prep->data, 8);
David Howells8a7a3eb2014-07-18 18:56:36 +0100843
Herbert Xu1afe5932016-01-24 21:19:01 +0800844 ci = crypto_alloc_skcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
David Howells8a7a3eb2014-07-18 18:56:36 +0100845 if (IS_ERR(ci)) {
846 _leave(" = %ld", PTR_ERR(ci));
847 return PTR_ERR(ci);
848 }
849
Herbert Xu1afe5932016-01-24 21:19:01 +0800850 if (crypto_skcipher_setkey(ci, prep->data, 8) < 0)
David Howells8a7a3eb2014-07-18 18:56:36 +0100851 BUG();
852
David Howells146aa8b2015-10-21 14:04:48 +0100853 prep->payload.data[0] = ci;
David Howells8a7a3eb2014-07-18 18:56:36 +0100854 _leave(" = 0");
855 return 0;
856}
857
858/*
859 * Clean up preparse data.
860 */
861static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep)
862{
David Howells146aa8b2015-10-21 14:04:48 +0100863 if (prep->payload.data[0])
Herbert Xu1afe5932016-01-24 21:19:01 +0800864 crypto_free_skcipher(prep->payload.data[0]);
David Howells8a7a3eb2014-07-18 18:56:36 +0100865}
866
867/*
868 * dispose of the data dangling from the corpse of a rxrpc key
869 */
870static void rxrpc_destroy(struct key *key)
871{
David Howells146aa8b2015-10-21 14:04:48 +0100872 rxrpc_free_token_list(key->payload.data[0]);
David Howells8a7a3eb2014-07-18 18:56:36 +0100873}
874
875/*
David Howells17926a72007-04-26 15:48:28 -0700876 * dispose of the data dangling from the corpse of a rxrpc key
877 */
878static void rxrpc_destroy_s(struct key *key)
879{
David Howells146aa8b2015-10-21 14:04:48 +0100880 if (key->payload.data[0]) {
Herbert Xu1afe5932016-01-24 21:19:01 +0800881 crypto_free_skcipher(key->payload.data[0]);
David Howells146aa8b2015-10-21 14:04:48 +0100882 key->payload.data[0] = NULL;
David Howells17926a72007-04-26 15:48:28 -0700883 }
884}
885
886/*
887 * describe the rxrpc key
888 */
889static void rxrpc_describe(const struct key *key, struct seq_file *m)
890{
891 seq_puts(m, key->description);
892}
893
894/*
895 * grab the security key for a socket
896 */
897int rxrpc_request_key(struct rxrpc_sock *rx, char __user *optval, int optlen)
898{
899 struct key *key;
900 char *description;
901
902 _enter("");
903
904 if (optlen <= 0 || optlen > PAGE_SIZE - 1)
905 return -EINVAL;
906
Al Viro16e5c1f2015-12-24 00:06:05 -0500907 description = memdup_user_nul(optval, optlen);
908 if (IS_ERR(description))
909 return PTR_ERR(description);
David Howells17926a72007-04-26 15:48:28 -0700910
911 key = request_key(&key_type_rxrpc, description, NULL);
912 if (IS_ERR(key)) {
913 kfree(description);
914 _leave(" = %ld", PTR_ERR(key));
915 return PTR_ERR(key);
916 }
917
918 rx->key = key;
919 kfree(description);
920 _leave(" = 0 [key %x]", key->serial);
921 return 0;
922}
923
924/*
925 * grab the security keyring for a server socket
926 */
927int rxrpc_server_keyring(struct rxrpc_sock *rx, char __user *optval,
928 int optlen)
929{
930 struct key *key;
931 char *description;
932
933 _enter("");
934
935 if (optlen <= 0 || optlen > PAGE_SIZE - 1)
936 return -EINVAL;
937
Al Viro16e5c1f2015-12-24 00:06:05 -0500938 description = memdup_user_nul(optval, optlen);
939 if (IS_ERR(description))
940 return PTR_ERR(description);
David Howells17926a72007-04-26 15:48:28 -0700941
942 key = request_key(&key_type_keyring, description, NULL);
943 if (IS_ERR(key)) {
944 kfree(description);
945 _leave(" = %ld", PTR_ERR(key));
946 return PTR_ERR(key);
947 }
948
949 rx->securities = key;
950 kfree(description);
951 _leave(" = 0 [key %x]", key->serial);
952 return 0;
953}
954
955/*
956 * generate a server data key
957 */
958int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
959 const void *session_key,
Baolin Wang10674a02017-08-29 10:15:40 +0100960 time64_t expiry,
David Howells17926a72007-04-26 15:48:28 -0700961 u32 kvno)
962{
David Howellsd84f4f92008-11-14 10:39:23 +1100963 const struct cred *cred = current_cred();
David Howells17926a72007-04-26 15:48:28 -0700964 struct key *key;
965 int ret;
966
967 struct {
968 u32 kver;
David Howells33941282009-09-14 01:17:35 +0000969 struct rxrpc_key_data_v1 v1;
David Howells17926a72007-04-26 15:48:28 -0700970 } data;
971
972 _enter("");
973
Eric W. Biedermanc6089732012-05-25 16:37:54 -0600974 key = key_alloc(&key_type_rxrpc, "x",
975 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 0,
David Howells5ac7eac2016-04-06 16:14:24 +0100976 KEY_ALLOC_NOT_IN_QUOTA, NULL);
David Howells17926a72007-04-26 15:48:28 -0700977 if (IS_ERR(key)) {
978 _leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
979 return -ENOMEM;
980 }
981
982 _debug("key %d", key_serial(key));
983
984 data.kver = 1;
David Howells33941282009-09-14 01:17:35 +0000985 data.v1.security_index = RXRPC_SECURITY_RXKAD;
986 data.v1.ticket_length = 0;
Baolin Wang10674a02017-08-29 10:15:40 +0100987 data.v1.expiry = rxrpc_time64_to_u32(expiry);
David Howells33941282009-09-14 01:17:35 +0000988 data.v1.kvno = 0;
David Howells17926a72007-04-26 15:48:28 -0700989
David Howells33941282009-09-14 01:17:35 +0000990 memcpy(&data.v1.session_key, session_key, sizeof(data.v1.session_key));
David Howells17926a72007-04-26 15:48:28 -0700991
992 ret = key_instantiate_and_link(key, &data, sizeof(data), NULL, NULL);
993 if (ret < 0)
994 goto error;
995
David Howells19ffa012016-04-04 14:00:36 +0100996 conn->params.key = key;
David Howells17926a72007-04-26 15:48:28 -0700997 _leave(" = 0 [%d]", key_serial(key));
998 return 0;
999
1000error:
1001 key_revoke(key);
1002 key_put(key);
1003 _leave(" = -ENOMEM [ins %d]", ret);
1004 return -ENOMEM;
1005}
David Howells17926a72007-04-26 15:48:28 -07001006EXPORT_SYMBOL(rxrpc_get_server_data_key);
David Howells76181c12007-10-16 23:29:46 -07001007
1008/**
1009 * rxrpc_get_null_key - Generate a null RxRPC key
1010 * @keyname: The name to give the key.
1011 *
1012 * Generate a null RxRPC key that can be used to indicate anonymous security is
1013 * required for a particular domain.
1014 */
1015struct key *rxrpc_get_null_key(const char *keyname)
1016{
David Howellsd84f4f92008-11-14 10:39:23 +11001017 const struct cred *cred = current_cred();
David Howells76181c12007-10-16 23:29:46 -07001018 struct key *key;
1019 int ret;
1020
Eric W. Biedermanc6089732012-05-25 16:37:54 -06001021 key = key_alloc(&key_type_rxrpc, keyname,
1022 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
David Howells5ac7eac2016-04-06 16:14:24 +01001023 KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA, NULL);
David Howells76181c12007-10-16 23:29:46 -07001024 if (IS_ERR(key))
1025 return key;
1026
1027 ret = key_instantiate_and_link(key, NULL, 0, NULL, NULL);
1028 if (ret < 0) {
1029 key_revoke(key);
1030 key_put(key);
1031 return ERR_PTR(ret);
1032 }
1033
1034 return key;
1035}
1036EXPORT_SYMBOL(rxrpc_get_null_key);
David Howellsed6dd182009-09-14 01:17:40 +00001037
1038/*
1039 * read the contents of an rxrpc key
1040 * - this returns the result in XDR form
1041 */
1042static long rxrpc_read(const struct key *key,
1043 char __user *buffer, size_t buflen)
1044{
David Howells994551532009-09-14 01:17:46 +00001045 const struct rxrpc_key_token *token;
1046 const struct krb5_principal *princ;
1047 size_t size;
1048 __be32 __user *xdr, *oldxdr;
1049 u32 cnlen, toksize, ntoks, tok, zero;
1050 u16 toksizes[AFSTOKEN_MAX];
1051 int loop;
David Howellsed6dd182009-09-14 01:17:40 +00001052
1053 _enter("");
1054
1055 /* we don't know what form we should return non-AFS keys in */
1056 if (memcmp(key->description, "afs@", 4) != 0)
1057 return -EOPNOTSUPP;
1058 cnlen = strlen(key->description + 4);
1059
David Howells994551532009-09-14 01:17:46 +00001060#define RND(X) (((X) + 3) & ~3)
1061
David Howellsed6dd182009-09-14 01:17:40 +00001062 /* AFS keys we return in XDR form, so we need to work out the size of
1063 * the XDR */
1064 size = 2 * 4; /* flags, cellname len */
David Howells994551532009-09-14 01:17:46 +00001065 size += RND(cnlen); /* cellname */
David Howellsed6dd182009-09-14 01:17:40 +00001066 size += 1 * 4; /* token count */
1067
1068 ntoks = 0;
David Howells146aa8b2015-10-21 14:04:48 +01001069 for (token = key->payload.data[0]; token; token = token->next) {
David Howells994551532009-09-14 01:17:46 +00001070 toksize = 4; /* sec index */
1071
David Howellsed6dd182009-09-14 01:17:40 +00001072 switch (token->security_index) {
1073 case RXRPC_SECURITY_RXKAD:
Marc Dionne774521f2017-02-24 12:33:09 +00001074 toksize += 9 * 4; /* viceid, kvno, key*2 + len, begin,
David Howells994551532009-09-14 01:17:46 +00001075 * end, primary, tktlen */
1076 toksize += RND(token->kad->ticket_len);
David Howellsed6dd182009-09-14 01:17:40 +00001077 break;
1078
David Howells994551532009-09-14 01:17:46 +00001079 case RXRPC_SECURITY_RXK5:
1080 princ = &token->k5->client;
1081 toksize += 4 + princ->n_name_parts * 4;
1082 for (loop = 0; loop < princ->n_name_parts; loop++)
1083 toksize += RND(strlen(princ->name_parts[loop]));
1084 toksize += 4 + RND(strlen(princ->realm));
1085
1086 princ = &token->k5->server;
1087 toksize += 4 + princ->n_name_parts * 4;
1088 for (loop = 0; loop < princ->n_name_parts; loop++)
1089 toksize += RND(strlen(princ->name_parts[loop]));
1090 toksize += 4 + RND(strlen(princ->realm));
1091
1092 toksize += 8 + RND(token->k5->session.data_len);
1093
1094 toksize += 4 * 8 + 2 * 4;
1095
1096 toksize += 4 + token->k5->n_addresses * 8;
1097 for (loop = 0; loop < token->k5->n_addresses; loop++)
1098 toksize += RND(token->k5->addresses[loop].data_len);
1099
1100 toksize += 4 + RND(token->k5->ticket_len);
1101 toksize += 4 + RND(token->k5->ticket2_len);
1102
1103 toksize += 4 + token->k5->n_authdata * 8;
1104 for (loop = 0; loop < token->k5->n_authdata; loop++)
1105 toksize += RND(token->k5->authdata[loop].data_len);
David Howellsed6dd182009-09-14 01:17:40 +00001106 break;
David Howells994551532009-09-14 01:17:46 +00001107
1108 default: /* we have a ticket we can't encode */
1109 BUG();
1110 continue;
David Howellsed6dd182009-09-14 01:17:40 +00001111 }
David Howells994551532009-09-14 01:17:46 +00001112
1113 _debug("token[%u]: toksize=%u", ntoks, toksize);
1114 ASSERTCMP(toksize, <=, AFSTOKEN_LENGTH_MAX);
1115
1116 toksizes[ntoks++] = toksize;
1117 size += toksize + 4; /* each token has a length word */
David Howellsed6dd182009-09-14 01:17:40 +00001118 }
1119
David Howells994551532009-09-14 01:17:46 +00001120#undef RND
1121
David Howellsed6dd182009-09-14 01:17:40 +00001122 if (!buffer || buflen < size)
1123 return size;
1124
1125 xdr = (__be32 __user *) buffer;
1126 zero = 0;
1127#define ENCODE(x) \
1128 do { \
1129 __be32 y = htonl(x); \
1130 if (put_user(y, xdr++) < 0) \
1131 goto fault; \
1132 } while(0)
David Howells994551532009-09-14 01:17:46 +00001133#define ENCODE_DATA(l, s) \
1134 do { \
1135 u32 _l = (l); \
1136 ENCODE(l); \
1137 if (copy_to_user(xdr, (s), _l) != 0) \
1138 goto fault; \
1139 if (_l & 3 && \
David Howellsed3bfdf2014-09-09 15:19:44 +01001140 copy_to_user((u8 __user *)xdr + _l, &zero, 4 - (_l & 3)) != 0) \
David Howells994551532009-09-14 01:17:46 +00001141 goto fault; \
1142 xdr += (_l + 3) >> 2; \
1143 } while(0)
1144#define ENCODE64(x) \
1145 do { \
1146 __be64 y = cpu_to_be64(x); \
1147 if (copy_to_user(xdr, &y, 8) != 0) \
1148 goto fault; \
1149 xdr += 8 >> 2; \
1150 } while(0)
1151#define ENCODE_STR(s) \
1152 do { \
1153 const char *_s = (s); \
1154 ENCODE_DATA(strlen(_s), _s); \
1155 } while(0)
David Howellsed6dd182009-09-14 01:17:40 +00001156
David Howells994551532009-09-14 01:17:46 +00001157 ENCODE(0); /* flags */
1158 ENCODE_DATA(cnlen, key->description + 4); /* cellname */
1159 ENCODE(ntoks);
David Howellsed6dd182009-09-14 01:17:40 +00001160
David Howells994551532009-09-14 01:17:46 +00001161 tok = 0;
David Howells146aa8b2015-10-21 14:04:48 +01001162 for (token = key->payload.data[0]; token; token = token->next) {
David Howells994551532009-09-14 01:17:46 +00001163 toksize = toksizes[tok++];
1164 ENCODE(toksize);
1165 oldxdr = xdr;
1166 ENCODE(token->security_index);
David Howellsed6dd182009-09-14 01:17:40 +00001167
1168 switch (token->security_index) {
1169 case RXRPC_SECURITY_RXKAD:
David Howellsed6dd182009-09-14 01:17:40 +00001170 ENCODE(token->kad->vice_id);
1171 ENCODE(token->kad->kvno);
David Howells994551532009-09-14 01:17:46 +00001172 ENCODE_DATA(8, token->kad->session_key);
David Howellsed6dd182009-09-14 01:17:40 +00001173 ENCODE(token->kad->start);
1174 ENCODE(token->kad->expiry);
1175 ENCODE(token->kad->primary_flag);
David Howells994551532009-09-14 01:17:46 +00001176 ENCODE_DATA(token->kad->ticket_len, token->kad->ticket);
1177 break;
1178
1179 case RXRPC_SECURITY_RXK5:
1180 princ = &token->k5->client;
1181 ENCODE(princ->n_name_parts);
1182 for (loop = 0; loop < princ->n_name_parts; loop++)
1183 ENCODE_STR(princ->name_parts[loop]);
1184 ENCODE_STR(princ->realm);
1185
1186 princ = &token->k5->server;
1187 ENCODE(princ->n_name_parts);
1188 for (loop = 0; loop < princ->n_name_parts; loop++)
1189 ENCODE_STR(princ->name_parts[loop]);
1190 ENCODE_STR(princ->realm);
1191
1192 ENCODE(token->k5->session.tag);
1193 ENCODE_DATA(token->k5->session.data_len,
1194 token->k5->session.data);
1195
1196 ENCODE64(token->k5->authtime);
1197 ENCODE64(token->k5->starttime);
1198 ENCODE64(token->k5->endtime);
1199 ENCODE64(token->k5->renew_till);
1200 ENCODE(token->k5->is_skey);
1201 ENCODE(token->k5->flags);
1202
1203 ENCODE(token->k5->n_addresses);
1204 for (loop = 0; loop < token->k5->n_addresses; loop++) {
1205 ENCODE(token->k5->addresses[loop].tag);
1206 ENCODE_DATA(token->k5->addresses[loop].data_len,
1207 token->k5->addresses[loop].data);
1208 }
1209
1210 ENCODE_DATA(token->k5->ticket_len, token->k5->ticket);
1211 ENCODE_DATA(token->k5->ticket2_len, token->k5->ticket2);
1212
1213 ENCODE(token->k5->n_authdata);
1214 for (loop = 0; loop < token->k5->n_authdata; loop++) {
1215 ENCODE(token->k5->authdata[loop].tag);
1216 ENCODE_DATA(token->k5->authdata[loop].data_len,
1217 token->k5->authdata[loop].data);
1218 }
David Howellsed6dd182009-09-14 01:17:40 +00001219 break;
1220
1221 default:
David Howells994551532009-09-14 01:17:46 +00001222 BUG();
David Howellsed6dd182009-09-14 01:17:40 +00001223 break;
1224 }
David Howells994551532009-09-14 01:17:46 +00001225
1226 ASSERTCMP((unsigned long)xdr - (unsigned long)oldxdr, ==,
1227 toksize);
David Howellsed6dd182009-09-14 01:17:40 +00001228 }
1229
David Howells994551532009-09-14 01:17:46 +00001230#undef ENCODE_STR
1231#undef ENCODE_DATA
1232#undef ENCODE64
David Howellsed6dd182009-09-14 01:17:40 +00001233#undef ENCODE
1234
David Howells994551532009-09-14 01:17:46 +00001235 ASSERTCMP(tok, ==, ntoks);
David Howellsed6dd182009-09-14 01:17:40 +00001236 ASSERTCMP((char __user *) xdr - buffer, ==, size);
1237 _leave(" = %zu", size);
1238 return size;
1239
1240fault:
1241 _leave(" = -EFAULT");
1242 return -EFAULT;
1243}