]>
Commit | Line | Data |
---|---|---|
4891f2d0 KC |
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> | |
c692554b | 62 | #include <linux/lcm.h> |
4891f2d0 | 63 | |
f895b252 | 64 | #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) |
4891f2d0 KC |
65 | # define RPCDBG_FACILITY RPCDBG_AUTH |
66 | #endif | |
67 | ||
68 | /* | |
69 | * This is the n-fold function as described in rfc3961, sec 5.1 | |
70 | * Taken from MIT Kerberos and modified. | |
71 | */ | |
72 | ||
73 | static void krb5_nfold(u32 inbits, const u8 *in, | |
74 | u32 outbits, u8 *out) | |
75 | { | |
c692554b | 76 | unsigned long ulcm; |
4891f2d0 KC |
77 | int byte, i, msbit; |
78 | ||
79 | /* the code below is more readable if I make these bytes | |
80 | instead of bits */ | |
81 | ||
82 | inbits >>= 3; | |
83 | outbits >>= 3; | |
84 | ||
85 | /* first compute lcm(n,k) */ | |
c692554b | 86 | ulcm = lcm(inbits, outbits); |
4891f2d0 KC |
87 | |
88 | /* now do the real work */ | |
89 | ||
90 | memset(out, 0, outbits); | |
91 | byte = 0; | |
92 | ||
93 | /* this will end up cycling through k lcm(k,n)/k times, which | |
94 | is correct */ | |
c692554b | 95 | for (i = ulcm-1; i >= 0; i--) { |
4891f2d0 KC |
96 | /* compute the msbit in k which gets added into this byte */ |
97 | msbit = ( | |
98 | /* first, start with the msbit in the first, | |
99 | * unrotated byte */ | |
100 | ((inbits << 3) - 1) | |
101 | /* then, for each byte, shift to the right | |
102 | * for each repetition */ | |
103 | + (((inbits << 3) + 13) * (i/inbits)) | |
104 | /* last, pick out the correct byte within | |
105 | * that shifted repetition */ | |
106 | + ((inbits - (i % inbits)) << 3) | |
107 | ) % (inbits << 3); | |
108 | ||
109 | /* pull out the byte value itself */ | |
110 | byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8)| | |
111 | (in[((inbits) - (msbit >> 3)) % inbits])) | |
112 | >> ((msbit & 7) + 1)) & 0xff; | |
113 | ||
114 | /* do the addition */ | |
115 | byte += out[i % outbits]; | |
116 | out[i % outbits] = byte & 0xff; | |
117 | ||
118 | /* keep around the carry bit, if any */ | |
119 | byte >>= 8; | |
120 | ||
121 | } | |
122 | ||
123 | /* if there's a carry bit left over, add it back in */ | |
124 | if (byte) { | |
125 | for (i = outbits - 1; i >= 0; i--) { | |
126 | /* do the addition */ | |
127 | byte += out[i]; | |
128 | out[i] = byte & 0xff; | |
129 | ||
130 | /* keep around the carry bit, if any */ | |
131 | byte >>= 8; | |
132 | } | |
133 | } | |
134 | } | |
135 | ||
136 | /* | |
137 | * This is the DK (derive_key) function as described in rfc3961, sec 5.1 | |
138 | * Taken from MIT Kerberos and modified. | |
139 | */ | |
140 | ||
47d84807 | 141 | u32 krb5_derive_key(const struct gss_krb5_enctype *gk5e, |
4891f2d0 KC |
142 | const struct xdr_netobj *inkey, |
143 | struct xdr_netobj *outkey, | |
1f4c86c0 TM |
144 | const struct xdr_netobj *in_constant, |
145 | gfp_t gfp_mask) | |
4891f2d0 KC |
146 | { |
147 | size_t blocksize, keybytes, keylength, n; | |
148 | unsigned char *inblockdata, *outblockdata, *rawkey; | |
149 | struct xdr_netobj inblock, outblock; | |
150 | struct crypto_blkcipher *cipher; | |
151 | u32 ret = EINVAL; | |
152 | ||
153 | blocksize = gk5e->blocksize; | |
154 | keybytes = gk5e->keybytes; | |
155 | keylength = gk5e->keylength; | |
156 | ||
157 | if ((inkey->len != keylength) || (outkey->len != keylength)) | |
158 | goto err_return; | |
159 | ||
160 | cipher = crypto_alloc_blkcipher(gk5e->encrypt_name, 0, | |
161 | CRYPTO_ALG_ASYNC); | |
162 | if (IS_ERR(cipher)) | |
163 | goto err_return; | |
164 | if (crypto_blkcipher_setkey(cipher, inkey->data, inkey->len)) | |
165 | goto err_return; | |
166 | ||
167 | /* allocate and set up buffers */ | |
168 | ||
169 | ret = ENOMEM; | |
1f4c86c0 | 170 | inblockdata = kmalloc(blocksize, gfp_mask); |
4891f2d0 KC |
171 | if (inblockdata == NULL) |
172 | goto err_free_cipher; | |
173 | ||
1f4c86c0 | 174 | outblockdata = kmalloc(blocksize, gfp_mask); |
4891f2d0 KC |
175 | if (outblockdata == NULL) |
176 | goto err_free_in; | |
177 | ||
1f4c86c0 | 178 | rawkey = kmalloc(keybytes, gfp_mask); |
4891f2d0 KC |
179 | if (rawkey == NULL) |
180 | goto err_free_out; | |
181 | ||
182 | inblock.data = (char *) inblockdata; | |
183 | inblock.len = blocksize; | |
184 | ||
185 | outblock.data = (char *) outblockdata; | |
186 | outblock.len = blocksize; | |
187 | ||
188 | /* initialize the input block */ | |
189 | ||
190 | if (in_constant->len == inblock.len) { | |
191 | memcpy(inblock.data, in_constant->data, inblock.len); | |
192 | } else { | |
193 | krb5_nfold(in_constant->len * 8, in_constant->data, | |
194 | inblock.len * 8, inblock.data); | |
195 | } | |
196 | ||
197 | /* loop encrypting the blocks until enough key bytes are generated */ | |
198 | ||
199 | n = 0; | |
200 | while (n < keybytes) { | |
201 | (*(gk5e->encrypt))(cipher, NULL, inblock.data, | |
202 | outblock.data, inblock.len); | |
203 | ||
204 | if ((keybytes - n) <= outblock.len) { | |
205 | memcpy(rawkey + n, outblock.data, (keybytes - n)); | |
206 | break; | |
207 | } | |
208 | ||
209 | memcpy(rawkey + n, outblock.data, outblock.len); | |
210 | memcpy(inblock.data, outblock.data, outblock.len); | |
211 | n += outblock.len; | |
212 | } | |
213 | ||
214 | /* postprocess the key */ | |
215 | ||
216 | inblock.data = (char *) rawkey; | |
217 | inblock.len = keybytes; | |
218 | ||
219 | BUG_ON(gk5e->mk_key == NULL); | |
220 | ret = (*(gk5e->mk_key))(gk5e, &inblock, outkey); | |
221 | if (ret) { | |
222 | dprintk("%s: got %d from mk_key function for '%s'\n", | |
223 | __func__, ret, gk5e->encrypt_name); | |
224 | goto err_free_raw; | |
225 | } | |
226 | ||
227 | /* clean memory, free resources and exit */ | |
228 | ||
229 | ret = 0; | |
230 | ||
231 | err_free_raw: | |
232 | memset(rawkey, 0, keybytes); | |
233 | kfree(rawkey); | |
234 | err_free_out: | |
235 | memset(outblockdata, 0, blocksize); | |
236 | kfree(outblockdata); | |
237 | err_free_in: | |
238 | memset(inblockdata, 0, blocksize); | |
239 | kfree(inblockdata); | |
240 | err_free_cipher: | |
241 | crypto_free_blkcipher(cipher); | |
242 | err_return: | |
243 | return ret; | |
244 | } | |
958142e9 KC |
245 | |
246 | #define smask(step) ((1<<step)-1) | |
247 | #define pstep(x, step) (((x)&smask(step))^(((x)>>step)&smask(step))) | |
248 | #define parity_char(x) pstep(pstep(pstep((x), 4), 2), 1) | |
249 | ||
250 | static void mit_des_fixup_key_parity(u8 key[8]) | |
251 | { | |
252 | int i; | |
253 | for (i = 0; i < 8; i++) { | |
254 | key[i] &= 0xfe; | |
255 | key[i] |= 1^parity_char(key[i]); | |
256 | } | |
257 | } | |
258 | ||
259 | /* | |
260 | * This is the des3 key derivation postprocess function | |
261 | */ | |
262 | u32 gss_krb5_des3_make_key(const struct gss_krb5_enctype *gk5e, | |
263 | struct xdr_netobj *randombits, | |
264 | struct xdr_netobj *key) | |
265 | { | |
266 | int i; | |
267 | u32 ret = EINVAL; | |
268 | ||
269 | if (key->len != 24) { | |
270 | dprintk("%s: key->len is %d\n", __func__, key->len); | |
271 | goto err_out; | |
272 | } | |
273 | if (randombits->len != 21) { | |
274 | dprintk("%s: randombits->len is %d\n", | |
275 | __func__, randombits->len); | |
276 | goto err_out; | |
277 | } | |
278 | ||
279 | /* take the seven bytes, move them around into the top 7 bits of the | |
280 | 8 key bytes, then compute the parity bits. Do this three times. */ | |
281 | ||
282 | for (i = 0; i < 3; i++) { | |
283 | memcpy(key->data + i*8, randombits->data + i*7, 7); | |
284 | key->data[i*8+7] = (((key->data[i*8]&1)<<1) | | |
285 | ((key->data[i*8+1]&1)<<2) | | |
286 | ((key->data[i*8+2]&1)<<3) | | |
287 | ((key->data[i*8+3]&1)<<4) | | |
288 | ((key->data[i*8+4]&1)<<5) | | |
289 | ((key->data[i*8+5]&1)<<6) | | |
290 | ((key->data[i*8+6]&1)<<7)); | |
291 | ||
292 | mit_des_fixup_key_parity(key->data + i*8); | |
293 | } | |
294 | ret = 0; | |
295 | err_out: | |
296 | return ret; | |
297 | } | |
934a95aa KC |
298 | |
299 | /* | |
300 | * This is the aes key derivation postprocess function | |
301 | */ | |
302 | u32 gss_krb5_aes_make_key(const struct gss_krb5_enctype *gk5e, | |
303 | struct xdr_netobj *randombits, | |
304 | struct xdr_netobj *key) | |
305 | { | |
306 | u32 ret = EINVAL; | |
307 | ||
308 | if (key->len != 16 && key->len != 32) { | |
309 | dprintk("%s: key->len is %d\n", __func__, key->len); | |
310 | goto err_out; | |
311 | } | |
312 | if (randombits->len != 16 && randombits->len != 32) { | |
313 | dprintk("%s: randombits->len is %d\n", | |
314 | __func__, randombits->len); | |
315 | goto err_out; | |
316 | } | |
317 | if (randombits->len != key->len) { | |
318 | dprintk("%s: randombits->len is %d, key->len is %d\n", | |
319 | __func__, randombits->len, key->len); | |
320 | goto err_out; | |
321 | } | |
322 | memcpy(key->data, randombits->data, key->len); | |
323 | ret = 0; | |
324 | err_out: | |
325 | return ret; | |
326 | } | |
327 |