Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/sunrpc/auth_gss/gss_krb5_keys.c
15112 views
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
337
338