14891f2d0SKevin Coffman /*
24891f2d0SKevin Coffman  * COPYRIGHT (c) 2008
34891f2d0SKevin Coffman  * The Regents of the University of Michigan
44891f2d0SKevin Coffman  * ALL RIGHTS RESERVED
54891f2d0SKevin Coffman  *
64891f2d0SKevin Coffman  * Permission is granted to use, copy, create derivative works
74891f2d0SKevin Coffman  * and redistribute this software and such derivative works
84891f2d0SKevin Coffman  * for any purpose, so long as the name of The University of
94891f2d0SKevin Coffman  * Michigan is not used in any advertising or publicity
104891f2d0SKevin Coffman  * pertaining to the use of distribution of this software
114891f2d0SKevin Coffman  * without specific, written prior authorization.  If the
124891f2d0SKevin Coffman  * above copyright notice or any other identification of the
134891f2d0SKevin Coffman  * University of Michigan is included in any copy of any
144891f2d0SKevin Coffman  * portion of this software, then the disclaimer below must
154891f2d0SKevin Coffman  * also be included.
164891f2d0SKevin Coffman  *
174891f2d0SKevin Coffman  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
184891f2d0SKevin Coffman  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
194891f2d0SKevin Coffman  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
204891f2d0SKevin Coffman  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
214891f2d0SKevin Coffman  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
224891f2d0SKevin Coffman  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
234891f2d0SKevin Coffman  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
244891f2d0SKevin Coffman  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
254891f2d0SKevin Coffman  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
264891f2d0SKevin Coffman  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
274891f2d0SKevin Coffman  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
284891f2d0SKevin Coffman  * SUCH DAMAGES.
294891f2d0SKevin Coffman  */
304891f2d0SKevin Coffman 
314891f2d0SKevin Coffman /*
324891f2d0SKevin Coffman  * Copyright (C) 1998 by the FundsXpress, INC.
334891f2d0SKevin Coffman  *
344891f2d0SKevin Coffman  * All rights reserved.
354891f2d0SKevin Coffman  *
364891f2d0SKevin Coffman  * Export of this software from the United States of America may require
374891f2d0SKevin Coffman  * a specific license from the United States Government.  It is the
384891f2d0SKevin Coffman  * responsibility of any person or organization contemplating export to
394891f2d0SKevin Coffman  * obtain such a license before exporting.
404891f2d0SKevin Coffman  *
414891f2d0SKevin Coffman  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
424891f2d0SKevin Coffman  * distribute this software and its documentation for any purpose and
434891f2d0SKevin Coffman  * without fee is hereby granted, provided that the above copyright
444891f2d0SKevin Coffman  * notice appear in all copies and that both that copyright notice and
454891f2d0SKevin Coffman  * this permission notice appear in supporting documentation, and that
464891f2d0SKevin Coffman  * the name of FundsXpress. not be used in advertising or publicity pertaining
474891f2d0SKevin Coffman  * to distribution of the software without specific, written prior
484891f2d0SKevin Coffman  * permission.  FundsXpress makes no representations about the suitability of
494891f2d0SKevin Coffman  * this software for any purpose.  It is provided "as is" without express
504891f2d0SKevin Coffman  * or implied warranty.
514891f2d0SKevin Coffman  *
524891f2d0SKevin Coffman  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
534891f2d0SKevin Coffman  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
544891f2d0SKevin Coffman  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
554891f2d0SKevin Coffman  */
564891f2d0SKevin Coffman 
573b5cf20cSHerbert Xu #include <crypto/skcipher.h>
584891f2d0SKevin Coffman #include <linux/err.h>
594891f2d0SKevin Coffman #include <linux/types.h>
604891f2d0SKevin Coffman #include <linux/sunrpc/gss_krb5.h>
614891f2d0SKevin Coffman #include <linux/sunrpc/xdr.h>
62c692554bSLuis Henriques #include <linux/lcm.h>
63ae2e4d2bSChuck Lever #include <crypto/hash.h>
64*eebd8c2dSChuck Lever #include <kunit/visibility.h>
654891f2d0SKevin Coffman 
66d50b8152SChuck Lever #include "gss_krb5_internal.h"
67d50b8152SChuck Lever 
68f895b252SJeff Layton #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
694891f2d0SKevin Coffman # define RPCDBG_FACILITY        RPCDBG_AUTH
704891f2d0SKevin Coffman #endif
714891f2d0SKevin Coffman 
72*eebd8c2dSChuck Lever /**
73*eebd8c2dSChuck Lever  * krb5_nfold - n-fold function
74*eebd8c2dSChuck Lever  * @inbits: number of bits in @in
75*eebd8c2dSChuck Lever  * @in: buffer containing input to fold
76*eebd8c2dSChuck Lever  * @outbits: number of bits in the output buffer
77*eebd8c2dSChuck Lever  * @out: buffer to hold the result
78*eebd8c2dSChuck Lever  *
794891f2d0SKevin Coffman  * This is the n-fold function as described in rfc3961, sec 5.1
804891f2d0SKevin Coffman  * Taken from MIT Kerberos and modified.
814891f2d0SKevin Coffman  */
82*eebd8c2dSChuck Lever VISIBLE_IF_KUNIT
krb5_nfold(u32 inbits,const u8 * in,u32 outbits,u8 * out)83*eebd8c2dSChuck Lever void krb5_nfold(u32 inbits, const u8 *in, u32 outbits, u8 *out)
844891f2d0SKevin Coffman {
85c692554bSLuis Henriques 	unsigned long ulcm;
864891f2d0SKevin Coffman 	int byte, i, msbit;
874891f2d0SKevin Coffman 
884891f2d0SKevin Coffman 	/* the code below is more readable if I make these bytes
894891f2d0SKevin Coffman 	   instead of bits */
904891f2d0SKevin Coffman 
914891f2d0SKevin Coffman 	inbits >>= 3;
924891f2d0SKevin Coffman 	outbits >>= 3;
934891f2d0SKevin Coffman 
944891f2d0SKevin Coffman 	/* first compute lcm(n,k) */
95c692554bSLuis Henriques 	ulcm = lcm(inbits, outbits);
964891f2d0SKevin Coffman 
974891f2d0SKevin Coffman 	/* now do the real work */
984891f2d0SKevin Coffman 
994891f2d0SKevin Coffman 	memset(out, 0, outbits);
1004891f2d0SKevin Coffman 	byte = 0;
1014891f2d0SKevin Coffman 
1024891f2d0SKevin Coffman 	/* this will end up cycling through k lcm(k,n)/k times, which
1034891f2d0SKevin Coffman 	   is correct */
104c692554bSLuis Henriques 	for (i = ulcm-1; i >= 0; i--) {
1054891f2d0SKevin Coffman 		/* compute the msbit in k which gets added into this byte */
1064891f2d0SKevin Coffman 		msbit = (
1074891f2d0SKevin Coffman 			/* first, start with the msbit in the first,
1084891f2d0SKevin Coffman 			 * unrotated byte */
1094891f2d0SKevin Coffman 			 ((inbits << 3) - 1)
1104891f2d0SKevin Coffman 			 /* then, for each byte, shift to the right
1114891f2d0SKevin Coffman 			  * for each repetition */
1124891f2d0SKevin Coffman 			 + (((inbits << 3) + 13) * (i/inbits))
1134891f2d0SKevin Coffman 			 /* last, pick out the correct byte within
1144891f2d0SKevin Coffman 			  * that shifted repetition */
1154891f2d0SKevin Coffman 			 + ((inbits - (i % inbits)) << 3)
1164891f2d0SKevin Coffman 			 ) % (inbits << 3);
1174891f2d0SKevin Coffman 
1184891f2d0SKevin Coffman 		/* pull out the byte value itself */
1194891f2d0SKevin Coffman 		byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8)|
1204891f2d0SKevin Coffman 				  (in[((inbits) - (msbit >> 3)) % inbits]))
1214891f2d0SKevin Coffman 				 >> ((msbit & 7) + 1)) & 0xff;
1224891f2d0SKevin Coffman 
1234891f2d0SKevin Coffman 		/* do the addition */
1244891f2d0SKevin Coffman 		byte += out[i % outbits];
1254891f2d0SKevin Coffman 		out[i % outbits] = byte & 0xff;
1264891f2d0SKevin Coffman 
1274891f2d0SKevin Coffman 		/* keep around the carry bit, if any */
1284891f2d0SKevin Coffman 		byte >>= 8;
1294891f2d0SKevin Coffman 
1304891f2d0SKevin Coffman 	}
1314891f2d0SKevin Coffman 
1324891f2d0SKevin Coffman 	/* if there's a carry bit left over, add it back in */
1334891f2d0SKevin Coffman 	if (byte) {
1344891f2d0SKevin Coffman 		for (i = outbits - 1; i >= 0; i--) {
1354891f2d0SKevin Coffman 			/* do the addition */
1364891f2d0SKevin Coffman 			byte += out[i];
1374891f2d0SKevin Coffman 			out[i] = byte & 0xff;
1384891f2d0SKevin Coffman 
1394891f2d0SKevin Coffman 			/* keep around the carry bit, if any */
1404891f2d0SKevin Coffman 			byte >>= 8;
1414891f2d0SKevin Coffman 		}
1424891f2d0SKevin Coffman 	}
1434891f2d0SKevin Coffman }
144*eebd8c2dSChuck Lever EXPORT_SYMBOL_IF_KUNIT(krb5_nfold);
1454891f2d0SKevin Coffman 
1464891f2d0SKevin Coffman /*
1474891f2d0SKevin Coffman  * This is the DK (derive_key) function as described in rfc3961, sec 5.1
1484891f2d0SKevin Coffman  * Taken from MIT Kerberos and modified.
1494891f2d0SKevin Coffman  */
krb5_DK(const struct gss_krb5_enctype * gk5e,const struct xdr_netobj * inkey,u8 * rawkey,const struct xdr_netobj * in_constant,gfp_t gfp_mask)1502691a27dSChuck Lever static int krb5_DK(const struct gss_krb5_enctype *gk5e,
1512691a27dSChuck Lever 		   const struct xdr_netobj *inkey, u8 *rawkey,
1522691a27dSChuck Lever 		   const struct xdr_netobj *in_constant, gfp_t gfp_mask)
1534891f2d0SKevin Coffman {
1544891f2d0SKevin Coffman 	size_t blocksize, keybytes, keylength, n;
1552691a27dSChuck Lever 	unsigned char *inblockdata, *outblockdata;
1564891f2d0SKevin Coffman 	struct xdr_netobj inblock, outblock;
157e9e575b8SKees Cook 	struct crypto_sync_skcipher *cipher;
1582691a27dSChuck Lever 	int ret = -EINVAL;
1594891f2d0SKevin Coffman 
1604891f2d0SKevin Coffman 	keybytes = gk5e->keybytes;
1614891f2d0SKevin Coffman 	keylength = gk5e->keylength;
1624891f2d0SKevin Coffman 
1632691a27dSChuck Lever 	if (inkey->len != keylength)
1644891f2d0SKevin Coffman 		goto err_return;
1654891f2d0SKevin Coffman 
166e9e575b8SKees Cook 	cipher = crypto_alloc_sync_skcipher(gk5e->encrypt_name, 0, 0);
1674891f2d0SKevin Coffman 	if (IS_ERR(cipher))
1684891f2d0SKevin Coffman 		goto err_return;
169f03640a1SChuck Lever 	blocksize = crypto_sync_skcipher_blocksize(cipher);
170e9e575b8SKees Cook 	if (crypto_sync_skcipher_setkey(cipher, inkey->data, inkey->len))
1714891f2d0SKevin Coffman 		goto err_return;
1724891f2d0SKevin Coffman 
1732691a27dSChuck Lever 	ret = -ENOMEM;
1741f4c86c0STrond Myklebust 	inblockdata = kmalloc(blocksize, gfp_mask);
1754891f2d0SKevin Coffman 	if (inblockdata == NULL)
1764891f2d0SKevin Coffman 		goto err_free_cipher;
1774891f2d0SKevin Coffman 
1781f4c86c0STrond Myklebust 	outblockdata = kmalloc(blocksize, gfp_mask);
1794891f2d0SKevin Coffman 	if (outblockdata == NULL)
1804891f2d0SKevin Coffman 		goto err_free_in;
1814891f2d0SKevin Coffman 
1824891f2d0SKevin Coffman 	inblock.data = (char *) inblockdata;
1834891f2d0SKevin Coffman 	inblock.len = blocksize;
1844891f2d0SKevin Coffman 
1854891f2d0SKevin Coffman 	outblock.data = (char *) outblockdata;
1864891f2d0SKevin Coffman 	outblock.len = blocksize;
1874891f2d0SKevin Coffman 
1884891f2d0SKevin Coffman 	/* initialize the input block */
1894891f2d0SKevin Coffman 
1904891f2d0SKevin Coffman 	if (in_constant->len == inblock.len) {
1914891f2d0SKevin Coffman 		memcpy(inblock.data, in_constant->data, inblock.len);
1924891f2d0SKevin Coffman 	} else {
1934891f2d0SKevin Coffman 		krb5_nfold(in_constant->len * 8, in_constant->data,
1944891f2d0SKevin Coffman 			   inblock.len * 8, inblock.data);
1954891f2d0SKevin Coffman 	}
1964891f2d0SKevin Coffman 
1974891f2d0SKevin Coffman 	/* loop encrypting the blocks until enough key bytes are generated */
1984891f2d0SKevin Coffman 
1994891f2d0SKevin Coffman 	n = 0;
2004891f2d0SKevin Coffman 	while (n < keybytes) {
201d50b8152SChuck Lever 		krb5_encrypt(cipher, NULL, inblock.data, outblock.data,
202d50b8152SChuck Lever 			     inblock.len);
2034891f2d0SKevin Coffman 
2044891f2d0SKevin Coffman 		if ((keybytes - n) <= outblock.len) {
2054891f2d0SKevin Coffman 			memcpy(rawkey + n, outblock.data, (keybytes - n));
2064891f2d0SKevin Coffman 			break;
2074891f2d0SKevin Coffman 		}
2084891f2d0SKevin Coffman 
2094891f2d0SKevin Coffman 		memcpy(rawkey + n, outblock.data, outblock.len);
2104891f2d0SKevin Coffman 		memcpy(inblock.data, outblock.data, outblock.len);
2114891f2d0SKevin Coffman 		n += outblock.len;
2124891f2d0SKevin Coffman 	}
2134891f2d0SKevin Coffman 
2144891f2d0SKevin Coffman 	ret = 0;
2154891f2d0SKevin Coffman 
216453431a5SWaiman Long 	kfree_sensitive(outblockdata);
2174891f2d0SKevin Coffman err_free_in:
218453431a5SWaiman Long 	kfree_sensitive(inblockdata);
2194891f2d0SKevin Coffman err_free_cipher:
220e9e575b8SKees Cook 	crypto_free_sync_skcipher(cipher);
2214891f2d0SKevin Coffman err_return:
2224891f2d0SKevin Coffman 	return ret;
2234891f2d0SKevin Coffman }
224958142e9SKevin Coffman 
2252691a27dSChuck Lever /*
2262691a27dSChuck Lever  * This is the identity function, with some sanity checking.
2272691a27dSChuck Lever  */
krb5_random_to_key_v2(const struct gss_krb5_enctype * gk5e,struct xdr_netobj * randombits,struct xdr_netobj * key)2282691a27dSChuck Lever static int krb5_random_to_key_v2(const struct gss_krb5_enctype *gk5e,
229934a95aaSKevin Coffman 				 struct xdr_netobj *randombits,
230934a95aaSKevin Coffman 				 struct xdr_netobj *key)
231934a95aaSKevin Coffman {
2322691a27dSChuck Lever 	int ret = -EINVAL;
233934a95aaSKevin Coffman 
234934a95aaSKevin Coffman 	if (key->len != 16 && key->len != 32) {
235934a95aaSKevin Coffman 		dprintk("%s: key->len is %d\n", __func__, key->len);
236934a95aaSKevin Coffman 		goto err_out;
237934a95aaSKevin Coffman 	}
238934a95aaSKevin Coffman 	if (randombits->len != 16 && randombits->len != 32) {
239934a95aaSKevin Coffman 		dprintk("%s: randombits->len is %d\n",
240934a95aaSKevin Coffman 			__func__, randombits->len);
241934a95aaSKevin Coffman 		goto err_out;
242934a95aaSKevin Coffman 	}
243934a95aaSKevin Coffman 	if (randombits->len != key->len) {
244934a95aaSKevin Coffman 		dprintk("%s: randombits->len is %d, key->len is %d\n",
245934a95aaSKevin Coffman 			__func__, randombits->len, key->len);
246934a95aaSKevin Coffman 		goto err_out;
247934a95aaSKevin Coffman 	}
248934a95aaSKevin Coffman 	memcpy(key->data, randombits->data, key->len);
249934a95aaSKevin Coffman 	ret = 0;
250934a95aaSKevin Coffman err_out:
251934a95aaSKevin Coffman 	return ret;
252934a95aaSKevin Coffman }
2532691a27dSChuck Lever 
2542691a27dSChuck Lever /**
2552691a27dSChuck Lever  * krb5_derive_key_v2 - Derive a subkey for an RFC 3962 enctype
2562691a27dSChuck Lever  * @gk5e: Kerberos 5 enctype profile
2572691a27dSChuck Lever  * @inkey: base protocol key
2582691a27dSChuck Lever  * @outkey: OUT: derived key
2592691a27dSChuck Lever  * @label: subkey usage label
2602691a27dSChuck Lever  * @gfp_mask: memory allocation control flags
2612691a27dSChuck Lever  *
2622691a27dSChuck Lever  * Caller sets @outkey->len to the desired length of the derived key.
2632691a27dSChuck Lever  *
2642691a27dSChuck Lever  * On success, returns 0 and fills in @outkey. A negative errno value
2652691a27dSChuck Lever  * is returned on failure.
2662691a27dSChuck Lever  */
krb5_derive_key_v2(const struct gss_krb5_enctype * gk5e,const struct xdr_netobj * inkey,struct xdr_netobj * outkey,const struct xdr_netobj * label,gfp_t gfp_mask)2672691a27dSChuck Lever int krb5_derive_key_v2(const struct gss_krb5_enctype *gk5e,
2682691a27dSChuck Lever 		       const struct xdr_netobj *inkey,
2692691a27dSChuck Lever 		       struct xdr_netobj *outkey,
2702691a27dSChuck Lever 		       const struct xdr_netobj *label,
2712691a27dSChuck Lever 		       gfp_t gfp_mask)
2722691a27dSChuck Lever {
2732691a27dSChuck Lever 	struct xdr_netobj inblock;
2742691a27dSChuck Lever 	int ret;
2752691a27dSChuck Lever 
2762691a27dSChuck Lever 	inblock.len = gk5e->keybytes;
2772691a27dSChuck Lever 	inblock.data = kmalloc(inblock.len, gfp_mask);
2782691a27dSChuck Lever 	if (!inblock.data)
2792691a27dSChuck Lever 		return -ENOMEM;
2802691a27dSChuck Lever 
2812691a27dSChuck Lever 	ret = krb5_DK(gk5e, inkey, inblock.data, label, gfp_mask);
2822691a27dSChuck Lever 	if (!ret)
2832691a27dSChuck Lever 		ret = krb5_random_to_key_v2(gk5e, &inblock, outkey);
2842691a27dSChuck Lever 
2852691a27dSChuck Lever 	kfree_sensitive(inblock.data);
2862691a27dSChuck Lever 	return ret;
2872691a27dSChuck Lever }
288ae2e4d2bSChuck Lever 
289ae2e4d2bSChuck Lever /*
29045b4ef46SChuck Lever  * K(i) = CMAC(key, K(i-1) | i | constant | 0x00 | k)
29145b4ef46SChuck Lever  *
29245b4ef46SChuck Lever  *    i: A block counter is used with a length of 4 bytes, represented
29345b4ef46SChuck Lever  *       in big-endian order.
29445b4ef46SChuck Lever  *
29545b4ef46SChuck Lever  *    constant: The label input to the KDF is the usage constant supplied
29645b4ef46SChuck Lever  *              to the key derivation function
29745b4ef46SChuck Lever  *
29845b4ef46SChuck Lever  *    k: The length of the output key in bits, represented as a 4-byte
29945b4ef46SChuck Lever  *       string in big-endian order.
30045b4ef46SChuck Lever  *
30145b4ef46SChuck Lever  * Caller fills in K(i-1) in @step, and receives the result K(i)
30245b4ef46SChuck Lever  * in the same buffer.
30345b4ef46SChuck Lever  */
30445b4ef46SChuck Lever static int
krb5_cmac_Ki(struct crypto_shash * tfm,const struct xdr_netobj * constant,u32 outlen,u32 count,struct xdr_netobj * step)30545b4ef46SChuck Lever krb5_cmac_Ki(struct crypto_shash *tfm, const struct xdr_netobj *constant,
30645b4ef46SChuck Lever 	     u32 outlen, u32 count, struct xdr_netobj *step)
30745b4ef46SChuck Lever {
30845b4ef46SChuck Lever 	__be32 k = cpu_to_be32(outlen * 8);
30945b4ef46SChuck Lever 	SHASH_DESC_ON_STACK(desc, tfm);
31045b4ef46SChuck Lever 	__be32 i = cpu_to_be32(count);
31145b4ef46SChuck Lever 	u8 zero = 0;
31245b4ef46SChuck Lever 	int ret;
31345b4ef46SChuck Lever 
31445b4ef46SChuck Lever 	desc->tfm = tfm;
31545b4ef46SChuck Lever 	ret = crypto_shash_init(desc);
31645b4ef46SChuck Lever 	if (ret)
31745b4ef46SChuck Lever 		goto out_err;
31845b4ef46SChuck Lever 
31945b4ef46SChuck Lever 	ret = crypto_shash_update(desc, step->data, step->len);
32045b4ef46SChuck Lever 	if (ret)
32145b4ef46SChuck Lever 		goto out_err;
32245b4ef46SChuck Lever 	ret = crypto_shash_update(desc, (u8 *)&i, sizeof(i));
32345b4ef46SChuck Lever 	if (ret)
32445b4ef46SChuck Lever 		goto out_err;
32545b4ef46SChuck Lever 	ret = crypto_shash_update(desc, constant->data, constant->len);
32645b4ef46SChuck Lever 	if (ret)
32745b4ef46SChuck Lever 		goto out_err;
32845b4ef46SChuck Lever 	ret = crypto_shash_update(desc, &zero, sizeof(zero));
32945b4ef46SChuck Lever 	if (ret)
33045b4ef46SChuck Lever 		goto out_err;
33145b4ef46SChuck Lever 	ret = crypto_shash_update(desc, (u8 *)&k, sizeof(k));
33245b4ef46SChuck Lever 	if (ret)
33345b4ef46SChuck Lever 		goto out_err;
33445b4ef46SChuck Lever 	ret = crypto_shash_final(desc, step->data);
33545b4ef46SChuck Lever 	if (ret)
33645b4ef46SChuck Lever 		goto out_err;
33745b4ef46SChuck Lever 
33845b4ef46SChuck Lever out_err:
33945b4ef46SChuck Lever 	shash_desc_zero(desc);
34045b4ef46SChuck Lever 	return ret;
34145b4ef46SChuck Lever }
34245b4ef46SChuck Lever 
34345b4ef46SChuck Lever /**
34445b4ef46SChuck Lever  * krb5_kdf_feedback_cmac - Derive a subkey for a Camellia/CMAC-based enctype
34545b4ef46SChuck Lever  * @gk5e: Kerberos 5 enctype parameters
34645b4ef46SChuck Lever  * @inkey: base protocol key
34745b4ef46SChuck Lever  * @outkey: OUT: derived key
34845b4ef46SChuck Lever  * @constant: subkey usage label
34945b4ef46SChuck Lever  * @gfp_mask: memory allocation control flags
35045b4ef46SChuck Lever  *
35145b4ef46SChuck Lever  * RFC 6803 Section 3:
35245b4ef46SChuck Lever  *
35345b4ef46SChuck Lever  * "We use a key derivation function from the family specified in
35445b4ef46SChuck Lever  *  [SP800-108], Section 5.2, 'KDF in Feedback Mode'."
35545b4ef46SChuck Lever  *
35645b4ef46SChuck Lever  *	n = ceiling(k / 128)
35745b4ef46SChuck Lever  *	K(0) = zeros
35845b4ef46SChuck Lever  *	K(i) = CMAC(key, K(i-1) | i | constant | 0x00 | k)
35945b4ef46SChuck Lever  *	DR(key, constant) = k-truncate(K(1) | K(2) | ... | K(n))
36045b4ef46SChuck Lever  *	KDF-FEEDBACK-CMAC(key, constant) = random-to-key(DR(key, constant))
36145b4ef46SChuck Lever  *
36245b4ef46SChuck Lever  * Caller sets @outkey->len to the desired length of the derived key (k).
36345b4ef46SChuck Lever  *
36445b4ef46SChuck Lever  * On success, returns 0 and fills in @outkey. A negative errno value
36545b4ef46SChuck Lever  * is returned on failure.
36645b4ef46SChuck Lever  */
36745b4ef46SChuck Lever int
krb5_kdf_feedback_cmac(const struct gss_krb5_enctype * gk5e,const struct xdr_netobj * inkey,struct xdr_netobj * outkey,const struct xdr_netobj * constant,gfp_t gfp_mask)36845b4ef46SChuck Lever krb5_kdf_feedback_cmac(const struct gss_krb5_enctype *gk5e,
36945b4ef46SChuck Lever 		       const struct xdr_netobj *inkey,
37045b4ef46SChuck Lever 		       struct xdr_netobj *outkey,
37145b4ef46SChuck Lever 		       const struct xdr_netobj *constant,
37245b4ef46SChuck Lever 		       gfp_t gfp_mask)
37345b4ef46SChuck Lever {
37445b4ef46SChuck Lever 	struct xdr_netobj step = { .data = NULL };
37545b4ef46SChuck Lever 	struct xdr_netobj DR = { .data = NULL };
37645b4ef46SChuck Lever 	unsigned int blocksize, offset;
37745b4ef46SChuck Lever 	struct crypto_shash *tfm;
37845b4ef46SChuck Lever 	int n, count, ret;
37945b4ef46SChuck Lever 
38045b4ef46SChuck Lever 	/*
38145b4ef46SChuck Lever 	 * This implementation assumes the CMAC used for an enctype's
38245b4ef46SChuck Lever 	 * key derivation is the same as the CMAC used for its
38345b4ef46SChuck Lever 	 * checksumming. This happens to be true for enctypes that
38445b4ef46SChuck Lever 	 * are currently supported by this implementation.
38545b4ef46SChuck Lever 	 */
38645b4ef46SChuck Lever 	tfm = crypto_alloc_shash(gk5e->cksum_name, 0, 0);
38745b4ef46SChuck Lever 	if (IS_ERR(tfm)) {
38845b4ef46SChuck Lever 		ret = PTR_ERR(tfm);
38945b4ef46SChuck Lever 		goto out;
39045b4ef46SChuck Lever 	}
39145b4ef46SChuck Lever 	ret = crypto_shash_setkey(tfm, inkey->data, inkey->len);
39245b4ef46SChuck Lever 	if (ret)
39345b4ef46SChuck Lever 		goto out_free_tfm;
39445b4ef46SChuck Lever 
39545b4ef46SChuck Lever 	blocksize = crypto_shash_digestsize(tfm);
39645b4ef46SChuck Lever 	n = (outkey->len + blocksize - 1) / blocksize;
39745b4ef46SChuck Lever 
39845b4ef46SChuck Lever 	/* K(0) is all zeroes */
39945b4ef46SChuck Lever 	ret = -ENOMEM;
40045b4ef46SChuck Lever 	step.len = blocksize;
40145b4ef46SChuck Lever 	step.data = kzalloc(step.len, gfp_mask);
40245b4ef46SChuck Lever 	if (!step.data)
40345b4ef46SChuck Lever 		goto out_free_tfm;
40445b4ef46SChuck Lever 
40545b4ef46SChuck Lever 	DR.len = blocksize * n;
40645b4ef46SChuck Lever 	DR.data = kmalloc(DR.len, gfp_mask);
40745b4ef46SChuck Lever 	if (!DR.data)
40845b4ef46SChuck Lever 		goto out_free_tfm;
40945b4ef46SChuck Lever 
41045b4ef46SChuck Lever 	/* XXX: Does not handle partial-block key sizes */
41145b4ef46SChuck Lever 	for (offset = 0, count = 1; count <= n; count++) {
41245b4ef46SChuck Lever 		ret = krb5_cmac_Ki(tfm, constant, outkey->len, count, &step);
41345b4ef46SChuck Lever 		if (ret)
41445b4ef46SChuck Lever 			goto out_free_tfm;
41545b4ef46SChuck Lever 
41645b4ef46SChuck Lever 		memcpy(DR.data + offset, step.data, blocksize);
41745b4ef46SChuck Lever 		offset += blocksize;
41845b4ef46SChuck Lever 	}
41945b4ef46SChuck Lever 
42045b4ef46SChuck Lever 	/* k-truncate and random-to-key */
42145b4ef46SChuck Lever 	memcpy(outkey->data, DR.data, outkey->len);
42245b4ef46SChuck Lever 	ret = 0;
42345b4ef46SChuck Lever 
42445b4ef46SChuck Lever out_free_tfm:
42545b4ef46SChuck Lever 	crypto_free_shash(tfm);
42645b4ef46SChuck Lever out:
42745b4ef46SChuck Lever 	kfree_sensitive(step.data);
42845b4ef46SChuck Lever 	kfree_sensitive(DR.data);
42945b4ef46SChuck Lever 	return ret;
43045b4ef46SChuck Lever }
43145b4ef46SChuck Lever 
43245b4ef46SChuck Lever /*
433ae2e4d2bSChuck Lever  * K1 = HMAC-SHA(key, 0x00000001 | label | 0x00 | k)
434ae2e4d2bSChuck Lever  *
435ae2e4d2bSChuck Lever  *    key: The source of entropy from which subsequent keys are derived.
436ae2e4d2bSChuck Lever  *
437ae2e4d2bSChuck Lever  *    label: An octet string describing the intended usage of the
438ae2e4d2bSChuck Lever  *    derived key.
439ae2e4d2bSChuck Lever  *
440ae2e4d2bSChuck Lever  *    k: Length in bits of the key to be outputted, expressed in
441ae2e4d2bSChuck Lever  *    big-endian binary representation in 4 bytes.
442ae2e4d2bSChuck Lever  */
443ae2e4d2bSChuck Lever static int
krb5_hmac_K1(struct crypto_shash * tfm,const struct xdr_netobj * label,u32 outlen,struct xdr_netobj * K1)444ae2e4d2bSChuck Lever krb5_hmac_K1(struct crypto_shash *tfm, const struct xdr_netobj *label,
445ae2e4d2bSChuck Lever 	     u32 outlen, struct xdr_netobj *K1)
446ae2e4d2bSChuck Lever {
447ae2e4d2bSChuck Lever 	__be32 k = cpu_to_be32(outlen * 8);
448ae2e4d2bSChuck Lever 	SHASH_DESC_ON_STACK(desc, tfm);
449ae2e4d2bSChuck Lever 	__be32 one = cpu_to_be32(1);
450ae2e4d2bSChuck Lever 	u8 zero = 0;
451ae2e4d2bSChuck Lever 	int ret;
452ae2e4d2bSChuck Lever 
453ae2e4d2bSChuck Lever 	desc->tfm = tfm;
454ae2e4d2bSChuck Lever 	ret = crypto_shash_init(desc);
455ae2e4d2bSChuck Lever 	if (ret)
456ae2e4d2bSChuck Lever 		goto out_err;
457ae2e4d2bSChuck Lever 	ret = crypto_shash_update(desc, (u8 *)&one, sizeof(one));
458ae2e4d2bSChuck Lever 	if (ret)
459ae2e4d2bSChuck Lever 		goto out_err;
460ae2e4d2bSChuck Lever 	ret = crypto_shash_update(desc, label->data, label->len);
461ae2e4d2bSChuck Lever 	if (ret)
462ae2e4d2bSChuck Lever 		goto out_err;
463ae2e4d2bSChuck Lever 	ret = crypto_shash_update(desc, &zero, sizeof(zero));
464ae2e4d2bSChuck Lever 	if (ret)
465ae2e4d2bSChuck Lever 		goto out_err;
466ae2e4d2bSChuck Lever 	ret = crypto_shash_update(desc, (u8 *)&k, sizeof(k));
467ae2e4d2bSChuck Lever 	if (ret)
468ae2e4d2bSChuck Lever 		goto out_err;
469ae2e4d2bSChuck Lever 	ret = crypto_shash_final(desc, K1->data);
470ae2e4d2bSChuck Lever 	if (ret)
471ae2e4d2bSChuck Lever 		goto out_err;
472ae2e4d2bSChuck Lever 
473ae2e4d2bSChuck Lever out_err:
474ae2e4d2bSChuck Lever 	shash_desc_zero(desc);
475ae2e4d2bSChuck Lever 	return ret;
476ae2e4d2bSChuck Lever }
477ae2e4d2bSChuck Lever 
478ae2e4d2bSChuck Lever /**
479ae2e4d2bSChuck Lever  * krb5_kdf_hmac_sha2 - Derive a subkey for an AES/SHA2-based enctype
480ae2e4d2bSChuck Lever  * @gk5e: Kerberos 5 enctype policy parameters
481ae2e4d2bSChuck Lever  * @inkey: base protocol key
482ae2e4d2bSChuck Lever  * @outkey: OUT: derived key
483ae2e4d2bSChuck Lever  * @label: subkey usage label
484ae2e4d2bSChuck Lever  * @gfp_mask: memory allocation control flags
485ae2e4d2bSChuck Lever  *
486ae2e4d2bSChuck Lever  * RFC 8009 Section 3:
487ae2e4d2bSChuck Lever  *
488ae2e4d2bSChuck Lever  *  "We use a key derivation function from Section 5.1 of [SP800-108],
489ae2e4d2bSChuck Lever  *   which uses the HMAC algorithm as the PRF."
490ae2e4d2bSChuck Lever  *
491ae2e4d2bSChuck Lever  *	function KDF-HMAC-SHA2(key, label, [context,] k):
492ae2e4d2bSChuck Lever  *		k-truncate(K1)
493ae2e4d2bSChuck Lever  *
494ae2e4d2bSChuck Lever  * Caller sets @outkey->len to the desired length of the derived key.
495ae2e4d2bSChuck Lever  *
496ae2e4d2bSChuck Lever  * On success, returns 0 and fills in @outkey. A negative errno value
497ae2e4d2bSChuck Lever  * is returned on failure.
498ae2e4d2bSChuck Lever  */
499ae2e4d2bSChuck Lever int
krb5_kdf_hmac_sha2(const struct gss_krb5_enctype * gk5e,const struct xdr_netobj * inkey,struct xdr_netobj * outkey,const struct xdr_netobj * label,gfp_t gfp_mask)500ae2e4d2bSChuck Lever krb5_kdf_hmac_sha2(const struct gss_krb5_enctype *gk5e,
501ae2e4d2bSChuck Lever 		   const struct xdr_netobj *inkey,
502ae2e4d2bSChuck Lever 		   struct xdr_netobj *outkey,
503ae2e4d2bSChuck Lever 		   const struct xdr_netobj *label,
504ae2e4d2bSChuck Lever 		   gfp_t gfp_mask)
505ae2e4d2bSChuck Lever {
506ae2e4d2bSChuck Lever 	struct crypto_shash *tfm;
507ae2e4d2bSChuck Lever 	struct xdr_netobj K1 = {
508ae2e4d2bSChuck Lever 		.data = NULL,
509ae2e4d2bSChuck Lever 	};
510ae2e4d2bSChuck Lever 	int ret;
511ae2e4d2bSChuck Lever 
512ae2e4d2bSChuck Lever 	/*
513ae2e4d2bSChuck Lever 	 * This implementation assumes the HMAC used for an enctype's
514ae2e4d2bSChuck Lever 	 * key derivation is the same as the HMAC used for its
515ae2e4d2bSChuck Lever 	 * checksumming. This happens to be true for enctypes that
516ae2e4d2bSChuck Lever 	 * are currently supported by this implementation.
517ae2e4d2bSChuck Lever 	 */
518ae2e4d2bSChuck Lever 	tfm = crypto_alloc_shash(gk5e->cksum_name, 0, 0);
519ae2e4d2bSChuck Lever 	if (IS_ERR(tfm)) {
520ae2e4d2bSChuck Lever 		ret = PTR_ERR(tfm);
521ae2e4d2bSChuck Lever 		goto out;
522ae2e4d2bSChuck Lever 	}
523ae2e4d2bSChuck Lever 	ret = crypto_shash_setkey(tfm, inkey->data, inkey->len);
524ae2e4d2bSChuck Lever 	if (ret)
525ae2e4d2bSChuck Lever 		goto out_free_tfm;
526ae2e4d2bSChuck Lever 
527ae2e4d2bSChuck Lever 	K1.len = crypto_shash_digestsize(tfm);
528ae2e4d2bSChuck Lever 	K1.data = kmalloc(K1.len, gfp_mask);
529ae2e4d2bSChuck Lever 	if (!K1.data) {
530ae2e4d2bSChuck Lever 		ret = -ENOMEM;
531ae2e4d2bSChuck Lever 		goto out_free_tfm;
532ae2e4d2bSChuck Lever 	}
533ae2e4d2bSChuck Lever 
534ae2e4d2bSChuck Lever 	ret = krb5_hmac_K1(tfm, label, outkey->len, &K1);
535ae2e4d2bSChuck Lever 	if (ret)
536ae2e4d2bSChuck Lever 		goto out_free_tfm;
537ae2e4d2bSChuck Lever 
538ae2e4d2bSChuck Lever 	/* k-truncate and random-to-key */
539ae2e4d2bSChuck Lever 	memcpy(outkey->data, K1.data, outkey->len);
540ae2e4d2bSChuck Lever 
541ae2e4d2bSChuck Lever out_free_tfm:
542ae2e4d2bSChuck Lever 	kfree_sensitive(K1.data);
543ae2e4d2bSChuck Lever 	crypto_free_shash(tfm);
544ae2e4d2bSChuck Lever out:
545ae2e4d2bSChuck Lever 	return ret;
546ae2e4d2bSChuck Lever }
547