1 // SPDX-License-Identifier: BSD-3-Clause
2 /* rfc3961 Kerberos 5 simplified crypto profile.
3 *
4 * Parts borrowed from net/sunrpc/auth_gss/.
5 */
6 /*
7 * COPYRIGHT (c) 2008
8 * The Regents of the University of Michigan
9 * ALL RIGHTS RESERVED
10 *
11 * Permission is granted to use, copy, create derivative works
12 * and redistribute this software and such derivative works
13 * for any purpose, so long as the name of The University of
14 * Michigan is not used in any advertising or publicity
15 * pertaining to the use of distribution of this software
16 * without specific, written prior authorization. If the
17 * above copyright notice or any other identification of the
18 * University of Michigan is included in any copy of any
19 * portion of this software, then the disclaimer below must
20 * also be included.
21 *
22 * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
23 * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
24 * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
25 * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
26 * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
28 * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
29 * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
30 * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
31 * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
32 * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGES.
34 */
35
36 /*
37 * Copyright (C) 1998 by the FundsXpress, INC.
38 *
39 * All rights reserved.
40 *
41 * Export of this software from the United States of America may require
42 * a specific license from the United States Government. It is the
43 * responsibility of any person or organization contemplating export to
44 * obtain such a license before exporting.
45 *
46 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
47 * distribute this software and its documentation for any purpose and
48 * without fee is hereby granted, provided that the above copyright
49 * notice appear in all copies and that both that copyright notice and
50 * this permission notice appear in supporting documentation, and that
51 * the name of FundsXpress. not be used in advertising or publicity pertaining
52 * to distribution of the software without specific, written prior
53 * permission. FundsXpress makes no representations about the suitability of
54 * this software for any purpose. It is provided "as is" without express
55 * or implied warranty.
56 *
57 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
58 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
59 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
60 */
61
62 /*
63 * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
64 * Written by David Howells (dhowells@redhat.com)
65 */
66
67 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
68
69 #include <linux/random.h>
70 #include <linux/scatterlist.h>
71 #include <linux/skbuff.h>
72 #include <linux/slab.h>
73 #include <linux/lcm.h>
74 #include <linux/rtnetlink.h>
75 #include <crypto/authenc.h>
76 #include <crypto/skcipher.h>
77 #include <crypto/hash.h>
78 #include "internal.h"
79
80 /* Maximum blocksize for the supported crypto algorithms */
81 #define KRB5_MAX_BLOCKSIZE (16)
82
crypto_shash_update_sg(struct shash_desc * desc,struct scatterlist * sg,size_t offset,size_t len)83 int crypto_shash_update_sg(struct shash_desc *desc, struct scatterlist *sg,
84 size_t offset, size_t len)
85 {
86 struct sg_mapping_iter miter;
87 size_t i, n;
88 int ret = 0;
89
90 sg_miter_start(&miter, sg, sg_nents(sg),
91 SG_MITER_FROM_SG | SG_MITER_LOCAL);
92 for (i = 0; i < len; i += n) {
93 sg_miter_next(&miter);
94 n = min(miter.length, len - i);
95 ret = crypto_shash_update(desc, miter.addr, n);
96 if (ret < 0)
97 break;
98 }
99 sg_miter_stop(&miter);
100 return ret;
101 }
102
rfc3961_do_encrypt(struct crypto_sync_skcipher * tfm,void * iv,const struct krb5_buffer * in,struct krb5_buffer * out)103 static int rfc3961_do_encrypt(struct crypto_sync_skcipher *tfm, void *iv,
104 const struct krb5_buffer *in, struct krb5_buffer *out)
105 {
106 struct scatterlist sg[1];
107 u8 local_iv[KRB5_MAX_BLOCKSIZE] __aligned(KRB5_MAX_BLOCKSIZE) = {0};
108 SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
109 int ret;
110
111 if (WARN_ON(in->len != out->len))
112 return -EINVAL;
113 if (out->len % crypto_sync_skcipher_blocksize(tfm) != 0)
114 return -EINVAL;
115
116 if (crypto_sync_skcipher_ivsize(tfm) > KRB5_MAX_BLOCKSIZE)
117 return -EINVAL;
118
119 if (iv)
120 memcpy(local_iv, iv, crypto_sync_skcipher_ivsize(tfm));
121
122 memcpy(out->data, in->data, out->len);
123 sg_init_one(sg, out->data, out->len);
124
125 skcipher_request_set_sync_tfm(req, tfm);
126 skcipher_request_set_callback(req, 0, NULL, NULL);
127 skcipher_request_set_crypt(req, sg, sg, out->len, local_iv);
128
129 ret = crypto_skcipher_encrypt(req);
130 skcipher_request_zero(req);
131 return ret;
132 }
133
134 /*
135 * Calculate an unkeyed basic hash.
136 */
rfc3961_calc_H(const struct krb5_enctype * krb5,const struct krb5_buffer * data,struct krb5_buffer * digest,gfp_t gfp)137 static int rfc3961_calc_H(const struct krb5_enctype *krb5,
138 const struct krb5_buffer *data,
139 struct krb5_buffer *digest,
140 gfp_t gfp)
141 {
142 struct crypto_shash *tfm;
143 struct shash_desc *desc;
144 size_t desc_size;
145 int ret = -ENOMEM;
146
147 tfm = crypto_alloc_shash(krb5->hash_name, 0, 0);
148 if (IS_ERR(tfm))
149 return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
150
151 desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
152
153 desc = kzalloc(desc_size, gfp);
154 if (!desc)
155 goto error_tfm;
156
157 digest->len = crypto_shash_digestsize(tfm);
158 digest->data = kzalloc(digest->len, gfp);
159 if (!digest->data)
160 goto error_desc;
161
162 desc->tfm = tfm;
163 ret = crypto_shash_init(desc);
164 if (ret < 0)
165 goto error_digest;
166
167 ret = crypto_shash_finup(desc, data->data, data->len, digest->data);
168 if (ret < 0)
169 goto error_digest;
170
171 goto error_desc;
172
173 error_digest:
174 kfree_sensitive(digest->data);
175 error_desc:
176 kfree_sensitive(desc);
177 error_tfm:
178 crypto_free_shash(tfm);
179 return ret;
180 }
181
182 /*
183 * This is the n-fold function as described in rfc3961, sec 5.1
184 * Taken from MIT Kerberos and modified.
185 */
rfc3961_nfold(const struct krb5_buffer * source,struct krb5_buffer * result)186 static void rfc3961_nfold(const struct krb5_buffer *source, struct krb5_buffer *result)
187 {
188 const u8 *in = source->data;
189 u8 *out = result->data;
190 unsigned long ulcm;
191 unsigned int inbits, outbits;
192 int byte, i, msbit;
193
194 /* the code below is more readable if I make these bytes instead of bits */
195 inbits = source->len;
196 outbits = result->len;
197
198 /* first compute lcm(n,k) */
199 ulcm = lcm(inbits, outbits);
200
201 /* now do the real work */
202 memset(out, 0, outbits);
203 byte = 0;
204
205 /* this will end up cycling through k lcm(k,n)/k times, which
206 * is correct.
207 */
208 for (i = ulcm-1; i >= 0; i--) {
209 /* compute the msbit in k which gets added into this byte */
210 msbit = (
211 /* first, start with the msbit in the first,
212 * unrotated byte
213 */
214 ((inbits << 3) - 1) +
215 /* then, for each byte, shift to the right
216 * for each repetition
217 */
218 (((inbits << 3) + 13) * (i/inbits)) +
219 /* last, pick out the correct byte within
220 * that shifted repetition
221 */
222 ((inbits - (i % inbits)) << 3)
223 ) % (inbits << 3);
224
225 /* pull out the byte value itself */
226 byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8) |
227 (in[((inbits) - (msbit >> 3)) % inbits]))
228 >> ((msbit & 7) + 1)) & 0xff;
229
230 /* do the addition */
231 byte += out[i % outbits];
232 out[i % outbits] = byte & 0xff;
233
234 /* keep around the carry bit, if any */
235 byte >>= 8;
236 }
237
238 /* if there's a carry bit left over, add it back in */
239 if (byte) {
240 for (i = outbits - 1; i >= 0; i--) {
241 /* do the addition */
242 byte += out[i];
243 out[i] = byte & 0xff;
244
245 /* keep around the carry bit, if any */
246 byte >>= 8;
247 }
248 }
249 }
250
251 /*
252 * Calculate a derived key, DK(Base Key, Well-Known Constant)
253 *
254 * DK(Key, Constant) = random-to-key(DR(Key, Constant))
255 * DR(Key, Constant) = k-truncate(E(Key, Constant, initial-cipher-state))
256 * K1 = E(Key, n-fold(Constant), initial-cipher-state)
257 * K2 = E(Key, K1, initial-cipher-state)
258 * K3 = E(Key, K2, initial-cipher-state)
259 * K4 = ...
260 * DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)
261 * [rfc3961 sec 5.1]
262 */
rfc3961_calc_DK(const struct krb5_enctype * krb5,const struct krb5_buffer * inkey,const struct krb5_buffer * in_constant,struct krb5_buffer * result,gfp_t gfp)263 static int rfc3961_calc_DK(const struct krb5_enctype *krb5,
264 const struct krb5_buffer *inkey,
265 const struct krb5_buffer *in_constant,
266 struct krb5_buffer *result,
267 gfp_t gfp)
268 {
269 unsigned int blocksize, keybytes, keylength, n;
270 struct krb5_buffer inblock, outblock, rawkey;
271 struct crypto_sync_skcipher *cipher;
272 int ret = -EINVAL;
273
274 blocksize = krb5->block_len;
275 keybytes = krb5->key_bytes;
276 keylength = krb5->key_len;
277
278 if (inkey->len != keylength || result->len != keylength)
279 return -EINVAL;
280 if (!krb5->random_to_key && result->len != keybytes)
281 return -EINVAL;
282
283 cipher = crypto_alloc_sync_skcipher(krb5->derivation_enc, 0, 0);
284 if (IS_ERR(cipher)) {
285 ret = (PTR_ERR(cipher) == -ENOENT) ? -ENOPKG : PTR_ERR(cipher);
286 goto err_return;
287 }
288 ret = crypto_sync_skcipher_setkey(cipher, inkey->data, inkey->len);
289 if (ret < 0)
290 goto err_free_cipher;
291
292 ret = -ENOMEM;
293 inblock.data = kzalloc(blocksize * 2 + keybytes, gfp);
294 if (!inblock.data)
295 goto err_free_cipher;
296
297 inblock.len = blocksize;
298 outblock.data = inblock.data + blocksize;
299 outblock.len = blocksize;
300 rawkey.data = outblock.data + blocksize;
301 rawkey.len = keybytes;
302
303 /* initialize the input block */
304
305 if (in_constant->len == inblock.len)
306 memcpy(inblock.data, in_constant->data, inblock.len);
307 else
308 rfc3961_nfold(in_constant, &inblock);
309
310 /* loop encrypting the blocks until enough key bytes are generated */
311 n = 0;
312 while (n < rawkey.len) {
313 rfc3961_do_encrypt(cipher, NULL, &inblock, &outblock);
314
315 if (keybytes - n <= outblock.len) {
316 memcpy(rawkey.data + n, outblock.data, keybytes - n);
317 break;
318 }
319
320 memcpy(rawkey.data + n, outblock.data, outblock.len);
321 memcpy(inblock.data, outblock.data, outblock.len);
322 n += outblock.len;
323 }
324
325 /* postprocess the key */
326 if (!krb5->random_to_key) {
327 /* Identity random-to-key function. */
328 memcpy(result->data, rawkey.data, rawkey.len);
329 ret = 0;
330 } else {
331 ret = krb5->random_to_key(krb5, &rawkey, result);
332 }
333
334 kfree_sensitive(inblock.data);
335 err_free_cipher:
336 crypto_free_sync_skcipher(cipher);
337 err_return:
338 return ret;
339 }
340
341 /*
342 * Calculate single encryption, E()
343 *
344 * E(Key, octets)
345 */
rfc3961_calc_E(const struct krb5_enctype * krb5,const struct krb5_buffer * key,const struct krb5_buffer * in_data,struct krb5_buffer * result,gfp_t gfp)346 static int rfc3961_calc_E(const struct krb5_enctype *krb5,
347 const struct krb5_buffer *key,
348 const struct krb5_buffer *in_data,
349 struct krb5_buffer *result,
350 gfp_t gfp)
351 {
352 struct crypto_sync_skcipher *cipher;
353 int ret;
354
355 cipher = crypto_alloc_sync_skcipher(krb5->derivation_enc, 0, 0);
356 if (IS_ERR(cipher)) {
357 ret = (PTR_ERR(cipher) == -ENOENT) ? -ENOPKG : PTR_ERR(cipher);
358 goto err;
359 }
360
361 ret = crypto_sync_skcipher_setkey(cipher, key->data, key->len);
362 if (ret < 0)
363 goto err_free;
364
365 ret = rfc3961_do_encrypt(cipher, NULL, in_data, result);
366
367 err_free:
368 crypto_free_sync_skcipher(cipher);
369 err:
370 return ret;
371 }
372
373 /*
374 * Calculate the pseudo-random function, PRF().
375 *
376 * tmp1 = H(octet-string)
377 * tmp2 = truncate tmp1 to multiple of m
378 * PRF = E(DK(protocol-key, prfconstant), tmp2, initial-cipher-state)
379 *
380 * The "prfconstant" used in the PRF operation is the three-octet string
381 * "prf".
382 * [rfc3961 sec 5.3]
383 */
rfc3961_calc_PRF(const struct krb5_enctype * krb5,const struct krb5_buffer * protocol_key,const struct krb5_buffer * octet_string,struct krb5_buffer * result,gfp_t gfp)384 static int rfc3961_calc_PRF(const struct krb5_enctype *krb5,
385 const struct krb5_buffer *protocol_key,
386 const struct krb5_buffer *octet_string,
387 struct krb5_buffer *result,
388 gfp_t gfp)
389 {
390 static const struct krb5_buffer prfconstant = { 3, "prf" };
391 struct krb5_buffer derived_key;
392 struct krb5_buffer tmp1, tmp2;
393 unsigned int m = krb5->block_len;
394 void *buffer;
395 int ret;
396
397 if (result->len != krb5->prf_len)
398 return -EINVAL;
399
400 tmp1.len = krb5->hash_len;
401 derived_key.len = krb5->key_bytes;
402 buffer = kzalloc(round16(tmp1.len) + round16(derived_key.len), gfp);
403 if (!buffer)
404 return -ENOMEM;
405
406 tmp1.data = buffer;
407 derived_key.data = buffer + round16(tmp1.len);
408
409 ret = rfc3961_calc_H(krb5, octet_string, &tmp1, gfp);
410 if (ret < 0)
411 goto err;
412
413 tmp2.len = tmp1.len & ~(m - 1);
414 tmp2.data = tmp1.data;
415
416 ret = rfc3961_calc_DK(krb5, protocol_key, &prfconstant, &derived_key, gfp);
417 if (ret < 0)
418 goto err;
419
420 ret = rfc3961_calc_E(krb5, &derived_key, &tmp2, result, gfp);
421
422 err:
423 kfree_sensitive(buffer);
424 return ret;
425 }
426
427 /*
428 * Derive the Ke and Ki keys and package them into a key parameter that can be
429 * given to the setkey of a authenc AEAD crypto object.
430 */
authenc_derive_encrypt_keys(const struct krb5_enctype * krb5,const struct krb5_buffer * TK,unsigned int usage,struct krb5_buffer * setkey,gfp_t gfp)431 int authenc_derive_encrypt_keys(const struct krb5_enctype *krb5,
432 const struct krb5_buffer *TK,
433 unsigned int usage,
434 struct krb5_buffer *setkey,
435 gfp_t gfp)
436 {
437 struct crypto_authenc_key_param *param;
438 struct krb5_buffer Ke, Ki;
439 struct rtattr *rta;
440 int ret;
441
442 Ke.len = krb5->Ke_len;
443 Ki.len = krb5->Ki_len;
444 setkey->len = RTA_LENGTH(sizeof(*param)) + Ke.len + Ki.len;
445 setkey->data = kzalloc(setkey->len, GFP_KERNEL);
446 if (!setkey->data)
447 return -ENOMEM;
448
449 rta = setkey->data;
450 rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
451 rta->rta_len = RTA_LENGTH(sizeof(*param));
452 param = RTA_DATA(rta);
453 param->enckeylen = htonl(Ke.len);
454
455 Ki.data = (void *)(param + 1);
456 Ke.data = Ki.data + Ki.len;
457
458 ret = krb5_derive_Ke(krb5, TK, usage, &Ke, gfp);
459 if (ret < 0) {
460 pr_err("get_Ke failed %d\n", ret);
461 return ret;
462 }
463 ret = krb5_derive_Ki(krb5, TK, usage, &Ki, gfp);
464 if (ret < 0)
465 pr_err("get_Ki failed %d\n", ret);
466 return ret;
467 }
468
469 /*
470 * Package predefined Ke and Ki keys and into a key parameter that can be given
471 * to the setkey of an authenc AEAD crypto object.
472 */
authenc_load_encrypt_keys(const struct krb5_enctype * krb5,const struct krb5_buffer * Ke,const struct krb5_buffer * Ki,struct krb5_buffer * setkey,gfp_t gfp)473 int authenc_load_encrypt_keys(const struct krb5_enctype *krb5,
474 const struct krb5_buffer *Ke,
475 const struct krb5_buffer *Ki,
476 struct krb5_buffer *setkey,
477 gfp_t gfp)
478 {
479 struct crypto_authenc_key_param *param;
480 struct rtattr *rta;
481
482 setkey->len = RTA_LENGTH(sizeof(*param)) + Ke->len + Ki->len;
483 setkey->data = kzalloc(setkey->len, GFP_KERNEL);
484 if (!setkey->data)
485 return -ENOMEM;
486
487 rta = setkey->data;
488 rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
489 rta->rta_len = RTA_LENGTH(sizeof(*param));
490 param = RTA_DATA(rta);
491 param->enckeylen = htonl(Ke->len);
492 memcpy((void *)(param + 1), Ki->data, Ki->len);
493 memcpy((void *)(param + 1) + Ki->len, Ke->data, Ke->len);
494 return 0;
495 }
496
497 /*
498 * Derive the Kc key for checksum-only mode and package it into a key parameter
499 * that can be given to the setkey of a hash crypto object.
500 */
rfc3961_derive_checksum_key(const struct krb5_enctype * krb5,const struct krb5_buffer * TK,unsigned int usage,struct krb5_buffer * setkey,gfp_t gfp)501 int rfc3961_derive_checksum_key(const struct krb5_enctype *krb5,
502 const struct krb5_buffer *TK,
503 unsigned int usage,
504 struct krb5_buffer *setkey,
505 gfp_t gfp)
506 {
507 int ret;
508
509 setkey->len = krb5->Kc_len;
510 setkey->data = kzalloc(setkey->len, GFP_KERNEL);
511 if (!setkey->data)
512 return -ENOMEM;
513
514 ret = krb5_derive_Kc(krb5, TK, usage, setkey, gfp);
515 if (ret < 0)
516 pr_err("get_Kc failed %d\n", ret);
517 return ret;
518 }
519
520 /*
521 * Package a predefined Kc key for checksum-only mode into a key parameter that
522 * can be given to the setkey of a hash crypto object.
523 */
rfc3961_load_checksum_key(const struct krb5_enctype * krb5,const struct krb5_buffer * Kc,struct krb5_buffer * setkey,gfp_t gfp)524 int rfc3961_load_checksum_key(const struct krb5_enctype *krb5,
525 const struct krb5_buffer *Kc,
526 struct krb5_buffer *setkey,
527 gfp_t gfp)
528 {
529 setkey->len = krb5->Kc_len;
530 setkey->data = kmemdup(Kc->data, Kc->len, GFP_KERNEL);
531 if (!setkey->data)
532 return -ENOMEM;
533 return 0;
534 }
535
536 /*
537 * Apply encryption and checksumming functions to part of a scatterlist.
538 */
krb5_aead_encrypt(const struct krb5_enctype * krb5,struct crypto_aead * aead,struct scatterlist * sg,unsigned int nr_sg,size_t sg_len,size_t data_offset,size_t data_len,bool preconfounded)539 ssize_t krb5_aead_encrypt(const struct krb5_enctype *krb5,
540 struct crypto_aead *aead,
541 struct scatterlist *sg, unsigned int nr_sg, size_t sg_len,
542 size_t data_offset, size_t data_len,
543 bool preconfounded)
544 {
545 struct aead_request *req;
546 ssize_t ret, done;
547 size_t bsize, base_len, secure_offset, secure_len, pad_len, cksum_offset;
548 void *buffer;
549 u8 *iv;
550
551 if (WARN_ON(data_offset != krb5->conf_len))
552 return -EINVAL; /* Data is in wrong place */
553
554 secure_offset = 0;
555 base_len = krb5->conf_len + data_len;
556 pad_len = 0;
557 secure_len = base_len + pad_len;
558 cksum_offset = secure_len;
559 if (WARN_ON(cksum_offset + krb5->cksum_len > sg_len))
560 return -EFAULT;
561
562 bsize = krb5_aead_size(aead) +
563 krb5_aead_ivsize(aead);
564 buffer = kzalloc(bsize, GFP_NOFS);
565 if (!buffer)
566 return -ENOMEM;
567
568 /* Insert the confounder into the buffer */
569 ret = -EFAULT;
570 if (!preconfounded) {
571 get_random_bytes(buffer, krb5->conf_len);
572 done = sg_pcopy_from_buffer(sg, nr_sg, buffer, krb5->conf_len,
573 secure_offset);
574 if (done != krb5->conf_len)
575 goto error;
576 }
577
578 /* We may need to pad out to the crypto blocksize. */
579 if (pad_len) {
580 done = sg_zero_buffer(sg, nr_sg, pad_len, data_offset + data_len);
581 if (done != pad_len)
582 goto error;
583 }
584
585 /* Hash and encrypt the message. */
586 req = buffer;
587 iv = buffer + krb5_aead_size(aead);
588
589 aead_request_set_tfm(req, aead);
590 aead_request_set_callback(req, 0, NULL, NULL);
591 aead_request_set_crypt(req, sg, sg, secure_len, iv);
592 ret = crypto_aead_encrypt(req);
593 if (ret < 0)
594 goto error;
595
596 ret = secure_len + krb5->cksum_len;
597
598 error:
599 kfree_sensitive(buffer);
600 return ret;
601 }
602
603 /*
604 * Apply decryption and checksumming functions to a message. The offset and
605 * length are updated to reflect the actual content of the encrypted region.
606 */
krb5_aead_decrypt(const struct krb5_enctype * krb5,struct crypto_aead * aead,struct scatterlist * sg,unsigned int nr_sg,size_t * _offset,size_t * _len)607 int krb5_aead_decrypt(const struct krb5_enctype *krb5,
608 struct crypto_aead *aead,
609 struct scatterlist *sg, unsigned int nr_sg,
610 size_t *_offset, size_t *_len)
611 {
612 struct aead_request *req;
613 size_t bsize;
614 void *buffer;
615 int ret;
616 u8 *iv;
617
618 if (WARN_ON(*_offset != 0))
619 return -EINVAL; /* Can't set offset on aead */
620
621 if (*_len < krb5->conf_len + krb5->cksum_len)
622 return -EPROTO;
623
624 bsize = krb5_aead_size(aead) +
625 krb5_aead_ivsize(aead);
626 buffer = kzalloc(bsize, GFP_NOFS);
627 if (!buffer)
628 return -ENOMEM;
629
630 /* Decrypt the message and verify its checksum. */
631 req = buffer;
632 iv = buffer + krb5_aead_size(aead);
633
634 aead_request_set_tfm(req, aead);
635 aead_request_set_callback(req, 0, NULL, NULL);
636 aead_request_set_crypt(req, sg, sg, *_len, iv);
637 ret = crypto_aead_decrypt(req);
638 if (ret < 0)
639 goto error;
640
641 /* Adjust the boundaries of the data. */
642 *_offset += krb5->conf_len;
643 *_len -= krb5->conf_len + krb5->cksum_len;
644 ret = 0;
645
646 error:
647 kfree_sensitive(buffer);
648 return ret;
649 }
650
651 /*
652 * Generate a checksum over some metadata and part of an skbuff and insert the
653 * MIC into the skbuff immediately prior to the data.
654 */
rfc3961_get_mic(const struct krb5_enctype * krb5,struct crypto_shash * shash,const struct krb5_buffer * metadata,struct scatterlist * sg,unsigned int nr_sg,size_t sg_len,size_t data_offset,size_t data_len)655 ssize_t rfc3961_get_mic(const struct krb5_enctype *krb5,
656 struct crypto_shash *shash,
657 const struct krb5_buffer *metadata,
658 struct scatterlist *sg, unsigned int nr_sg, size_t sg_len,
659 size_t data_offset, size_t data_len)
660 {
661 struct shash_desc *desc;
662 ssize_t ret, done;
663 size_t bsize;
664 void *buffer, *digest;
665
666 if (WARN_ON(data_offset != krb5->cksum_len))
667 return -EMSGSIZE;
668
669 bsize = krb5_shash_size(shash) +
670 krb5_digest_size(shash);
671 buffer = kzalloc(bsize, GFP_NOFS);
672 if (!buffer)
673 return -ENOMEM;
674
675 /* Calculate the MIC with key Kc and store it into the skb */
676 desc = buffer;
677 desc->tfm = shash;
678 ret = crypto_shash_init(desc);
679 if (ret < 0)
680 goto error;
681
682 if (metadata) {
683 ret = crypto_shash_update(desc, metadata->data, metadata->len);
684 if (ret < 0)
685 goto error;
686 }
687
688 ret = crypto_shash_update_sg(desc, sg, data_offset, data_len);
689 if (ret < 0)
690 goto error;
691
692 digest = buffer + krb5_shash_size(shash);
693 ret = crypto_shash_final(desc, digest);
694 if (ret < 0)
695 goto error;
696
697 ret = -EFAULT;
698 done = sg_pcopy_from_buffer(sg, nr_sg, digest, krb5->cksum_len,
699 data_offset - krb5->cksum_len);
700 if (done != krb5->cksum_len)
701 goto error;
702
703 ret = krb5->cksum_len + data_len;
704
705 error:
706 kfree_sensitive(buffer);
707 return ret;
708 }
709
710 /*
711 * Check the MIC on a region of an skbuff. The offset and length are updated
712 * to reflect the actual content of the secure region.
713 */
rfc3961_verify_mic(const struct krb5_enctype * krb5,struct crypto_shash * shash,const struct krb5_buffer * metadata,struct scatterlist * sg,unsigned int nr_sg,size_t * _offset,size_t * _len)714 int rfc3961_verify_mic(const struct krb5_enctype *krb5,
715 struct crypto_shash *shash,
716 const struct krb5_buffer *metadata,
717 struct scatterlist *sg, unsigned int nr_sg,
718 size_t *_offset, size_t *_len)
719 {
720 struct shash_desc *desc;
721 ssize_t done;
722 size_t bsize, data_offset, data_len, offset = *_offset, len = *_len;
723 void *buffer = NULL;
724 int ret;
725 u8 *cksum, *cksum2;
726
727 if (len < krb5->cksum_len)
728 return -EPROTO;
729 data_offset = offset + krb5->cksum_len;
730 data_len = len - krb5->cksum_len;
731
732 bsize = krb5_shash_size(shash) +
733 krb5_digest_size(shash) * 2;
734 buffer = kzalloc(bsize, GFP_NOFS);
735 if (!buffer)
736 return -ENOMEM;
737
738 cksum = buffer +
739 krb5_shash_size(shash);
740 cksum2 = buffer +
741 krb5_shash_size(shash) +
742 krb5_digest_size(shash);
743
744 /* Calculate the MIC */
745 desc = buffer;
746 desc->tfm = shash;
747 ret = crypto_shash_init(desc);
748 if (ret < 0)
749 goto error;
750
751 if (metadata) {
752 ret = crypto_shash_update(desc, metadata->data, metadata->len);
753 if (ret < 0)
754 goto error;
755 }
756
757 crypto_shash_update_sg(desc, sg, data_offset, data_len);
758 crypto_shash_final(desc, cksum);
759
760 ret = -EFAULT;
761 done = sg_pcopy_to_buffer(sg, nr_sg, cksum2, krb5->cksum_len, offset);
762 if (done != krb5->cksum_len)
763 goto error;
764
765 if (memcmp(cksum, cksum2, krb5->cksum_len) != 0) {
766 ret = -EBADMSG;
767 goto error;
768 }
769
770 *_offset += krb5->cksum_len;
771 *_len -= krb5->cksum_len;
772 ret = 0;
773
774 error:
775 kfree_sensitive(buffer);
776 return ret;
777 }
778
779 const struct krb5_crypto_profile rfc3961_simplified_profile = {
780 .calc_PRF = rfc3961_calc_PRF,
781 .calc_Kc = rfc3961_calc_DK,
782 .calc_Ke = rfc3961_calc_DK,
783 .calc_Ki = rfc3961_calc_DK,
784 .derive_encrypt_keys = authenc_derive_encrypt_keys,
785 .load_encrypt_keys = authenc_load_encrypt_keys,
786 .derive_checksum_key = rfc3961_derive_checksum_key,
787 .load_checksum_key = rfc3961_load_checksum_key,
788 .encrypt = krb5_aead_encrypt,
789 .decrypt = krb5_aead_decrypt,
790 .get_mic = rfc3961_get_mic,
791 .verify_mic = rfc3961_verify_mic,
792 };
793