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