18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * COPYRIGHT (c) 2008
38c2ecf20Sopenharmony_ci * The Regents of the University of Michigan
48c2ecf20Sopenharmony_ci * ALL RIGHTS RESERVED
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Permission is granted to use, copy, create derivative works
78c2ecf20Sopenharmony_ci * and redistribute this software and such derivative works
88c2ecf20Sopenharmony_ci * for any purpose, so long as the name of The University of
98c2ecf20Sopenharmony_ci * Michigan is not used in any advertising or publicity
108c2ecf20Sopenharmony_ci * pertaining to the use of distribution of this software
118c2ecf20Sopenharmony_ci * without specific, written prior authorization.  If the
128c2ecf20Sopenharmony_ci * above copyright notice or any other identification of the
138c2ecf20Sopenharmony_ci * University of Michigan is included in any copy of any
148c2ecf20Sopenharmony_ci * portion of this software, then the disclaimer below must
158c2ecf20Sopenharmony_ci * also be included.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
188c2ecf20Sopenharmony_ci * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
198c2ecf20Sopenharmony_ci * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
208c2ecf20Sopenharmony_ci * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
218c2ecf20Sopenharmony_ci * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
228c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
238c2ecf20Sopenharmony_ci * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
248c2ecf20Sopenharmony_ci * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
258c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
268c2ecf20Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
278c2ecf20Sopenharmony_ci * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
288c2ecf20Sopenharmony_ci * SUCH DAMAGES.
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/*
328c2ecf20Sopenharmony_ci * Copyright (C) 1998 by the FundsXpress, INC.
338c2ecf20Sopenharmony_ci *
348c2ecf20Sopenharmony_ci * All rights reserved.
358c2ecf20Sopenharmony_ci *
368c2ecf20Sopenharmony_ci * Export of this software from the United States of America may require
378c2ecf20Sopenharmony_ci * a specific license from the United States Government.  It is the
388c2ecf20Sopenharmony_ci * responsibility of any person or organization contemplating export to
398c2ecf20Sopenharmony_ci * obtain such a license before exporting.
408c2ecf20Sopenharmony_ci *
418c2ecf20Sopenharmony_ci * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
428c2ecf20Sopenharmony_ci * distribute this software and its documentation for any purpose and
438c2ecf20Sopenharmony_ci * without fee is hereby granted, provided that the above copyright
448c2ecf20Sopenharmony_ci * notice appear in all copies and that both that copyright notice and
458c2ecf20Sopenharmony_ci * this permission notice appear in supporting documentation, and that
468c2ecf20Sopenharmony_ci * the name of FundsXpress. not be used in advertising or publicity pertaining
478c2ecf20Sopenharmony_ci * to distribution of the software without specific, written prior
488c2ecf20Sopenharmony_ci * permission.  FundsXpress makes no representations about the suitability of
498c2ecf20Sopenharmony_ci * this software for any purpose.  It is provided "as is" without express
508c2ecf20Sopenharmony_ci * or implied warranty.
518c2ecf20Sopenharmony_ci *
528c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
538c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
548c2ecf20Sopenharmony_ci * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
558c2ecf20Sopenharmony_ci */
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#include <crypto/skcipher.h>
588c2ecf20Sopenharmony_ci#include <linux/err.h>
598c2ecf20Sopenharmony_ci#include <linux/types.h>
608c2ecf20Sopenharmony_ci#include <linux/sunrpc/gss_krb5.h>
618c2ecf20Sopenharmony_ci#include <linux/sunrpc/xdr.h>
628c2ecf20Sopenharmony_ci#include <linux/lcm.h>
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
658c2ecf20Sopenharmony_ci# define RPCDBG_FACILITY        RPCDBG_AUTH
668c2ecf20Sopenharmony_ci#endif
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/*
698c2ecf20Sopenharmony_ci * This is the n-fold function as described in rfc3961, sec 5.1
708c2ecf20Sopenharmony_ci * Taken from MIT Kerberos and modified.
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic void krb5_nfold(u32 inbits, const u8 *in,
748c2ecf20Sopenharmony_ci		       u32 outbits, u8 *out)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	unsigned long ulcm;
778c2ecf20Sopenharmony_ci	int byte, i, msbit;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	/* the code below is more readable if I make these bytes
808c2ecf20Sopenharmony_ci	   instead of bits */
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	inbits >>= 3;
838c2ecf20Sopenharmony_ci	outbits >>= 3;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/* first compute lcm(n,k) */
868c2ecf20Sopenharmony_ci	ulcm = lcm(inbits, outbits);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	/* now do the real work */
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	memset(out, 0, outbits);
918c2ecf20Sopenharmony_ci	byte = 0;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	/* this will end up cycling through k lcm(k,n)/k times, which
948c2ecf20Sopenharmony_ci	   is correct */
958c2ecf20Sopenharmony_ci	for (i = ulcm-1; i >= 0; i--) {
968c2ecf20Sopenharmony_ci		/* compute the msbit in k which gets added into this byte */
978c2ecf20Sopenharmony_ci		msbit = (
988c2ecf20Sopenharmony_ci			/* first, start with the msbit in the first,
998c2ecf20Sopenharmony_ci			 * unrotated byte */
1008c2ecf20Sopenharmony_ci			 ((inbits << 3) - 1)
1018c2ecf20Sopenharmony_ci			 /* then, for each byte, shift to the right
1028c2ecf20Sopenharmony_ci			  * for each repetition */
1038c2ecf20Sopenharmony_ci			 + (((inbits << 3) + 13) * (i/inbits))
1048c2ecf20Sopenharmony_ci			 /* last, pick out the correct byte within
1058c2ecf20Sopenharmony_ci			  * that shifted repetition */
1068c2ecf20Sopenharmony_ci			 + ((inbits - (i % inbits)) << 3)
1078c2ecf20Sopenharmony_ci			 ) % (inbits << 3);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci		/* pull out the byte value itself */
1108c2ecf20Sopenharmony_ci		byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8)|
1118c2ecf20Sopenharmony_ci				  (in[((inbits) - (msbit >> 3)) % inbits]))
1128c2ecf20Sopenharmony_ci				 >> ((msbit & 7) + 1)) & 0xff;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci		/* do the addition */
1158c2ecf20Sopenharmony_ci		byte += out[i % outbits];
1168c2ecf20Sopenharmony_ci		out[i % outbits] = byte & 0xff;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		/* keep around the carry bit, if any */
1198c2ecf20Sopenharmony_ci		byte >>= 8;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	/* if there's a carry bit left over, add it back in */
1248c2ecf20Sopenharmony_ci	if (byte) {
1258c2ecf20Sopenharmony_ci		for (i = outbits - 1; i >= 0; i--) {
1268c2ecf20Sopenharmony_ci			/* do the addition */
1278c2ecf20Sopenharmony_ci			byte += out[i];
1288c2ecf20Sopenharmony_ci			out[i] = byte & 0xff;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci			/* keep around the carry bit, if any */
1318c2ecf20Sopenharmony_ci			byte >>= 8;
1328c2ecf20Sopenharmony_ci		}
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci/*
1378c2ecf20Sopenharmony_ci * This is the DK (derive_key) function as described in rfc3961, sec 5.1
1388c2ecf20Sopenharmony_ci * Taken from MIT Kerberos and modified.
1398c2ecf20Sopenharmony_ci */
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ciu32 krb5_derive_key(const struct gss_krb5_enctype *gk5e,
1428c2ecf20Sopenharmony_ci		    const struct xdr_netobj *inkey,
1438c2ecf20Sopenharmony_ci		    struct xdr_netobj *outkey,
1448c2ecf20Sopenharmony_ci		    const struct xdr_netobj *in_constant,
1458c2ecf20Sopenharmony_ci		    gfp_t gfp_mask)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	size_t blocksize, keybytes, keylength, n;
1488c2ecf20Sopenharmony_ci	unsigned char *inblockdata, *outblockdata, *rawkey;
1498c2ecf20Sopenharmony_ci	struct xdr_netobj inblock, outblock;
1508c2ecf20Sopenharmony_ci	struct crypto_sync_skcipher *cipher;
1518c2ecf20Sopenharmony_ci	u32 ret = EINVAL;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	blocksize = gk5e->blocksize;
1548c2ecf20Sopenharmony_ci	keybytes = gk5e->keybytes;
1558c2ecf20Sopenharmony_ci	keylength = gk5e->keylength;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if ((inkey->len != keylength) || (outkey->len != keylength))
1588c2ecf20Sopenharmony_ci		goto err_return;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	cipher = crypto_alloc_sync_skcipher(gk5e->encrypt_name, 0, 0);
1618c2ecf20Sopenharmony_ci	if (IS_ERR(cipher))
1628c2ecf20Sopenharmony_ci		goto err_return;
1638c2ecf20Sopenharmony_ci	if (crypto_sync_skcipher_setkey(cipher, inkey->data, inkey->len))
1648c2ecf20Sopenharmony_ci		goto err_return;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/* allocate and set up buffers */
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	ret = ENOMEM;
1698c2ecf20Sopenharmony_ci	inblockdata = kmalloc(blocksize, gfp_mask);
1708c2ecf20Sopenharmony_ci	if (inblockdata == NULL)
1718c2ecf20Sopenharmony_ci		goto err_free_cipher;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	outblockdata = kmalloc(blocksize, gfp_mask);
1748c2ecf20Sopenharmony_ci	if (outblockdata == NULL)
1758c2ecf20Sopenharmony_ci		goto err_free_in;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	rawkey = kmalloc(keybytes, gfp_mask);
1788c2ecf20Sopenharmony_ci	if (rawkey == NULL)
1798c2ecf20Sopenharmony_ci		goto err_free_out;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	inblock.data = (char *) inblockdata;
1828c2ecf20Sopenharmony_ci	inblock.len = blocksize;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	outblock.data = (char *) outblockdata;
1858c2ecf20Sopenharmony_ci	outblock.len = blocksize;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	/* initialize the input block */
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (in_constant->len == inblock.len) {
1908c2ecf20Sopenharmony_ci		memcpy(inblock.data, in_constant->data, inblock.len);
1918c2ecf20Sopenharmony_ci	} else {
1928c2ecf20Sopenharmony_ci		krb5_nfold(in_constant->len * 8, in_constant->data,
1938c2ecf20Sopenharmony_ci			   inblock.len * 8, inblock.data);
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	/* loop encrypting the blocks until enough key bytes are generated */
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	n = 0;
1998c2ecf20Sopenharmony_ci	while (n < keybytes) {
2008c2ecf20Sopenharmony_ci		(*(gk5e->encrypt))(cipher, NULL, inblock.data,
2018c2ecf20Sopenharmony_ci				   outblock.data, inblock.len);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci		if ((keybytes - n) <= outblock.len) {
2048c2ecf20Sopenharmony_ci			memcpy(rawkey + n, outblock.data, (keybytes - n));
2058c2ecf20Sopenharmony_ci			break;
2068c2ecf20Sopenharmony_ci		}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci		memcpy(rawkey + n, outblock.data, outblock.len);
2098c2ecf20Sopenharmony_ci		memcpy(inblock.data, outblock.data, outblock.len);
2108c2ecf20Sopenharmony_ci		n += outblock.len;
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	/* postprocess the key */
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	inblock.data = (char *) rawkey;
2168c2ecf20Sopenharmony_ci	inblock.len = keybytes;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	BUG_ON(gk5e->mk_key == NULL);
2198c2ecf20Sopenharmony_ci	ret = (*(gk5e->mk_key))(gk5e, &inblock, outkey);
2208c2ecf20Sopenharmony_ci	if (ret) {
2218c2ecf20Sopenharmony_ci		dprintk("%s: got %d from mk_key function for '%s'\n",
2228c2ecf20Sopenharmony_ci			__func__, ret, gk5e->encrypt_name);
2238c2ecf20Sopenharmony_ci		goto err_free_raw;
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	/* clean memory, free resources and exit */
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	ret = 0;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cierr_free_raw:
2318c2ecf20Sopenharmony_ci	kfree_sensitive(rawkey);
2328c2ecf20Sopenharmony_cierr_free_out:
2338c2ecf20Sopenharmony_ci	kfree_sensitive(outblockdata);
2348c2ecf20Sopenharmony_cierr_free_in:
2358c2ecf20Sopenharmony_ci	kfree_sensitive(inblockdata);
2368c2ecf20Sopenharmony_cierr_free_cipher:
2378c2ecf20Sopenharmony_ci	crypto_free_sync_skcipher(cipher);
2388c2ecf20Sopenharmony_cierr_return:
2398c2ecf20Sopenharmony_ci	return ret;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci#define smask(step) ((1<<step)-1)
2438c2ecf20Sopenharmony_ci#define pstep(x, step) (((x)&smask(step))^(((x)>>step)&smask(step)))
2448c2ecf20Sopenharmony_ci#define parity_char(x) pstep(pstep(pstep((x), 4), 2), 1)
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic void mit_des_fixup_key_parity(u8 key[8])
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	int i;
2498c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
2508c2ecf20Sopenharmony_ci		key[i] &= 0xfe;
2518c2ecf20Sopenharmony_ci		key[i] |= 1^parity_char(key[i]);
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci/*
2568c2ecf20Sopenharmony_ci * This is the des3 key derivation postprocess function
2578c2ecf20Sopenharmony_ci */
2588c2ecf20Sopenharmony_ciu32 gss_krb5_des3_make_key(const struct gss_krb5_enctype *gk5e,
2598c2ecf20Sopenharmony_ci			   struct xdr_netobj *randombits,
2608c2ecf20Sopenharmony_ci			   struct xdr_netobj *key)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	int i;
2638c2ecf20Sopenharmony_ci	u32 ret = EINVAL;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	if (key->len != 24) {
2668c2ecf20Sopenharmony_ci		dprintk("%s: key->len is %d\n", __func__, key->len);
2678c2ecf20Sopenharmony_ci		goto err_out;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci	if (randombits->len != 21) {
2708c2ecf20Sopenharmony_ci		dprintk("%s: randombits->len is %d\n",
2718c2ecf20Sopenharmony_ci			__func__, randombits->len);
2728c2ecf20Sopenharmony_ci		goto err_out;
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/* take the seven bytes, move them around into the top 7 bits of the
2768c2ecf20Sopenharmony_ci	   8 key bytes, then compute the parity bits.  Do this three times. */
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	for (i = 0; i < 3; i++) {
2798c2ecf20Sopenharmony_ci		memcpy(key->data + i*8, randombits->data + i*7, 7);
2808c2ecf20Sopenharmony_ci		key->data[i*8+7] = (((key->data[i*8]&1)<<1) |
2818c2ecf20Sopenharmony_ci				    ((key->data[i*8+1]&1)<<2) |
2828c2ecf20Sopenharmony_ci				    ((key->data[i*8+2]&1)<<3) |
2838c2ecf20Sopenharmony_ci				    ((key->data[i*8+3]&1)<<4) |
2848c2ecf20Sopenharmony_ci				    ((key->data[i*8+4]&1)<<5) |
2858c2ecf20Sopenharmony_ci				    ((key->data[i*8+5]&1)<<6) |
2868c2ecf20Sopenharmony_ci				    ((key->data[i*8+6]&1)<<7));
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci		mit_des_fixup_key_parity(key->data + i*8);
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci	ret = 0;
2918c2ecf20Sopenharmony_cierr_out:
2928c2ecf20Sopenharmony_ci	return ret;
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci/*
2968c2ecf20Sopenharmony_ci * This is the aes key derivation postprocess function
2978c2ecf20Sopenharmony_ci */
2988c2ecf20Sopenharmony_ciu32 gss_krb5_aes_make_key(const struct gss_krb5_enctype *gk5e,
2998c2ecf20Sopenharmony_ci			  struct xdr_netobj *randombits,
3008c2ecf20Sopenharmony_ci			  struct xdr_netobj *key)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	u32 ret = EINVAL;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (key->len != 16 && key->len != 32) {
3058c2ecf20Sopenharmony_ci		dprintk("%s: key->len is %d\n", __func__, key->len);
3068c2ecf20Sopenharmony_ci		goto err_out;
3078c2ecf20Sopenharmony_ci	}
3088c2ecf20Sopenharmony_ci	if (randombits->len != 16 && randombits->len != 32) {
3098c2ecf20Sopenharmony_ci		dprintk("%s: randombits->len is %d\n",
3108c2ecf20Sopenharmony_ci			__func__, randombits->len);
3118c2ecf20Sopenharmony_ci		goto err_out;
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci	if (randombits->len != key->len) {
3148c2ecf20Sopenharmony_ci		dprintk("%s: randombits->len is %d, key->len is %d\n",
3158c2ecf20Sopenharmony_ci			__func__, randombits->len, key->len);
3168c2ecf20Sopenharmony_ci		goto err_out;
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci	memcpy(key->data, randombits->data, key->len);
3198c2ecf20Sopenharmony_ci	ret = 0;
3208c2ecf20Sopenharmony_cierr_out:
3218c2ecf20Sopenharmony_ci	return ret;
3228c2ecf20Sopenharmony_ci}
323