162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * COPYRIGHT (c) 2008
362306a36Sopenharmony_ci * The Regents of the University of Michigan
462306a36Sopenharmony_ci * ALL RIGHTS RESERVED
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Permission is granted to use, copy, create derivative works
762306a36Sopenharmony_ci * and redistribute this software and such derivative works
862306a36Sopenharmony_ci * for any purpose, so long as the name of The University of
962306a36Sopenharmony_ci * Michigan is not used in any advertising or publicity
1062306a36Sopenharmony_ci * pertaining to the use of distribution of this software
1162306a36Sopenharmony_ci * without specific, written prior authorization.  If the
1262306a36Sopenharmony_ci * above copyright notice or any other identification of the
1362306a36Sopenharmony_ci * University of Michigan is included in any copy of any
1462306a36Sopenharmony_ci * portion of this software, then the disclaimer below must
1562306a36Sopenharmony_ci * also be included.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
1862306a36Sopenharmony_ci * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
1962306a36Sopenharmony_ci * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
2062306a36Sopenharmony_ci * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
2162306a36Sopenharmony_ci * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
2262306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
2362306a36Sopenharmony_ci * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
2462306a36Sopenharmony_ci * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
2562306a36Sopenharmony_ci * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
2662306a36Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
2762306a36Sopenharmony_ci * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
2862306a36Sopenharmony_ci * SUCH DAMAGES.
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/*
3262306a36Sopenharmony_ci * Copyright (C) 1998 by the FundsXpress, INC.
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * All rights reserved.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * Export of this software from the United States of America may require
3762306a36Sopenharmony_ci * a specific license from the United States Government.  It is the
3862306a36Sopenharmony_ci * responsibility of any person or organization contemplating export to
3962306a36Sopenharmony_ci * obtain such a license before exporting.
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
4262306a36Sopenharmony_ci * distribute this software and its documentation for any purpose and
4362306a36Sopenharmony_ci * without fee is hereby granted, provided that the above copyright
4462306a36Sopenharmony_ci * notice appear in all copies and that both that copyright notice and
4562306a36Sopenharmony_ci * this permission notice appear in supporting documentation, and that
4662306a36Sopenharmony_ci * the name of FundsXpress. not be used in advertising or publicity pertaining
4762306a36Sopenharmony_ci * to distribution of the software without specific, written prior
4862306a36Sopenharmony_ci * permission.  FundsXpress makes no representations about the suitability of
4962306a36Sopenharmony_ci * this software for any purpose.  It is provided "as is" without express
5062306a36Sopenharmony_ci * or implied warranty.
5162306a36Sopenharmony_ci *
5262306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
5362306a36Sopenharmony_ci * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
5462306a36Sopenharmony_ci * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
5562306a36Sopenharmony_ci */
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#include <crypto/skcipher.h>
5862306a36Sopenharmony_ci#include <linux/err.h>
5962306a36Sopenharmony_ci#include <linux/types.h>
6062306a36Sopenharmony_ci#include <linux/sunrpc/gss_krb5.h>
6162306a36Sopenharmony_ci#include <linux/sunrpc/xdr.h>
6262306a36Sopenharmony_ci#include <linux/lcm.h>
6362306a36Sopenharmony_ci#include <crypto/hash.h>
6462306a36Sopenharmony_ci#include <kunit/visibility.h>
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#include "gss_krb5_internal.h"
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
6962306a36Sopenharmony_ci# define RPCDBG_FACILITY        RPCDBG_AUTH
7062306a36Sopenharmony_ci#endif
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/**
7362306a36Sopenharmony_ci * krb5_nfold - n-fold function
7462306a36Sopenharmony_ci * @inbits: number of bits in @in
7562306a36Sopenharmony_ci * @in: buffer containing input to fold
7662306a36Sopenharmony_ci * @outbits: number of bits in the output buffer
7762306a36Sopenharmony_ci * @out: buffer to hold the result
7862306a36Sopenharmony_ci *
7962306a36Sopenharmony_ci * This is the n-fold function as described in rfc3961, sec 5.1
8062306a36Sopenharmony_ci * Taken from MIT Kerberos and modified.
8162306a36Sopenharmony_ci */
8262306a36Sopenharmony_ciVISIBLE_IF_KUNIT
8362306a36Sopenharmony_civoid krb5_nfold(u32 inbits, const u8 *in, u32 outbits, u8 *out)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	unsigned long ulcm;
8662306a36Sopenharmony_ci	int byte, i, msbit;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/* the code below is more readable if I make these bytes
8962306a36Sopenharmony_ci	   instead of bits */
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	inbits >>= 3;
9262306a36Sopenharmony_ci	outbits >>= 3;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	/* first compute lcm(n,k) */
9562306a36Sopenharmony_ci	ulcm = lcm(inbits, outbits);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	/* now do the real work */
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	memset(out, 0, outbits);
10062306a36Sopenharmony_ci	byte = 0;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	/* this will end up cycling through k lcm(k,n)/k times, which
10362306a36Sopenharmony_ci	   is correct */
10462306a36Sopenharmony_ci	for (i = ulcm-1; i >= 0; i--) {
10562306a36Sopenharmony_ci		/* compute the msbit in k which gets added into this byte */
10662306a36Sopenharmony_ci		msbit = (
10762306a36Sopenharmony_ci			/* first, start with the msbit in the first,
10862306a36Sopenharmony_ci			 * unrotated byte */
10962306a36Sopenharmony_ci			 ((inbits << 3) - 1)
11062306a36Sopenharmony_ci			 /* then, for each byte, shift to the right
11162306a36Sopenharmony_ci			  * for each repetition */
11262306a36Sopenharmony_ci			 + (((inbits << 3) + 13) * (i/inbits))
11362306a36Sopenharmony_ci			 /* last, pick out the correct byte within
11462306a36Sopenharmony_ci			  * that shifted repetition */
11562306a36Sopenharmony_ci			 + ((inbits - (i % inbits)) << 3)
11662306a36Sopenharmony_ci			 ) % (inbits << 3);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci		/* pull out the byte value itself */
11962306a36Sopenharmony_ci		byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8)|
12062306a36Sopenharmony_ci				  (in[((inbits) - (msbit >> 3)) % inbits]))
12162306a36Sopenharmony_ci				 >> ((msbit & 7) + 1)) & 0xff;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci		/* do the addition */
12462306a36Sopenharmony_ci		byte += out[i % outbits];
12562306a36Sopenharmony_ci		out[i % outbits] = byte & 0xff;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci		/* keep around the carry bit, if any */
12862306a36Sopenharmony_ci		byte >>= 8;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* if there's a carry bit left over, add it back in */
13362306a36Sopenharmony_ci	if (byte) {
13462306a36Sopenharmony_ci		for (i = outbits - 1; i >= 0; i--) {
13562306a36Sopenharmony_ci			/* do the addition */
13662306a36Sopenharmony_ci			byte += out[i];
13762306a36Sopenharmony_ci			out[i] = byte & 0xff;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci			/* keep around the carry bit, if any */
14062306a36Sopenharmony_ci			byte >>= 8;
14162306a36Sopenharmony_ci		}
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ciEXPORT_SYMBOL_IF_KUNIT(krb5_nfold);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/*
14762306a36Sopenharmony_ci * This is the DK (derive_key) function as described in rfc3961, sec 5.1
14862306a36Sopenharmony_ci * Taken from MIT Kerberos and modified.
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_cistatic int krb5_DK(const struct gss_krb5_enctype *gk5e,
15162306a36Sopenharmony_ci		   const struct xdr_netobj *inkey, u8 *rawkey,
15262306a36Sopenharmony_ci		   const struct xdr_netobj *in_constant, gfp_t gfp_mask)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	size_t blocksize, keybytes, keylength, n;
15562306a36Sopenharmony_ci	unsigned char *inblockdata, *outblockdata;
15662306a36Sopenharmony_ci	struct xdr_netobj inblock, outblock;
15762306a36Sopenharmony_ci	struct crypto_sync_skcipher *cipher;
15862306a36Sopenharmony_ci	int ret = -EINVAL;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	keybytes = gk5e->keybytes;
16162306a36Sopenharmony_ci	keylength = gk5e->keylength;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	if (inkey->len != keylength)
16462306a36Sopenharmony_ci		goto err_return;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	cipher = crypto_alloc_sync_skcipher(gk5e->encrypt_name, 0, 0);
16762306a36Sopenharmony_ci	if (IS_ERR(cipher))
16862306a36Sopenharmony_ci		goto err_return;
16962306a36Sopenharmony_ci	blocksize = crypto_sync_skcipher_blocksize(cipher);
17062306a36Sopenharmony_ci	if (crypto_sync_skcipher_setkey(cipher, inkey->data, inkey->len))
17162306a36Sopenharmony_ci		goto err_return;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	ret = -ENOMEM;
17462306a36Sopenharmony_ci	inblockdata = kmalloc(blocksize, gfp_mask);
17562306a36Sopenharmony_ci	if (inblockdata == NULL)
17662306a36Sopenharmony_ci		goto err_free_cipher;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	outblockdata = kmalloc(blocksize, gfp_mask);
17962306a36Sopenharmony_ci	if (outblockdata == NULL)
18062306a36Sopenharmony_ci		goto err_free_in;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	inblock.data = (char *) inblockdata;
18362306a36Sopenharmony_ci	inblock.len = blocksize;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	outblock.data = (char *) outblockdata;
18662306a36Sopenharmony_ci	outblock.len = blocksize;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* initialize the input block */
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	if (in_constant->len == inblock.len) {
19162306a36Sopenharmony_ci		memcpy(inblock.data, in_constant->data, inblock.len);
19262306a36Sopenharmony_ci	} else {
19362306a36Sopenharmony_ci		krb5_nfold(in_constant->len * 8, in_constant->data,
19462306a36Sopenharmony_ci			   inblock.len * 8, inblock.data);
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	/* loop encrypting the blocks until enough key bytes are generated */
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	n = 0;
20062306a36Sopenharmony_ci	while (n < keybytes) {
20162306a36Sopenharmony_ci		krb5_encrypt(cipher, NULL, inblock.data, outblock.data,
20262306a36Sopenharmony_ci			     inblock.len);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		if ((keybytes - n) <= outblock.len) {
20562306a36Sopenharmony_ci			memcpy(rawkey + n, outblock.data, (keybytes - n));
20662306a36Sopenharmony_ci			break;
20762306a36Sopenharmony_ci		}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci		memcpy(rawkey + n, outblock.data, outblock.len);
21062306a36Sopenharmony_ci		memcpy(inblock.data, outblock.data, outblock.len);
21162306a36Sopenharmony_ci		n += outblock.len;
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	ret = 0;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	kfree_sensitive(outblockdata);
21762306a36Sopenharmony_cierr_free_in:
21862306a36Sopenharmony_ci	kfree_sensitive(inblockdata);
21962306a36Sopenharmony_cierr_free_cipher:
22062306a36Sopenharmony_ci	crypto_free_sync_skcipher(cipher);
22162306a36Sopenharmony_cierr_return:
22262306a36Sopenharmony_ci	return ret;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/*
22662306a36Sopenharmony_ci * This is the identity function, with some sanity checking.
22762306a36Sopenharmony_ci */
22862306a36Sopenharmony_cistatic int krb5_random_to_key_v2(const struct gss_krb5_enctype *gk5e,
22962306a36Sopenharmony_ci				 struct xdr_netobj *randombits,
23062306a36Sopenharmony_ci				 struct xdr_netobj *key)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	int ret = -EINVAL;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (key->len != 16 && key->len != 32) {
23562306a36Sopenharmony_ci		dprintk("%s: key->len is %d\n", __func__, key->len);
23662306a36Sopenharmony_ci		goto err_out;
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci	if (randombits->len != 16 && randombits->len != 32) {
23962306a36Sopenharmony_ci		dprintk("%s: randombits->len is %d\n",
24062306a36Sopenharmony_ci			__func__, randombits->len);
24162306a36Sopenharmony_ci		goto err_out;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci	if (randombits->len != key->len) {
24462306a36Sopenharmony_ci		dprintk("%s: randombits->len is %d, key->len is %d\n",
24562306a36Sopenharmony_ci			__func__, randombits->len, key->len);
24662306a36Sopenharmony_ci		goto err_out;
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci	memcpy(key->data, randombits->data, key->len);
24962306a36Sopenharmony_ci	ret = 0;
25062306a36Sopenharmony_cierr_out:
25162306a36Sopenharmony_ci	return ret;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci/**
25562306a36Sopenharmony_ci * krb5_derive_key_v2 - Derive a subkey for an RFC 3962 enctype
25662306a36Sopenharmony_ci * @gk5e: Kerberos 5 enctype profile
25762306a36Sopenharmony_ci * @inkey: base protocol key
25862306a36Sopenharmony_ci * @outkey: OUT: derived key
25962306a36Sopenharmony_ci * @label: subkey usage label
26062306a36Sopenharmony_ci * @gfp_mask: memory allocation control flags
26162306a36Sopenharmony_ci *
26262306a36Sopenharmony_ci * Caller sets @outkey->len to the desired length of the derived key.
26362306a36Sopenharmony_ci *
26462306a36Sopenharmony_ci * On success, returns 0 and fills in @outkey. A negative errno value
26562306a36Sopenharmony_ci * is returned on failure.
26662306a36Sopenharmony_ci */
26762306a36Sopenharmony_ciint krb5_derive_key_v2(const struct gss_krb5_enctype *gk5e,
26862306a36Sopenharmony_ci		       const struct xdr_netobj *inkey,
26962306a36Sopenharmony_ci		       struct xdr_netobj *outkey,
27062306a36Sopenharmony_ci		       const struct xdr_netobj *label,
27162306a36Sopenharmony_ci		       gfp_t gfp_mask)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct xdr_netobj inblock;
27462306a36Sopenharmony_ci	int ret;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	inblock.len = gk5e->keybytes;
27762306a36Sopenharmony_ci	inblock.data = kmalloc(inblock.len, gfp_mask);
27862306a36Sopenharmony_ci	if (!inblock.data)
27962306a36Sopenharmony_ci		return -ENOMEM;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	ret = krb5_DK(gk5e, inkey, inblock.data, label, gfp_mask);
28262306a36Sopenharmony_ci	if (!ret)
28362306a36Sopenharmony_ci		ret = krb5_random_to_key_v2(gk5e, &inblock, outkey);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	kfree_sensitive(inblock.data);
28662306a36Sopenharmony_ci	return ret;
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci/*
29062306a36Sopenharmony_ci * K(i) = CMAC(key, K(i-1) | i | constant | 0x00 | k)
29162306a36Sopenharmony_ci *
29262306a36Sopenharmony_ci *    i: A block counter is used with a length of 4 bytes, represented
29362306a36Sopenharmony_ci *       in big-endian order.
29462306a36Sopenharmony_ci *
29562306a36Sopenharmony_ci *    constant: The label input to the KDF is the usage constant supplied
29662306a36Sopenharmony_ci *              to the key derivation function
29762306a36Sopenharmony_ci *
29862306a36Sopenharmony_ci *    k: The length of the output key in bits, represented as a 4-byte
29962306a36Sopenharmony_ci *       string in big-endian order.
30062306a36Sopenharmony_ci *
30162306a36Sopenharmony_ci * Caller fills in K(i-1) in @step, and receives the result K(i)
30262306a36Sopenharmony_ci * in the same buffer.
30362306a36Sopenharmony_ci */
30462306a36Sopenharmony_cistatic int
30562306a36Sopenharmony_cikrb5_cmac_Ki(struct crypto_shash *tfm, const struct xdr_netobj *constant,
30662306a36Sopenharmony_ci	     u32 outlen, u32 count, struct xdr_netobj *step)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	__be32 k = cpu_to_be32(outlen * 8);
30962306a36Sopenharmony_ci	SHASH_DESC_ON_STACK(desc, tfm);
31062306a36Sopenharmony_ci	__be32 i = cpu_to_be32(count);
31162306a36Sopenharmony_ci	u8 zero = 0;
31262306a36Sopenharmony_ci	int ret;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	desc->tfm = tfm;
31562306a36Sopenharmony_ci	ret = crypto_shash_init(desc);
31662306a36Sopenharmony_ci	if (ret)
31762306a36Sopenharmony_ci		goto out_err;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	ret = crypto_shash_update(desc, step->data, step->len);
32062306a36Sopenharmony_ci	if (ret)
32162306a36Sopenharmony_ci		goto out_err;
32262306a36Sopenharmony_ci	ret = crypto_shash_update(desc, (u8 *)&i, sizeof(i));
32362306a36Sopenharmony_ci	if (ret)
32462306a36Sopenharmony_ci		goto out_err;
32562306a36Sopenharmony_ci	ret = crypto_shash_update(desc, constant->data, constant->len);
32662306a36Sopenharmony_ci	if (ret)
32762306a36Sopenharmony_ci		goto out_err;
32862306a36Sopenharmony_ci	ret = crypto_shash_update(desc, &zero, sizeof(zero));
32962306a36Sopenharmony_ci	if (ret)
33062306a36Sopenharmony_ci		goto out_err;
33162306a36Sopenharmony_ci	ret = crypto_shash_update(desc, (u8 *)&k, sizeof(k));
33262306a36Sopenharmony_ci	if (ret)
33362306a36Sopenharmony_ci		goto out_err;
33462306a36Sopenharmony_ci	ret = crypto_shash_final(desc, step->data);
33562306a36Sopenharmony_ci	if (ret)
33662306a36Sopenharmony_ci		goto out_err;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ciout_err:
33962306a36Sopenharmony_ci	shash_desc_zero(desc);
34062306a36Sopenharmony_ci	return ret;
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci/**
34462306a36Sopenharmony_ci * krb5_kdf_feedback_cmac - Derive a subkey for a Camellia/CMAC-based enctype
34562306a36Sopenharmony_ci * @gk5e: Kerberos 5 enctype parameters
34662306a36Sopenharmony_ci * @inkey: base protocol key
34762306a36Sopenharmony_ci * @outkey: OUT: derived key
34862306a36Sopenharmony_ci * @constant: subkey usage label
34962306a36Sopenharmony_ci * @gfp_mask: memory allocation control flags
35062306a36Sopenharmony_ci *
35162306a36Sopenharmony_ci * RFC 6803 Section 3:
35262306a36Sopenharmony_ci *
35362306a36Sopenharmony_ci * "We use a key derivation function from the family specified in
35462306a36Sopenharmony_ci *  [SP800-108], Section 5.2, 'KDF in Feedback Mode'."
35562306a36Sopenharmony_ci *
35662306a36Sopenharmony_ci *	n = ceiling(k / 128)
35762306a36Sopenharmony_ci *	K(0) = zeros
35862306a36Sopenharmony_ci *	K(i) = CMAC(key, K(i-1) | i | constant | 0x00 | k)
35962306a36Sopenharmony_ci *	DR(key, constant) = k-truncate(K(1) | K(2) | ... | K(n))
36062306a36Sopenharmony_ci *	KDF-FEEDBACK-CMAC(key, constant) = random-to-key(DR(key, constant))
36162306a36Sopenharmony_ci *
36262306a36Sopenharmony_ci * Caller sets @outkey->len to the desired length of the derived key (k).
36362306a36Sopenharmony_ci *
36462306a36Sopenharmony_ci * On success, returns 0 and fills in @outkey. A negative errno value
36562306a36Sopenharmony_ci * is returned on failure.
36662306a36Sopenharmony_ci */
36762306a36Sopenharmony_ciint
36862306a36Sopenharmony_cikrb5_kdf_feedback_cmac(const struct gss_krb5_enctype *gk5e,
36962306a36Sopenharmony_ci		       const struct xdr_netobj *inkey,
37062306a36Sopenharmony_ci		       struct xdr_netobj *outkey,
37162306a36Sopenharmony_ci		       const struct xdr_netobj *constant,
37262306a36Sopenharmony_ci		       gfp_t gfp_mask)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	struct xdr_netobj step = { .data = NULL };
37562306a36Sopenharmony_ci	struct xdr_netobj DR = { .data = NULL };
37662306a36Sopenharmony_ci	unsigned int blocksize, offset;
37762306a36Sopenharmony_ci	struct crypto_shash *tfm;
37862306a36Sopenharmony_ci	int n, count, ret;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	/*
38162306a36Sopenharmony_ci	 * This implementation assumes the CMAC used for an enctype's
38262306a36Sopenharmony_ci	 * key derivation is the same as the CMAC used for its
38362306a36Sopenharmony_ci	 * checksumming. This happens to be true for enctypes that
38462306a36Sopenharmony_ci	 * are currently supported by this implementation.
38562306a36Sopenharmony_ci	 */
38662306a36Sopenharmony_ci	tfm = crypto_alloc_shash(gk5e->cksum_name, 0, 0);
38762306a36Sopenharmony_ci	if (IS_ERR(tfm)) {
38862306a36Sopenharmony_ci		ret = PTR_ERR(tfm);
38962306a36Sopenharmony_ci		goto out;
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci	ret = crypto_shash_setkey(tfm, inkey->data, inkey->len);
39262306a36Sopenharmony_ci	if (ret)
39362306a36Sopenharmony_ci		goto out_free_tfm;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	blocksize = crypto_shash_digestsize(tfm);
39662306a36Sopenharmony_ci	n = (outkey->len + blocksize - 1) / blocksize;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* K(0) is all zeroes */
39962306a36Sopenharmony_ci	ret = -ENOMEM;
40062306a36Sopenharmony_ci	step.len = blocksize;
40162306a36Sopenharmony_ci	step.data = kzalloc(step.len, gfp_mask);
40262306a36Sopenharmony_ci	if (!step.data)
40362306a36Sopenharmony_ci		goto out_free_tfm;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	DR.len = blocksize * n;
40662306a36Sopenharmony_ci	DR.data = kmalloc(DR.len, gfp_mask);
40762306a36Sopenharmony_ci	if (!DR.data)
40862306a36Sopenharmony_ci		goto out_free_tfm;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	/* XXX: Does not handle partial-block key sizes */
41162306a36Sopenharmony_ci	for (offset = 0, count = 1; count <= n; count++) {
41262306a36Sopenharmony_ci		ret = krb5_cmac_Ki(tfm, constant, outkey->len, count, &step);
41362306a36Sopenharmony_ci		if (ret)
41462306a36Sopenharmony_ci			goto out_free_tfm;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci		memcpy(DR.data + offset, step.data, blocksize);
41762306a36Sopenharmony_ci		offset += blocksize;
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* k-truncate and random-to-key */
42162306a36Sopenharmony_ci	memcpy(outkey->data, DR.data, outkey->len);
42262306a36Sopenharmony_ci	ret = 0;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ciout_free_tfm:
42562306a36Sopenharmony_ci	crypto_free_shash(tfm);
42662306a36Sopenharmony_ciout:
42762306a36Sopenharmony_ci	kfree_sensitive(step.data);
42862306a36Sopenharmony_ci	kfree_sensitive(DR.data);
42962306a36Sopenharmony_ci	return ret;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci/*
43362306a36Sopenharmony_ci * K1 = HMAC-SHA(key, 0x00000001 | label | 0x00 | k)
43462306a36Sopenharmony_ci *
43562306a36Sopenharmony_ci *    key: The source of entropy from which subsequent keys are derived.
43662306a36Sopenharmony_ci *
43762306a36Sopenharmony_ci *    label: An octet string describing the intended usage of the
43862306a36Sopenharmony_ci *    derived key.
43962306a36Sopenharmony_ci *
44062306a36Sopenharmony_ci *    k: Length in bits of the key to be outputted, expressed in
44162306a36Sopenharmony_ci *    big-endian binary representation in 4 bytes.
44262306a36Sopenharmony_ci */
44362306a36Sopenharmony_cistatic int
44462306a36Sopenharmony_cikrb5_hmac_K1(struct crypto_shash *tfm, const struct xdr_netobj *label,
44562306a36Sopenharmony_ci	     u32 outlen, struct xdr_netobj *K1)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	__be32 k = cpu_to_be32(outlen * 8);
44862306a36Sopenharmony_ci	SHASH_DESC_ON_STACK(desc, tfm);
44962306a36Sopenharmony_ci	__be32 one = cpu_to_be32(1);
45062306a36Sopenharmony_ci	u8 zero = 0;
45162306a36Sopenharmony_ci	int ret;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	desc->tfm = tfm;
45462306a36Sopenharmony_ci	ret = crypto_shash_init(desc);
45562306a36Sopenharmony_ci	if (ret)
45662306a36Sopenharmony_ci		goto out_err;
45762306a36Sopenharmony_ci	ret = crypto_shash_update(desc, (u8 *)&one, sizeof(one));
45862306a36Sopenharmony_ci	if (ret)
45962306a36Sopenharmony_ci		goto out_err;
46062306a36Sopenharmony_ci	ret = crypto_shash_update(desc, label->data, label->len);
46162306a36Sopenharmony_ci	if (ret)
46262306a36Sopenharmony_ci		goto out_err;
46362306a36Sopenharmony_ci	ret = crypto_shash_update(desc, &zero, sizeof(zero));
46462306a36Sopenharmony_ci	if (ret)
46562306a36Sopenharmony_ci		goto out_err;
46662306a36Sopenharmony_ci	ret = crypto_shash_update(desc, (u8 *)&k, sizeof(k));
46762306a36Sopenharmony_ci	if (ret)
46862306a36Sopenharmony_ci		goto out_err;
46962306a36Sopenharmony_ci	ret = crypto_shash_final(desc, K1->data);
47062306a36Sopenharmony_ci	if (ret)
47162306a36Sopenharmony_ci		goto out_err;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ciout_err:
47462306a36Sopenharmony_ci	shash_desc_zero(desc);
47562306a36Sopenharmony_ci	return ret;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci/**
47962306a36Sopenharmony_ci * krb5_kdf_hmac_sha2 - Derive a subkey for an AES/SHA2-based enctype
48062306a36Sopenharmony_ci * @gk5e: Kerberos 5 enctype policy parameters
48162306a36Sopenharmony_ci * @inkey: base protocol key
48262306a36Sopenharmony_ci * @outkey: OUT: derived key
48362306a36Sopenharmony_ci * @label: subkey usage label
48462306a36Sopenharmony_ci * @gfp_mask: memory allocation control flags
48562306a36Sopenharmony_ci *
48662306a36Sopenharmony_ci * RFC 8009 Section 3:
48762306a36Sopenharmony_ci *
48862306a36Sopenharmony_ci *  "We use a key derivation function from Section 5.1 of [SP800-108],
48962306a36Sopenharmony_ci *   which uses the HMAC algorithm as the PRF."
49062306a36Sopenharmony_ci *
49162306a36Sopenharmony_ci *	function KDF-HMAC-SHA2(key, label, [context,] k):
49262306a36Sopenharmony_ci *		k-truncate(K1)
49362306a36Sopenharmony_ci *
49462306a36Sopenharmony_ci * Caller sets @outkey->len to the desired length of the derived key.
49562306a36Sopenharmony_ci *
49662306a36Sopenharmony_ci * On success, returns 0 and fills in @outkey. A negative errno value
49762306a36Sopenharmony_ci * is returned on failure.
49862306a36Sopenharmony_ci */
49962306a36Sopenharmony_ciint
50062306a36Sopenharmony_cikrb5_kdf_hmac_sha2(const struct gss_krb5_enctype *gk5e,
50162306a36Sopenharmony_ci		   const struct xdr_netobj *inkey,
50262306a36Sopenharmony_ci		   struct xdr_netobj *outkey,
50362306a36Sopenharmony_ci		   const struct xdr_netobj *label,
50462306a36Sopenharmony_ci		   gfp_t gfp_mask)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	struct crypto_shash *tfm;
50762306a36Sopenharmony_ci	struct xdr_netobj K1 = {
50862306a36Sopenharmony_ci		.data = NULL,
50962306a36Sopenharmony_ci	};
51062306a36Sopenharmony_ci	int ret;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/*
51362306a36Sopenharmony_ci	 * This implementation assumes the HMAC used for an enctype's
51462306a36Sopenharmony_ci	 * key derivation is the same as the HMAC used for its
51562306a36Sopenharmony_ci	 * checksumming. This happens to be true for enctypes that
51662306a36Sopenharmony_ci	 * are currently supported by this implementation.
51762306a36Sopenharmony_ci	 */
51862306a36Sopenharmony_ci	tfm = crypto_alloc_shash(gk5e->cksum_name, 0, 0);
51962306a36Sopenharmony_ci	if (IS_ERR(tfm)) {
52062306a36Sopenharmony_ci		ret = PTR_ERR(tfm);
52162306a36Sopenharmony_ci		goto out;
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci	ret = crypto_shash_setkey(tfm, inkey->data, inkey->len);
52462306a36Sopenharmony_ci	if (ret)
52562306a36Sopenharmony_ci		goto out_free_tfm;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	K1.len = crypto_shash_digestsize(tfm);
52862306a36Sopenharmony_ci	K1.data = kmalloc(K1.len, gfp_mask);
52962306a36Sopenharmony_ci	if (!K1.data) {
53062306a36Sopenharmony_ci		ret = -ENOMEM;
53162306a36Sopenharmony_ci		goto out_free_tfm;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	ret = krb5_hmac_K1(tfm, label, outkey->len, &K1);
53562306a36Sopenharmony_ci	if (ret)
53662306a36Sopenharmony_ci		goto out_free_tfm;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	/* k-truncate and random-to-key */
53962306a36Sopenharmony_ci	memcpy(outkey->data, K1.data, outkey->len);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ciout_free_tfm:
54262306a36Sopenharmony_ci	kfree_sensitive(K1.data);
54362306a36Sopenharmony_ci	crypto_free_shash(tfm);
54462306a36Sopenharmony_ciout:
54562306a36Sopenharmony_ci	return ret;
54662306a36Sopenharmony_ci}
547