Path: blob/master/net/sunrpc/auth_gss/gss_krb5_keys.c
15112 views
/*1* COPYRIGHT (c) 20082* The Regents of the University of Michigan3* ALL RIGHTS RESERVED4*5* Permission is granted to use, copy, create derivative works6* and redistribute this software and such derivative works7* for any purpose, so long as the name of The University of8* Michigan is not used in any advertising or publicity9* pertaining to the use of distribution of this software10* without specific, written prior authorization. If the11* above copyright notice or any other identification of the12* University of Michigan is included in any copy of any13* portion of this software, then the disclaimer below must14* also be included.15*16* THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION17* FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY18* PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF19* MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING20* WITHOUT LIMITATION THE IMPLIED WARRANTIES OF21* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE22* REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE23* FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR24* CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING25* OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN26* IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF27* SUCH DAMAGES.28*/2930/*31* Copyright (C) 1998 by the FundsXpress, INC.32*33* All rights reserved.34*35* Export of this software from the United States of America may require36* a specific license from the United States Government. It is the37* responsibility of any person or organization contemplating export to38* obtain such a license before exporting.39*40* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and41* distribute this software and its documentation for any purpose and42* without fee is hereby granted, provided that the above copyright43* notice appear in all copies and that both that copyright notice and44* this permission notice appear in supporting documentation, and that45* the name of FundsXpress. not be used in advertising or publicity pertaining46* to distribution of the software without specific, written prior47* permission. FundsXpress makes no representations about the suitability of48* this software for any purpose. It is provided "as is" without express49* or implied warranty.50*51* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR52* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED53* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.54*/5556#include <linux/err.h>57#include <linux/types.h>58#include <linux/crypto.h>59#include <linux/sunrpc/gss_krb5.h>60#include <linux/sunrpc/xdr.h>6162#ifdef RPC_DEBUG63# define RPCDBG_FACILITY RPCDBG_AUTH64#endif6566/*67* This is the n-fold function as described in rfc3961, sec 5.168* Taken from MIT Kerberos and modified.69*/7071static void krb5_nfold(u32 inbits, const u8 *in,72u32 outbits, u8 *out)73{74int a, b, c, lcm;75int byte, i, msbit;7677/* the code below is more readable if I make these bytes78instead of bits */7980inbits >>= 3;81outbits >>= 3;8283/* first compute lcm(n,k) */8485a = outbits;86b = inbits;8788while (b != 0) {89c = b;90b = a%b;91a = c;92}9394lcm = outbits*inbits/a;9596/* now do the real work */9798memset(out, 0, outbits);99byte = 0;100101/* this will end up cycling through k lcm(k,n)/k times, which102is correct */103for (i = lcm-1; i >= 0; i--) {104/* compute the msbit in k which gets added into this byte */105msbit = (106/* first, start with the msbit in the first,107* unrotated byte */108((inbits << 3) - 1)109/* then, for each byte, shift to the right110* for each repetition */111+ (((inbits << 3) + 13) * (i/inbits))112/* last, pick out the correct byte within113* that shifted repetition */114+ ((inbits - (i % inbits)) << 3)115) % (inbits << 3);116117/* pull out the byte value itself */118byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8)|119(in[((inbits) - (msbit >> 3)) % inbits]))120>> ((msbit & 7) + 1)) & 0xff;121122/* do the addition */123byte += out[i % outbits];124out[i % outbits] = byte & 0xff;125126/* keep around the carry bit, if any */127byte >>= 8;128129}130131/* if there's a carry bit left over, add it back in */132if (byte) {133for (i = outbits - 1; i >= 0; i--) {134/* do the addition */135byte += out[i];136out[i] = byte & 0xff;137138/* keep around the carry bit, if any */139byte >>= 8;140}141}142}143144/*145* This is the DK (derive_key) function as described in rfc3961, sec 5.1146* Taken from MIT Kerberos and modified.147*/148149u32 krb5_derive_key(const struct gss_krb5_enctype *gk5e,150const struct xdr_netobj *inkey,151struct xdr_netobj *outkey,152const struct xdr_netobj *in_constant,153gfp_t gfp_mask)154{155size_t blocksize, keybytes, keylength, n;156unsigned char *inblockdata, *outblockdata, *rawkey;157struct xdr_netobj inblock, outblock;158struct crypto_blkcipher *cipher;159u32 ret = EINVAL;160161blocksize = gk5e->blocksize;162keybytes = gk5e->keybytes;163keylength = gk5e->keylength;164165if ((inkey->len != keylength) || (outkey->len != keylength))166goto err_return;167168cipher = crypto_alloc_blkcipher(gk5e->encrypt_name, 0,169CRYPTO_ALG_ASYNC);170if (IS_ERR(cipher))171goto err_return;172if (crypto_blkcipher_setkey(cipher, inkey->data, inkey->len))173goto err_return;174175/* allocate and set up buffers */176177ret = ENOMEM;178inblockdata = kmalloc(blocksize, gfp_mask);179if (inblockdata == NULL)180goto err_free_cipher;181182outblockdata = kmalloc(blocksize, gfp_mask);183if (outblockdata == NULL)184goto err_free_in;185186rawkey = kmalloc(keybytes, gfp_mask);187if (rawkey == NULL)188goto err_free_out;189190inblock.data = (char *) inblockdata;191inblock.len = blocksize;192193outblock.data = (char *) outblockdata;194outblock.len = blocksize;195196/* initialize the input block */197198if (in_constant->len == inblock.len) {199memcpy(inblock.data, in_constant->data, inblock.len);200} else {201krb5_nfold(in_constant->len * 8, in_constant->data,202inblock.len * 8, inblock.data);203}204205/* loop encrypting the blocks until enough key bytes are generated */206207n = 0;208while (n < keybytes) {209(*(gk5e->encrypt))(cipher, NULL, inblock.data,210outblock.data, inblock.len);211212if ((keybytes - n) <= outblock.len) {213memcpy(rawkey + n, outblock.data, (keybytes - n));214break;215}216217memcpy(rawkey + n, outblock.data, outblock.len);218memcpy(inblock.data, outblock.data, outblock.len);219n += outblock.len;220}221222/* postprocess the key */223224inblock.data = (char *) rawkey;225inblock.len = keybytes;226227BUG_ON(gk5e->mk_key == NULL);228ret = (*(gk5e->mk_key))(gk5e, &inblock, outkey);229if (ret) {230dprintk("%s: got %d from mk_key function for '%s'\n",231__func__, ret, gk5e->encrypt_name);232goto err_free_raw;233}234235/* clean memory, free resources and exit */236237ret = 0;238239err_free_raw:240memset(rawkey, 0, keybytes);241kfree(rawkey);242err_free_out:243memset(outblockdata, 0, blocksize);244kfree(outblockdata);245err_free_in:246memset(inblockdata, 0, blocksize);247kfree(inblockdata);248err_free_cipher:249crypto_free_blkcipher(cipher);250err_return:251return ret;252}253254#define smask(step) ((1<<step)-1)255#define pstep(x, step) (((x)&smask(step))^(((x)>>step)&smask(step)))256#define parity_char(x) pstep(pstep(pstep((x), 4), 2), 1)257258static void mit_des_fixup_key_parity(u8 key[8])259{260int i;261for (i = 0; i < 8; i++) {262key[i] &= 0xfe;263key[i] |= 1^parity_char(key[i]);264}265}266267/*268* This is the des3 key derivation postprocess function269*/270u32 gss_krb5_des3_make_key(const struct gss_krb5_enctype *gk5e,271struct xdr_netobj *randombits,272struct xdr_netobj *key)273{274int i;275u32 ret = EINVAL;276277if (key->len != 24) {278dprintk("%s: key->len is %d\n", __func__, key->len);279goto err_out;280}281if (randombits->len != 21) {282dprintk("%s: randombits->len is %d\n",283__func__, randombits->len);284goto err_out;285}286287/* take the seven bytes, move them around into the top 7 bits of the2888 key bytes, then compute the parity bits. Do this three times. */289290for (i = 0; i < 3; i++) {291memcpy(key->data + i*8, randombits->data + i*7, 7);292key->data[i*8+7] = (((key->data[i*8]&1)<<1) |293((key->data[i*8+1]&1)<<2) |294((key->data[i*8+2]&1)<<3) |295((key->data[i*8+3]&1)<<4) |296((key->data[i*8+4]&1)<<5) |297((key->data[i*8+5]&1)<<6) |298((key->data[i*8+6]&1)<<7));299300mit_des_fixup_key_parity(key->data + i*8);301}302ret = 0;303err_out:304return ret;305}306307/*308* This is the aes key derivation postprocess function309*/310u32 gss_krb5_aes_make_key(const struct gss_krb5_enctype *gk5e,311struct xdr_netobj *randombits,312struct xdr_netobj *key)313{314u32 ret = EINVAL;315316if (key->len != 16 && key->len != 32) {317dprintk("%s: key->len is %d\n", __func__, key->len);318goto err_out;319}320if (randombits->len != 16 && randombits->len != 32) {321dprintk("%s: randombits->len is %d\n",322__func__, randombits->len);323goto err_out;324}325if (randombits->len != key->len) {326dprintk("%s: randombits->len is %d, key->len is %d\n",327__func__, randombits->len, key->len);328goto err_out;329}330memcpy(key->data, randombits->data, key->len);331ret = 0;332err_out:333return ret;334}335336337338