File Index
Files and directories
Sign in
FILE

rfc3961_simplified.c

File preview with syntax highlighting.

linux-6.19.14/crypto/krb5/rfc3961_simplified.c C
  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
 83int 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
104static 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 */
138static 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
174error_digest:
175	kfree_sensitive(digest->data);
176error_desc:
177	kfree_sensitive(desc);
178error_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 */
187static 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 */
264static 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);
336err_free_cipher:
337	crypto_free_sync_skcipher(cipher);
338err_return:
339	return ret;
340}
341
342/*
343 * Calculate single encryption, E()
344 *
345 *	E(Key, octets)
346 */
347static 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
368err_free:
369	crypto_free_sync_skcipher(cipher);
370err:
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 */
385static 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
423err:
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 */
432int 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 */
474int 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 */
502int 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 */
525int 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 */
540ssize_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
599error:
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 */
608int 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
647error:
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 */
656ssize_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
706error:
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 */
715int 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
775error:
776	kfree_sensitive(buffer);
777	return ret;
778}
779
780const 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};
~/ Read-only file preview.