~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to net/sunrpc/auth_gss/gss_krb5_keys.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * COPYRIGHT (c) 2008
 
3
 * The Regents of the University of Michigan
 
4
 * ALL RIGHTS RESERVED
 
5
 *
 
6
 * Permission is granted to use, copy, create derivative works
 
7
 * and redistribute this software and such derivative works
 
8
 * for any purpose, so long as the name of The University of
 
9
 * Michigan is not used in any advertising or publicity
 
10
 * pertaining to the use of distribution of this software
 
11
 * without specific, written prior authorization.  If the
 
12
 * above copyright notice or any other identification of the
 
13
 * University of Michigan is included in any copy of any
 
14
 * portion of this software, then the disclaimer below must
 
15
 * also be included.
 
16
 *
 
17
 * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
 
18
 * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
 
19
 * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
 
20
 * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
 
21
 * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
 
22
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
 
23
 * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
 
24
 * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
 
25
 * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
 
26
 * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
 
27
 * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
 
28
 * SUCH DAMAGES.
 
29
 */
 
30
 
 
31
/*
 
32
 * Copyright (C) 1998 by the FundsXpress, INC.
 
33
 *
 
34
 * All rights reserved.
 
35
 *
 
36
 * Export of this software from the United States of America may require
 
37
 * a specific license from the United States Government.  It is the
 
38
 * responsibility of any person or organization contemplating export to
 
39
 * obtain such a license before exporting.
 
40
 *
 
41
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 
42
 * distribute this software and its documentation for any purpose and
 
43
 * without fee is hereby granted, provided that the above copyright
 
44
 * notice appear in all copies and that both that copyright notice and
 
45
 * this permission notice appear in supporting documentation, and that
 
46
 * the name of FundsXpress. not be used in advertising or publicity pertaining
 
47
 * to distribution of the software without specific, written prior
 
48
 * permission.  FundsXpress makes no representations about the suitability of
 
49
 * this software for any purpose.  It is provided "as is" without express
 
50
 * or implied warranty.
 
51
 *
 
52
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 
53
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 
54
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
55
 */
 
56
 
 
57
#include <linux/err.h>
 
58
#include <linux/types.h>
 
59
#include <linux/crypto.h>
 
60
#include <linux/sunrpc/gss_krb5.h>
 
61
#include <linux/sunrpc/xdr.h>
 
62
 
 
63
#ifdef RPC_DEBUG
 
64
# define RPCDBG_FACILITY        RPCDBG_AUTH
 
65
#endif
 
66
 
 
67
/*
 
68
 * This is the n-fold function as described in rfc3961, sec 5.1
 
69
 * Taken from MIT Kerberos and modified.
 
70
 */
 
71
 
 
72
static void krb5_nfold(u32 inbits, const u8 *in,
 
73
                       u32 outbits, u8 *out)
 
74
{
 
75
        int a, b, c, lcm;
 
76
        int byte, i, msbit;
 
77
 
 
78
        /* the code below is more readable if I make these bytes
 
79
           instead of bits */
 
80
 
 
81
        inbits >>= 3;
 
82
        outbits >>= 3;
 
83
 
 
84
        /* first compute lcm(n,k) */
 
85
 
 
86
        a = outbits;
 
87
        b = inbits;
 
88
 
 
89
        while (b != 0) {
 
90
                c = b;
 
91
                b = a%b;
 
92
                a = c;
 
93
        }
 
94
 
 
95
        lcm = outbits*inbits/a;
 
96
 
 
97
        /* now do the real work */
 
98
 
 
99
        memset(out, 0, outbits);
 
100
        byte = 0;
 
101
 
 
102
        /* this will end up cycling through k lcm(k,n)/k times, which
 
103
           is correct */
 
104
        for (i = lcm-1; i >= 0; i--) {
 
105
                /* compute the msbit in k which gets added into this byte */
 
106
                msbit = (
 
107
                        /* first, start with the msbit in the first,
 
108
                         * unrotated byte */
 
109
                         ((inbits << 3) - 1)
 
110
                         /* then, for each byte, shift to the right
 
111
                          * for each repetition */
 
112
                         + (((inbits << 3) + 13) * (i/inbits))
 
113
                         /* last, pick out the correct byte within
 
114
                          * that shifted repetition */
 
115
                         + ((inbits - (i % inbits)) << 3)
 
116
                         ) % (inbits << 3);
 
117
 
 
118
                /* pull out the byte value itself */
 
119
                byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8)|
 
120
                                  (in[((inbits) - (msbit >> 3)) % inbits]))
 
121
                                 >> ((msbit & 7) + 1)) & 0xff;
 
122
 
 
123
                /* do the addition */
 
124
                byte += out[i % outbits];
 
125
                out[i % outbits] = byte & 0xff;
 
126
 
 
127
                /* keep around the carry bit, if any */
 
128
                byte >>= 8;
 
129
 
 
130
        }
 
131
 
 
132
        /* if there's a carry bit left over, add it back in */
 
133
        if (byte) {
 
134
                for (i = outbits - 1; i >= 0; i--) {
 
135
                        /* do the addition */
 
136
                        byte += out[i];
 
137
                        out[i] = byte & 0xff;
 
138
 
 
139
                        /* keep around the carry bit, if any */
 
140
                        byte >>= 8;
 
141
                }
 
142
        }
 
143
}
 
144
 
 
145
/*
 
146
 * This is the DK (derive_key) function as described in rfc3961, sec 5.1
 
147
 * Taken from MIT Kerberos and modified.
 
148
 */
 
149
 
 
150
u32 krb5_derive_key(const struct gss_krb5_enctype *gk5e,
 
151
                    const struct xdr_netobj *inkey,
 
152
                    struct xdr_netobj *outkey,
 
153
                    const struct xdr_netobj *in_constant,
 
154
                    gfp_t gfp_mask)
 
155
{
 
156
        size_t blocksize, keybytes, keylength, n;
 
157
        unsigned char *inblockdata, *outblockdata, *rawkey;
 
158
        struct xdr_netobj inblock, outblock;
 
159
        struct crypto_blkcipher *cipher;
 
160
        u32 ret = EINVAL;
 
161
 
 
162
        blocksize = gk5e->blocksize;
 
163
        keybytes = gk5e->keybytes;
 
164
        keylength = gk5e->keylength;
 
165
 
 
166
        if ((inkey->len != keylength) || (outkey->len != keylength))
 
167
                goto err_return;
 
168
 
 
169
        cipher = crypto_alloc_blkcipher(gk5e->encrypt_name, 0,
 
170
                                        CRYPTO_ALG_ASYNC);
 
171
        if (IS_ERR(cipher))
 
172
                goto err_return;
 
173
        if (crypto_blkcipher_setkey(cipher, inkey->data, inkey->len))
 
174
                goto err_return;
 
175
 
 
176
        /* allocate and set up buffers */
 
177
 
 
178
        ret = ENOMEM;
 
179
        inblockdata = kmalloc(blocksize, gfp_mask);
 
180
        if (inblockdata == NULL)
 
181
                goto err_free_cipher;
 
182
 
 
183
        outblockdata = kmalloc(blocksize, gfp_mask);
 
184
        if (outblockdata == NULL)
 
185
                goto err_free_in;
 
186
 
 
187
        rawkey = kmalloc(keybytes, gfp_mask);
 
188
        if (rawkey == NULL)
 
189
                goto err_free_out;
 
190
 
 
191
        inblock.data = (char *) inblockdata;
 
192
        inblock.len = blocksize;
 
193
 
 
194
        outblock.data = (char *) outblockdata;
 
195
        outblock.len = blocksize;
 
196
 
 
197
        /* initialize the input block */
 
198
 
 
199
        if (in_constant->len == inblock.len) {
 
200
                memcpy(inblock.data, in_constant->data, inblock.len);
 
201
        } else {
 
202
                krb5_nfold(in_constant->len * 8, in_constant->data,
 
203
                           inblock.len * 8, inblock.data);
 
204
        }
 
205
 
 
206
        /* loop encrypting the blocks until enough key bytes are generated */
 
207
 
 
208
        n = 0;
 
209
        while (n < keybytes) {
 
210
                (*(gk5e->encrypt))(cipher, NULL, inblock.data,
 
211
                                   outblock.data, inblock.len);
 
212
 
 
213
                if ((keybytes - n) <= outblock.len) {
 
214
                        memcpy(rawkey + n, outblock.data, (keybytes - n));
 
215
                        break;
 
216
                }
 
217
 
 
218
                memcpy(rawkey + n, outblock.data, outblock.len);
 
219
                memcpy(inblock.data, outblock.data, outblock.len);
 
220
                n += outblock.len;
 
221
        }
 
222
 
 
223
        /* postprocess the key */
 
224
 
 
225
        inblock.data = (char *) rawkey;
 
226
        inblock.len = keybytes;
 
227
 
 
228
        BUG_ON(gk5e->mk_key == NULL);
 
229
        ret = (*(gk5e->mk_key))(gk5e, &inblock, outkey);
 
230
        if (ret) {
 
231
                dprintk("%s: got %d from mk_key function for '%s'\n",
 
232
                        __func__, ret, gk5e->encrypt_name);
 
233
                goto err_free_raw;
 
234
        }
 
235
 
 
236
        /* clean memory, free resources and exit */
 
237
 
 
238
        ret = 0;
 
239
 
 
240
err_free_raw:
 
241
        memset(rawkey, 0, keybytes);
 
242
        kfree(rawkey);
 
243
err_free_out:
 
244
        memset(outblockdata, 0, blocksize);
 
245
        kfree(outblockdata);
 
246
err_free_in:
 
247
        memset(inblockdata, 0, blocksize);
 
248
        kfree(inblockdata);
 
249
err_free_cipher:
 
250
        crypto_free_blkcipher(cipher);
 
251
err_return:
 
252
        return ret;
 
253
}
 
254
 
 
255
#define smask(step) ((1<<step)-1)
 
256
#define pstep(x, step) (((x)&smask(step))^(((x)>>step)&smask(step)))
 
257
#define parity_char(x) pstep(pstep(pstep((x), 4), 2), 1)
 
258
 
 
259
static void mit_des_fixup_key_parity(u8 key[8])
 
260
{
 
261
        int i;
 
262
        for (i = 0; i < 8; i++) {
 
263
                key[i] &= 0xfe;
 
264
                key[i] |= 1^parity_char(key[i]);
 
265
        }
 
266
}
 
267
 
 
268
/*
 
269
 * This is the des3 key derivation postprocess function
 
270
 */
 
271
u32 gss_krb5_des3_make_key(const struct gss_krb5_enctype *gk5e,
 
272
                           struct xdr_netobj *randombits,
 
273
                           struct xdr_netobj *key)
 
274
{
 
275
        int i;
 
276
        u32 ret = EINVAL;
 
277
 
 
278
        if (key->len != 24) {
 
279
                dprintk("%s: key->len is %d\n", __func__, key->len);
 
280
                goto err_out;
 
281
        }
 
282
        if (randombits->len != 21) {
 
283
                dprintk("%s: randombits->len is %d\n",
 
284
                        __func__, randombits->len);
 
285
                goto err_out;
 
286
        }
 
287
 
 
288
        /* take the seven bytes, move them around into the top 7 bits of the
 
289
           8 key bytes, then compute the parity bits.  Do this three times. */
 
290
 
 
291
        for (i = 0; i < 3; i++) {
 
292
                memcpy(key->data + i*8, randombits->data + i*7, 7);
 
293
                key->data[i*8+7] = (((key->data[i*8]&1)<<1) |
 
294
                                    ((key->data[i*8+1]&1)<<2) |
 
295
                                    ((key->data[i*8+2]&1)<<3) |
 
296
                                    ((key->data[i*8+3]&1)<<4) |
 
297
                                    ((key->data[i*8+4]&1)<<5) |
 
298
                                    ((key->data[i*8+5]&1)<<6) |
 
299
                                    ((key->data[i*8+6]&1)<<7));
 
300
 
 
301
                mit_des_fixup_key_parity(key->data + i*8);
 
302
        }
 
303
        ret = 0;
 
304
err_out:
 
305
        return ret;
 
306
}
 
307
 
 
308
/*
 
309
 * This is the aes key derivation postprocess function
 
310
 */
 
311
u32 gss_krb5_aes_make_key(const struct gss_krb5_enctype *gk5e,
 
312
                          struct xdr_netobj *randombits,
 
313
                          struct xdr_netobj *key)
 
314
{
 
315
        u32 ret = EINVAL;
 
316
 
 
317
        if (key->len != 16 && key->len != 32) {
 
318
                dprintk("%s: key->len is %d\n", __func__, key->len);
 
319
                goto err_out;
 
320
        }
 
321
        if (randombits->len != 16 && randombits->len != 32) {
 
322
                dprintk("%s: randombits->len is %d\n",
 
323
                        __func__, randombits->len);
 
324
                goto err_out;
 
325
        }
 
326
        if (randombits->len != key->len) {
 
327
                dprintk("%s: randombits->len is %d, key->len is %d\n",
 
328
                        __func__, randombits->len, key->len);
 
329
                goto err_out;
 
330
        }
 
331
        memcpy(key->data, randombits->data, key->len);
 
332
        ret = 0;
 
333
err_out:
 
334
        return ret;
 
335
}
 
336