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 sg_miter_skip(&miter, offset);
93 for (i = 0; i < len; i += n) {
94 sg_miter_next(&miter);
95 n = min(miter.length, len - i);
96 ret = crypto_shash_update(desc, miter.addr, n);
97 if (ret < 0)
98 break;
99 }
100 sg_miter_stop(&miter);
101 return ret;
102 }
103
rfc3961_do_encrypt(struct crypto_sync_skcipher * tfm,void * iv,const struct krb5_buffer * in,struct krb5_buffer * out)104 static int rfc3961_do_encrypt(struct crypto_sync_skcipher *tfm, void *iv,
105 const struct krb5_buffer *in, struct krb5_buffer *out)
106 {
107 struct scatterlist sg[1];
108 u8 local_iv[KRB5_MAX_BLOCKSIZE] __aligned(KRB5_MAX_BLOCKSIZE) = {0};
109 SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
110 int ret;
111
112 if (WARN_ON(in->len != out->len))
113 return -EINVAL;
114 if (out->len % crypto_sync_skcipher_blocksize(tfm) != 0)
115 return -EINVAL;
116
117 if (crypto_sync_skcipher_ivsize(tfm) > KRB5_MAX_BLOCKSIZE)
118 return -EINVAL;
119
120 if (iv)
121 memcpy(local_iv, iv, crypto_sync_skcipher_ivsize(tfm));
122
123 memcpy(out->data, in->data, out->len);
124 sg_init_one(sg, out->data, out->len);
125
126 skcipher_request_set_sync_tfm(req, tfm);
127 skcipher_request_set_callback(req, 0, NULL, NULL);
128 skcipher_request_set_crypt(req, sg, sg, out->len, local_iv);
129
130 ret = crypto_skcipher_encrypt(req);
131 skcipher_request_zero(req);
132 return ret;
133 }
134
135 /*
136 * Calculate an unkeyed basic hash.
137 */
rfc3961_calc_H(const struct krb5_enctype * krb5,const struct krb5_buffer * data,struct krb5_buffer * digest,gfp_t gfp)138 static int rfc3961_calc_H(const struct krb5_enctype *krb5,
139 const struct krb5_buffer *data,
140 struct krb5_buffer *digest,
141 gfp_t gfp)
142 {
143 struct crypto_shash *tfm;
144 struct shash_desc *desc;
145 size_t desc_size;
146 int ret = -ENOMEM;
147
148 tfm = crypto_alloc_shash(krb5->hash_name, 0, 0);
149 if (IS_ERR(tfm))
150 return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
151
152 desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
153
154 desc = kzalloc(desc_size, gfp);
155 if (!desc)
156 goto error_tfm;
157
158 digest->len = crypto_shash_digestsize(tfm);
159 digest->data = kzalloc(digest->len, gfp);
160 if (!digest->data)
161 goto error_desc;
162
163 desc->tfm = tfm;
164 ret = crypto_shash_init(desc);
165 if (ret < 0)
166 goto error_digest;
167
168 ret = crypto_shash_finup(desc, data->data, data->len, digest->data);
169 if (ret < 0)
170 goto error_digest;
171
172 goto error_desc;
173
174 error_digest:
175 kfree_sensitive(digest->data);
176 error_desc:
177 kfree_sensitive(desc);
178 error_tfm:
179 crypto_free_shash(tfm);
180 return ret;
181 }
182
183 /*
184 * This is the n-fold function as described in rfc3961, sec 5.1
185 * Taken from MIT Kerberos and modified.
186 */
rfc3961_nfold(const struct krb5_buffer * source,struct krb5_buffer * result)187 static void rfc3961_nfold(const struct krb5_buffer *source, struct krb5_buffer *result)
188 {
189 const u8 *in = source->data;
190 u8 *out = result->data;
191 unsigned long ulcm;
192 unsigned int inbits, outbits;
193 int byte, i, msbit;
194
195 /* the code below is more readable if I make these bytes instead of bits */
196 inbits = source->len;
197 outbits = result->len;
198
199 /* first compute lcm(n,k) */
200 ulcm = lcm(inbits, outbits);
201
202 /* now do the real work */
203 memset(out, 0, outbits);
204 byte = 0;
205
206 /* this will end up cycling through k lcm(k,n)/k times, which
207 * is correct.
208 */
209 for (i = ulcm-1; i >= 0; i--) {
210 /* compute the msbit in k which gets added into this byte */
211 msbit = (
212 /* first, start with the msbit in the first,
213 * unrotated byte
214 */
215 ((inbits << 3) - 1) +
216 /* then, for each byte, shift to the right
217 * for each repetition
218 */
219 (((inbits << 3) + 13) * (i/inbits)) +
220 /* last, pick out the correct byte within
221 * that shifted repetition
222 */
223 ((inbits - (i % inbits)) << 3)
224 ) % (inbits << 3);
225
226 /* pull out the byte value itself */
227 byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8) |
228 (in[((inbits) - (msbit >> 3)) % inbits]))
229 >> ((msbit & 7) + 1)) & 0xff;
230
231 /* do the addition */
232 byte += out[i % outbits];
233 out[i % outbits] = byte & 0xff;
234
235 /* keep around the carry bit, if any */
236 byte >>= 8;
237 }
238
239 /* if there's a carry bit left over, add it back in */
240 if (byte) {
241 for (i = outbits - 1; i >= 0; i--) {
242 /* do the addition */
243 byte += out[i];
244 out[i] = byte & 0xff;
245
246 /* keep around the carry bit, if any */
247 byte >>= 8;
248 }
249 }
250 }
251
252 /*
253 * Calculate a derived key, DK(Base Key, Well-Known Constant)
254 *
255 * DK(Key, Constant) = random-to-key(DR(Key, Constant))
256 * DR(Key, Constant) = k-truncate(E(Key, Constant, initial-cipher-state))
257 * K1 = E(Key, n-fold(Constant), initial-cipher-state)
258 * K2 = E(Key, K1, initial-cipher-state)
259 * K3 = E(Key, K2, initial-cipher-state)
260 * K4 = ...
261 * DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)
262 * [rfc3961 sec 5.1]
263 */
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)264 static int rfc3961_calc_DK(const struct krb5_enctype *krb5,
265 const struct krb5_buffer *inkey,
266 const struct krb5_buffer *in_constant,
267 struct krb5_buffer *result,
268 gfp_t gfp)
269 {
270 unsigned int blocksize, keybytes, keylength, n;
271 struct krb5_buffer inblock, outblock, rawkey;
272 struct crypto_sync_skcipher *cipher;
273 int ret = -EINVAL;
274
275 blocksize = krb5->block_len;
276 keybytes = krb5->key_bytes;
277 keylength = krb5->key_len;
278
279 if (inkey->len != keylength || result->len != keylength)
280 return -EINVAL;
281 if (!krb5->random_to_key && result->len != keybytes)
282 return -EINVAL;
283
284 cipher = crypto_alloc_sync_skcipher(krb5->derivation_enc, 0, 0);
285 if (IS_ERR(cipher)) {
286 ret = (PTR_ERR(cipher) == -ENOENT) ? -ENOPKG : PTR_ERR(cipher);
287 goto err_return;
288 }
289 ret = crypto_sync_skcipher_setkey(cipher, inkey->data, inkey->len);
290 if (ret < 0)
291 goto err_free_cipher;
292
293 ret = -ENOMEM;
294 inblock.data = kzalloc(blocksize * 2 + keybytes, gfp);
295 if (!inblock.data)
296 goto err_free_cipher;
297
298 inblock.len = blocksize;
299 outblock.data = inblock.data + blocksize;
300 outblock.len = blocksize;
301 rawkey.data = outblock.data + blocksize;
302 rawkey.len = keybytes;
303
304 /* initialize the input block */
305
306 if (in_constant->len == inblock.len)
307 memcpy(inblock.data, in_constant->data, inblock.len);
308 else
309 rfc3961_nfold(in_constant, &inblock);
310
311 /* loop encrypting the blocks until enough key bytes are generated */
312 n = 0;
313 while (n < rawkey.len) {
314 rfc3961_do_encrypt(cipher, NULL, &inblock, &outblock);
315
316 if (keybytes - n <= outblock.len) {
317 memcpy(rawkey.data + n, outblock.data, keybytes - n);
318 break;
319 }
320
321 memcpy(rawkey.data + n, outblock.data, outblock.len);
322 memcpy(inblock.data, outblock.data, outblock.len);
323 n += outblock.len;
324 }
325
326 /* postprocess the key */
327 if (!krb5->random_to_key) {
328 /* Identity random-to-key function. */
329 memcpy(result->data, rawkey.data, rawkey.len);
330 ret = 0;
331 } else {
332 ret = krb5->random_to_key(krb5, &rawkey, result);
333 }
334
335 kfree_sensitive(inblock.data);
336 err_free_cipher:
337 crypto_free_sync_skcipher(cipher);
338 err_return:
339 return ret;
340 }
341
342 /*
343 * Calculate single encryption, E()
344 *
345 * E(Key, octets)
346 */
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)347 static int rfc3961_calc_E(const struct krb5_enctype *krb5,
348 const struct krb5_buffer *key,
349 const struct krb5_buffer *in_data,
350 struct krb5_buffer *result,
351 gfp_t gfp)
352 {
353 struct crypto_sync_skcipher *cipher;
354 int ret;
355
356 cipher = crypto_alloc_sync_skcipher(krb5->derivation_enc, 0, 0);
357 if (IS_ERR(cipher)) {
358 ret = (PTR_ERR(cipher) == -ENOENT) ? -ENOPKG : PTR_ERR(cipher);
359 goto err;
360 }
361
362 ret = crypto_sync_skcipher_setkey(cipher, key->data, key->len);
363 if (ret < 0)
364 goto err_free;
365
366 ret = rfc3961_do_encrypt(cipher, NULL, in_data, result);
367
368 err_free:
369 crypto_free_sync_skcipher(cipher);
370 err:
371 return ret;
372 }
373
374 /*
375 * Calculate the pseudo-random function, PRF().
376 *
377 * tmp1 = H(octet-string)
378 * tmp2 = truncate tmp1 to multiple of m
379 * PRF = E(DK(protocol-key, prfconstant), tmp2, initial-cipher-state)
380 *
381 * The "prfconstant" used in the PRF operation is the three-octet string
382 * "prf".
383 * [rfc3961 sec 5.3]
384 */
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)385 static int rfc3961_calc_PRF(const struct krb5_enctype *krb5,
386 const struct krb5_buffer *protocol_key,
387 const struct krb5_buffer *octet_string,
388 struct krb5_buffer *result,
389 gfp_t gfp)
390 {
391 static const struct krb5_buffer prfconstant = { 3, "prf" };
392 struct krb5_buffer derived_key;
393 struct krb5_buffer tmp1, tmp2;
394 unsigned int m = krb5->block_len;
395 void *buffer;
396 int ret;
397
398 if (result->len != krb5->prf_len)
399 return -EINVAL;
400
401 tmp1.len = krb5->hash_len;
402 derived_key.len = krb5->key_bytes;
403 buffer = kzalloc(round16(tmp1.len) + round16(derived_key.len), gfp);
404 if (!buffer)
405 return -ENOMEM;
406
407 tmp1.data = buffer;
408 derived_key.data = buffer + round16(tmp1.len);
409
410 ret = rfc3961_calc_H(krb5, octet_string, &tmp1, gfp);
411 if (ret < 0)
412 goto err;
413
414 tmp2.len = tmp1.len & ~(m - 1);
415 tmp2.data = tmp1.data;
416
417 ret = rfc3961_calc_DK(krb5, protocol_key, &prfconstant, &derived_key, gfp);
418 if (ret < 0)
419 goto err;
420
421 ret = rfc3961_calc_E(krb5, &derived_key, &tmp2, result, gfp);
422
423 err:
424 kfree_sensitive(buffer);
425 return ret;
426 }
427
428 /*
429 * Derive the Ke and Ki keys and package them into a key parameter that can be
430 * given to the setkey of a authenc AEAD crypto object.
431 */
authenc_derive_encrypt_keys(const struct krb5_enctype * krb5,const struct krb5_buffer * TK,unsigned int usage,struct krb5_buffer * setkey,gfp_t gfp)432 int authenc_derive_encrypt_keys(const struct krb5_enctype *krb5,
433 const struct krb5_buffer *TK,
434 unsigned int usage,
435 struct krb5_buffer *setkey,
436 gfp_t gfp)
437 {
438 struct crypto_authenc_key_param *param;
439 struct krb5_buffer Ke, Ki;
440 struct rtattr *rta;
441 int ret;
442
443 Ke.len = krb5->Ke_len;
444 Ki.len = krb5->Ki_len;
445 setkey->len = RTA_LENGTH(sizeof(*param)) + Ke.len + Ki.len;
446 setkey->data = kzalloc(setkey->len, GFP_KERNEL);
447 if (!setkey->data)
448 return -ENOMEM;
449
450 rta = setkey->data;
451 rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
452 rta->rta_len = RTA_LENGTH(sizeof(*param));
453 param = RTA_DATA(rta);
454 param->enckeylen = htonl(Ke.len);
455
456 Ki.data = (void *)(param + 1);
457 Ke.data = Ki.data + Ki.len;
458
459 ret = krb5_derive_Ke(krb5, TK, usage, &Ke, gfp);
460 if (ret < 0) {
461 pr_err("get_Ke failed %d\n", ret);
462 return ret;
463 }
464 ret = krb5_derive_Ki(krb5, TK, usage, &Ki, gfp);
465 if (ret < 0)
466 pr_err("get_Ki failed %d\n", ret);
467 return ret;
468 }
469
470 /*
471 * Package predefined Ke and Ki keys and into a key parameter that can be given
472 * to the setkey of an authenc AEAD crypto object.
473 */
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)474 int authenc_load_encrypt_keys(const struct krb5_enctype *krb5,
475 const struct krb5_buffer *Ke,
476 const struct krb5_buffer *Ki,
477 struct krb5_buffer *setkey,
478 gfp_t gfp)
479 {
480 struct crypto_authenc_key_param *param;
481 struct rtattr *rta;
482
483 setkey->len = RTA_LENGTH(sizeof(*param)) + Ke->len + Ki->len;
484 setkey->data = kzalloc(setkey->len, GFP_KERNEL);
485 if (!setkey->data)
486 return -ENOMEM;
487
488 rta = setkey->data;
489 rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
490 rta->rta_len = RTA_LENGTH(sizeof(*param));
491 param = RTA_DATA(rta);
492 param->enckeylen = htonl(Ke->len);
493 memcpy((void *)(param + 1), Ki->data, Ki->len);
494 memcpy((void *)(param + 1) + Ki->len, Ke->data, Ke->len);
495 return 0;
496 }
497
498 /*
499 * Derive the Kc key for checksum-only mode and package it into a key parameter
500 * that can be given to the setkey of a hash crypto object.
501 */
rfc3961_derive_checksum_key(const struct krb5_enctype * krb5,const struct krb5_buffer * TK,unsigned int usage,struct krb5_buffer * setkey,gfp_t gfp)502 int rfc3961_derive_checksum_key(const struct krb5_enctype *krb5,
503 const struct krb5_buffer *TK,
504 unsigned int usage,
505 struct krb5_buffer *setkey,
506 gfp_t gfp)
507 {
508 int ret;
509
510 setkey->len = krb5->Kc_len;
511 setkey->data = kzalloc(setkey->len, GFP_KERNEL);
512 if (!setkey->data)
513 return -ENOMEM;
514
515 ret = krb5_derive_Kc(krb5, TK, usage, setkey, gfp);
516 if (ret < 0)
517 pr_err("get_Kc failed %d\n", ret);
518 return ret;
519 }
520
521 /*
522 * Package a predefined Kc key for checksum-only mode into a key parameter that
523 * can be given to the setkey of a hash crypto object.
524 */
rfc3961_load_checksum_key(const struct krb5_enctype * krb5,const struct krb5_buffer * Kc,struct krb5_buffer * setkey,gfp_t gfp)525 int rfc3961_load_checksum_key(const struct krb5_enctype *krb5,
526 const struct krb5_buffer *Kc,
527 struct krb5_buffer *setkey,
528 gfp_t gfp)
529 {
530 setkey->len = krb5->Kc_len;
531 setkey->data = kmemdup(Kc->data, Kc->len, GFP_KERNEL);
532 if (!setkey->data)
533 return -ENOMEM;
534 return 0;
535 }
536
537 /*
538 * Apply encryption and checksumming functions to part of a scatterlist.
539 */
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)540 ssize_t krb5_aead_encrypt(const struct krb5_enctype *krb5,
541 struct crypto_aead *aead,
542 struct scatterlist *sg, unsigned int nr_sg, size_t sg_len,
543 size_t data_offset, size_t data_len,
544 bool preconfounded)
545 {
546 struct aead_request *req;
547 ssize_t ret, done;
548 size_t bsize, base_len, secure_offset, secure_len, pad_len, cksum_offset;
549 void *buffer;
550 u8 *iv;
551
552 if (WARN_ON(data_offset != krb5->conf_len))
553 return -EINVAL; /* Data is in wrong place */
554
555 secure_offset = 0;
556 base_len = krb5->conf_len + data_len;
557 pad_len = 0;
558 secure_len = base_len + pad_len;
559 cksum_offset = secure_len;
560 if (WARN_ON(cksum_offset + krb5->cksum_len > sg_len))
561 return -EFAULT;
562
563 bsize = krb5_aead_size(aead) +
564 krb5_aead_ivsize(aead);
565 buffer = kzalloc(bsize, GFP_NOFS);
566 if (!buffer)
567 return -ENOMEM;
568
569 /* Insert the confounder into the buffer */
570 ret = -EFAULT;
571 if (!preconfounded) {
572 get_random_bytes(buffer, krb5->conf_len);
573 done = sg_pcopy_from_buffer(sg, nr_sg, buffer, krb5->conf_len,
574 secure_offset);
575 if (done != krb5->conf_len)
576 goto error;
577 }
578
579 /* We may need to pad out to the crypto blocksize. */
580 if (pad_len) {
581 done = sg_zero_buffer(sg, nr_sg, pad_len, data_offset + data_len);
582 if (done != pad_len)
583 goto error;
584 }
585
586 /* Hash and encrypt the message. */
587 req = buffer;
588 iv = buffer + krb5_aead_size(aead);
589
590 aead_request_set_tfm(req, aead);
591 aead_request_set_callback(req, 0, NULL, NULL);
592 aead_request_set_crypt(req, sg, sg, secure_len, iv);
593 ret = crypto_aead_encrypt(req);
594 if (ret < 0)
595 goto error;
596
597 ret = secure_len + krb5->cksum_len;
598
599 error:
600 kfree_sensitive(buffer);
601 return ret;
602 }
603
604 /*
605 * Apply decryption and checksumming functions to a message. The offset and
606 * length are updated to reflect the actual content of the encrypted region.
607 */
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)608 int krb5_aead_decrypt(const struct krb5_enctype *krb5,
609 struct crypto_aead *aead,
610 struct scatterlist *sg, unsigned int nr_sg,
611 size_t *_offset, size_t *_len)
612 {
613 struct aead_request *req;
614 size_t bsize;
615 void *buffer;
616 int ret;
617 u8 *iv;
618
619 if (WARN_ON(*_offset != 0))
620 return -EINVAL; /* Can't set offset on aead */
621
622 if (*_len < krb5->conf_len + krb5->cksum_len)
623 return -EPROTO;
624
625 bsize = krb5_aead_size(aead) +
626 krb5_aead_ivsize(aead);
627 buffer = kzalloc(bsize, GFP_NOFS);
628 if (!buffer)
629 return -ENOMEM;
630
631 /* Decrypt the message and verify its checksum. */
632 req = buffer;
633 iv = buffer + krb5_aead_size(aead);
634
635 aead_request_set_tfm(req, aead);
636 aead_request_set_callback(req, 0, NULL, NULL);
637 aead_request_set_crypt(req, sg, sg, *_len, iv);
638 ret = crypto_aead_decrypt(req);
639 if (ret < 0)
640 goto error;
641
642 /* Adjust the boundaries of the data. */
643 *_offset += krb5->conf_len;
644 *_len -= krb5->conf_len + krb5->cksum_len;
645 ret = 0;
646
647 error:
648 kfree_sensitive(buffer);
649 return ret;
650 }
651
652 /*
653 * Generate a checksum over some metadata and part of an skbuff and insert the
654 * MIC into the skbuff immediately prior to the data.
655 */
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)656 ssize_t rfc3961_get_mic(const struct krb5_enctype *krb5,
657 struct crypto_shash *shash,
658 const struct krb5_buffer *metadata,
659 struct scatterlist *sg, unsigned int nr_sg, size_t sg_len,
660 size_t data_offset, size_t data_len)
661 {
662 struct shash_desc *desc;
663 ssize_t ret, done;
664 size_t bsize;
665 void *buffer, *digest;
666
667 if (WARN_ON(data_offset != krb5->cksum_len))
668 return -EMSGSIZE;
669
670 bsize = krb5_shash_size(shash) +
671 krb5_digest_size(shash);
672 buffer = kzalloc(bsize, GFP_NOFS);
673 if (!buffer)
674 return -ENOMEM;
675
676 /* Calculate the MIC with key Kc and store it into the skb */
677 desc = buffer;
678 desc->tfm = shash;
679 ret = crypto_shash_init(desc);
680 if (ret < 0)
681 goto error;
682
683 if (metadata) {
684 ret = crypto_shash_update(desc, metadata->data, metadata->len);
685 if (ret < 0)
686 goto error;
687 }
688
689 ret = crypto_shash_update_sg(desc, sg, data_offset, data_len);
690 if (ret < 0)
691 goto error;
692
693 digest = buffer + krb5_shash_size(shash);
694 ret = crypto_shash_final(desc, digest);
695 if (ret < 0)
696 goto error;
697
698 ret = -EFAULT;
699 done = sg_pcopy_from_buffer(sg, nr_sg, digest, krb5->cksum_len,
700 data_offset - krb5->cksum_len);
701 if (done != krb5->cksum_len)
702 goto error;
703
704 ret = krb5->cksum_len + data_len;
705
706 error:
707 kfree_sensitive(buffer);
708 return ret;
709 }
710
711 /*
712 * Check the MIC on a region of an skbuff. The offset and length are updated
713 * to reflect the actual content of the secure region.
714 */
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)715 int rfc3961_verify_mic(const struct krb5_enctype *krb5,
716 struct crypto_shash *shash,
717 const struct krb5_buffer *metadata,
718 struct scatterlist *sg, unsigned int nr_sg,
719 size_t *_offset, size_t *_len)
720 {
721 struct shash_desc *desc;
722 ssize_t done;
723 size_t bsize, data_offset, data_len, offset = *_offset, len = *_len;
724 void *buffer = NULL;
725 int ret;
726 u8 *cksum, *cksum2;
727
728 if (len < krb5->cksum_len)
729 return -EPROTO;
730 data_offset = offset + krb5->cksum_len;
731 data_len = len - krb5->cksum_len;
732
733 bsize = krb5_shash_size(shash) +
734 krb5_digest_size(shash) * 2;
735 buffer = kzalloc(bsize, GFP_NOFS);
736 if (!buffer)
737 return -ENOMEM;
738
739 cksum = buffer +
740 krb5_shash_size(shash);
741 cksum2 = buffer +
742 krb5_shash_size(shash) +
743 krb5_digest_size(shash);
744
745 /* Calculate the MIC */
746 desc = buffer;
747 desc->tfm = shash;
748 ret = crypto_shash_init(desc);
749 if (ret < 0)
750 goto error;
751
752 if (metadata) {
753 ret = crypto_shash_update(desc, metadata->data, metadata->len);
754 if (ret < 0)
755 goto error;
756 }
757
758 crypto_shash_update_sg(desc, sg, data_offset, data_len);
759 crypto_shash_final(desc, cksum);
760
761 ret = -EFAULT;
762 done = sg_pcopy_to_buffer(sg, nr_sg, cksum2, krb5->cksum_len, offset);
763 if (done != krb5->cksum_len)
764 goto error;
765
766 if (memcmp(cksum, cksum2, krb5->cksum_len) != 0) {
767 ret = -EBADMSG;
768 goto error;
769 }
770
771 *_offset += krb5->cksum_len;
772 *_len -= krb5->cksum_len;
773 ret = 0;
774
775 error:
776 kfree_sensitive(buffer);
777 return ret;
778 }
779
780 const struct krb5_crypto_profile rfc3961_simplified_profile = {
781 .calc_PRF = rfc3961_calc_PRF,
782 .calc_Kc = rfc3961_calc_DK,
783 .calc_Ke = rfc3961_calc_DK,
784 .calc_Ki = rfc3961_calc_DK,
785 .derive_encrypt_keys = authenc_derive_encrypt_keys,
786 .load_encrypt_keys = authenc_load_encrypt_keys,
787 .derive_checksum_key = rfc3961_derive_checksum_key,
788 .load_checksum_key = rfc3961_load_checksum_key,
789 .encrypt = krb5_aead_encrypt,
790 .decrypt = krb5_aead_decrypt,
791 .get_mic = rfc3961_get_mic,
792 .verify_mic = rfc3961_verify_mic,
793 };
794