]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/net/sunrpc/gss_krb5_crypto.c | |
3 | * | |
81d4a433 | 4 | * Copyright (c) 2000-2008 The Regents of the University of Michigan. |
1da177e4 LT |
5 | * All rights reserved. |
6 | * | |
7 | * Andy Adamson <andros@umich.edu> | |
8 | * Bruce Fields <bfields@umich.edu> | |
9 | */ | |
10 | ||
11 | /* | |
12 | * Copyright (C) 1998 by the FundsXpress, INC. | |
13 | * | |
14 | * All rights reserved. | |
15 | * | |
16 | * Export of this software from the United States of America may require | |
17 | * a specific license from the United States Government. It is the | |
18 | * responsibility of any person or organization contemplating export to | |
19 | * obtain such a license before exporting. | |
20 | * | |
21 | * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and | |
22 | * distribute this software and its documentation for any purpose and | |
23 | * without fee is hereby granted, provided that the above copyright | |
24 | * notice appear in all copies and that both that copyright notice and | |
25 | * this permission notice appear in supporting documentation, and that | |
26 | * the name of FundsXpress. not be used in advertising or publicity pertaining | |
27 | * to distribution of the software without specific, written prior | |
28 | * permission. FundsXpress makes no representations about the suitability of | |
29 | * this software for any purpose. It is provided "as is" without express | |
30 | * or implied warranty. | |
31 | * | |
32 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
33 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
34 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
35 | */ | |
36 | ||
15a8b93f | 37 | #include <crypto/algapi.h> |
3b5cf20c HX |
38 | #include <crypto/hash.h> |
39 | #include <crypto/skcipher.h> | |
35058687 | 40 | #include <linux/err.h> |
1da177e4 LT |
41 | #include <linux/types.h> |
42 | #include <linux/mm.h> | |
378f058c | 43 | #include <linux/scatterlist.h> |
1da177e4 LT |
44 | #include <linux/highmem.h> |
45 | #include <linux/pagemap.h> | |
934a95aa | 46 | #include <linux/random.h> |
1da177e4 | 47 | #include <linux/sunrpc/gss_krb5.h> |
37a4e6cb | 48 | #include <linux/sunrpc/xdr.h> |
1da177e4 | 49 | |
f895b252 | 50 | #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) |
1da177e4 LT |
51 | # define RPCDBG_FACILITY RPCDBG_AUTH |
52 | #endif | |
53 | ||
54 | u32 | |
55 | krb5_encrypt( | |
e9e575b8 | 56 | struct crypto_sync_skcipher *tfm, |
1da177e4 LT |
57 | void * iv, |
58 | void * in, | |
59 | void * out, | |
60 | int length) | |
61 | { | |
62 | u32 ret = -EINVAL; | |
cca5172a | 63 | struct scatterlist sg[1]; |
81d4a433 | 64 | u8 local_iv[GSS_KRB5_MAX_BLOCKSIZE] = {0}; |
e9e575b8 | 65 | SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); |
1da177e4 | 66 | |
e9e575b8 | 67 | if (length % crypto_sync_skcipher_blocksize(tfm) != 0) |
1da177e4 LT |
68 | goto out; |
69 | ||
e9e575b8 | 70 | if (crypto_sync_skcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) { |
3d4a6886 | 71 | dprintk("RPC: gss_k5encrypt: tfm iv size too large %d\n", |
e9e575b8 | 72 | crypto_sync_skcipher_ivsize(tfm)); |
1da177e4 LT |
73 | goto out; |
74 | } | |
75 | ||
76 | if (iv) | |
e9e575b8 | 77 | memcpy(local_iv, iv, crypto_sync_skcipher_ivsize(tfm)); |
1da177e4 LT |
78 | |
79 | memcpy(out, in, length); | |
68e3f5dd | 80 | sg_init_one(sg, out, length); |
1da177e4 | 81 | |
e9e575b8 | 82 | skcipher_request_set_sync_tfm(req, tfm); |
3b5cf20c HX |
83 | skcipher_request_set_callback(req, 0, NULL, NULL); |
84 | skcipher_request_set_crypt(req, sg, sg, length, local_iv); | |
85 | ||
86 | ret = crypto_skcipher_encrypt(req); | |
87 | skcipher_request_zero(req); | |
1da177e4 | 88 | out: |
8885cb36 | 89 | dprintk("RPC: krb5_encrypt returns %d\n", ret); |
8fc7500b | 90 | return ret; |
1da177e4 LT |
91 | } |
92 | ||
1da177e4 LT |
93 | u32 |
94 | krb5_decrypt( | |
e9e575b8 | 95 | struct crypto_sync_skcipher *tfm, |
1da177e4 LT |
96 | void * iv, |
97 | void * in, | |
98 | void * out, | |
99 | int length) | |
100 | { | |
101 | u32 ret = -EINVAL; | |
102 | struct scatterlist sg[1]; | |
81d4a433 | 103 | u8 local_iv[GSS_KRB5_MAX_BLOCKSIZE] = {0}; |
e9e575b8 | 104 | SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); |
1da177e4 | 105 | |
e9e575b8 | 106 | if (length % crypto_sync_skcipher_blocksize(tfm) != 0) |
1da177e4 LT |
107 | goto out; |
108 | ||
e9e575b8 | 109 | if (crypto_sync_skcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) { |
3d4a6886 | 110 | dprintk("RPC: gss_k5decrypt: tfm iv size too large %d\n", |
e9e575b8 | 111 | crypto_sync_skcipher_ivsize(tfm)); |
1da177e4 LT |
112 | goto out; |
113 | } | |
114 | if (iv) | |
e9e575b8 | 115 | memcpy(local_iv, iv, crypto_sync_skcipher_ivsize(tfm)); |
1da177e4 LT |
116 | |
117 | memcpy(out, in, length); | |
68e3f5dd | 118 | sg_init_one(sg, out, length); |
1da177e4 | 119 | |
e9e575b8 | 120 | skcipher_request_set_sync_tfm(req, tfm); |
3b5cf20c HX |
121 | skcipher_request_set_callback(req, 0, NULL, NULL); |
122 | skcipher_request_set_crypt(req, sg, sg, length, local_iv); | |
123 | ||
124 | ret = crypto_skcipher_decrypt(req); | |
125 | skcipher_request_zero(req); | |
1da177e4 | 126 | out: |
8885cb36 | 127 | dprintk("RPC: gss_k5decrypt returns %d\n",ret); |
8fc7500b | 128 | return ret; |
1da177e4 LT |
129 | } |
130 | ||
f7b3af64 BF |
131 | static int |
132 | checksummer(struct scatterlist *sg, void *data) | |
133 | { | |
3b5cf20c HX |
134 | struct ahash_request *req = data; |
135 | ||
136 | ahash_request_set_crypt(req, sg, NULL, sg->length); | |
f7b3af64 | 137 | |
3b5cf20c | 138 | return crypto_ahash_update(req); |
f7b3af64 BF |
139 | } |
140 | ||
fffdaef2 KC |
141 | static int |
142 | arcfour_hmac_md5_usage_to_salt(unsigned int usage, u8 salt[4]) | |
143 | { | |
144 | unsigned int ms_usage; | |
145 | ||
146 | switch (usage) { | |
147 | case KG_USAGE_SIGN: | |
148 | ms_usage = 15; | |
149 | break; | |
150 | case KG_USAGE_SEAL: | |
151 | ms_usage = 13; | |
152 | break; | |
153 | default: | |
f3c0ceea | 154 | return -EINVAL; |
fffdaef2 KC |
155 | } |
156 | salt[0] = (ms_usage >> 0) & 0xff; | |
157 | salt[1] = (ms_usage >> 8) & 0xff; | |
158 | salt[2] = (ms_usage >> 16) & 0xff; | |
159 | salt[3] = (ms_usage >> 24) & 0xff; | |
160 | ||
161 | return 0; | |
162 | } | |
163 | ||
164 | static u32 | |
165 | make_checksum_hmac_md5(struct krb5_ctx *kctx, char *header, int hdrlen, | |
166 | struct xdr_buf *body, int body_offset, u8 *cksumkey, | |
167 | unsigned int usage, struct xdr_netobj *cksumout) | |
168 | { | |
fffdaef2 | 169 | struct scatterlist sg[1]; |
2876a344 BF |
170 | int err = -1; |
171 | u8 *checksumdata; | |
44090cc8 | 172 | u8 *rc4salt; |
3b5cf20c HX |
173 | struct crypto_ahash *md5; |
174 | struct crypto_ahash *hmac_md5; | |
175 | struct ahash_request *req; | |
fffdaef2 KC |
176 | |
177 | if (cksumkey == NULL) | |
178 | return GSS_S_FAILURE; | |
179 | ||
180 | if (cksumout->len < kctx->gk5e->cksumlength) { | |
181 | dprintk("%s: checksum buffer length, %u, too small for %s\n", | |
182 | __func__, cksumout->len, kctx->gk5e->name); | |
183 | return GSS_S_FAILURE; | |
184 | } | |
185 | ||
44090cc8 LA |
186 | rc4salt = kmalloc_array(4, sizeof(*rc4salt), GFP_NOFS); |
187 | if (!rc4salt) | |
188 | return GSS_S_FAILURE; | |
189 | ||
fffdaef2 KC |
190 | if (arcfour_hmac_md5_usage_to_salt(usage, rc4salt)) { |
191 | dprintk("%s: invalid usage value %u\n", __func__, usage); | |
44090cc8 | 192 | goto out_free_rc4salt; |
fffdaef2 KC |
193 | } |
194 | ||
2876a344 BF |
195 | checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_NOFS); |
196 | if (!checksumdata) | |
44090cc8 | 197 | goto out_free_rc4salt; |
2876a344 | 198 | |
3b5cf20c | 199 | md5 = crypto_alloc_ahash("md5", 0, CRYPTO_ALG_ASYNC); |
fffdaef2 | 200 | if (IS_ERR(md5)) |
2876a344 | 201 | goto out_free_cksum; |
fffdaef2 | 202 | |
3b5cf20c HX |
203 | hmac_md5 = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0, |
204 | CRYPTO_ALG_ASYNC); | |
2876a344 BF |
205 | if (IS_ERR(hmac_md5)) |
206 | goto out_free_md5; | |
3b5cf20c | 207 | |
56094edd | 208 | req = ahash_request_alloc(md5, GFP_NOFS); |
2876a344 BF |
209 | if (!req) |
210 | goto out_free_hmac_md5; | |
fffdaef2 | 211 | |
3b5cf20c | 212 | ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); |
fffdaef2 | 213 | |
3b5cf20c | 214 | err = crypto_ahash_init(req); |
fffdaef2 KC |
215 | if (err) |
216 | goto out; | |
217 | sg_init_one(sg, rc4salt, 4); | |
3b5cf20c HX |
218 | ahash_request_set_crypt(req, sg, NULL, 4); |
219 | err = crypto_ahash_update(req); | |
fffdaef2 KC |
220 | if (err) |
221 | goto out; | |
222 | ||
223 | sg_init_one(sg, header, hdrlen); | |
3b5cf20c HX |
224 | ahash_request_set_crypt(req, sg, NULL, hdrlen); |
225 | err = crypto_ahash_update(req); | |
fffdaef2 KC |
226 | if (err) |
227 | goto out; | |
228 | err = xdr_process_buf(body, body_offset, body->len - body_offset, | |
3b5cf20c | 229 | checksummer, req); |
fffdaef2 KC |
230 | if (err) |
231 | goto out; | |
3b5cf20c HX |
232 | ahash_request_set_crypt(req, NULL, checksumdata, 0); |
233 | err = crypto_ahash_final(req); | |
fffdaef2 KC |
234 | if (err) |
235 | goto out; | |
236 | ||
3b5cf20c | 237 | ahash_request_free(req); |
56094edd | 238 | req = ahash_request_alloc(hmac_md5, GFP_NOFS); |
2876a344 BF |
239 | if (!req) |
240 | goto out_free_hmac_md5; | |
3b5cf20c HX |
241 | |
242 | ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); | |
fffdaef2 | 243 | |
3b5cf20c | 244 | err = crypto_ahash_setkey(hmac_md5, cksumkey, kctx->gk5e->keylength); |
fffdaef2 KC |
245 | if (err) |
246 | goto out; | |
247 | ||
3b5cf20c HX |
248 | sg_init_one(sg, checksumdata, crypto_ahash_digestsize(md5)); |
249 | ahash_request_set_crypt(req, sg, checksumdata, | |
250 | crypto_ahash_digestsize(md5)); | |
251 | err = crypto_ahash_digest(req); | |
fffdaef2 KC |
252 | if (err) |
253 | goto out; | |
254 | ||
255 | memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength); | |
256 | cksumout->len = kctx->gk5e->cksumlength; | |
257 | out: | |
3b5cf20c | 258 | ahash_request_free(req); |
2876a344 | 259 | out_free_hmac_md5: |
3b5cf20c | 260 | crypto_free_ahash(hmac_md5); |
2876a344 BF |
261 | out_free_md5: |
262 | crypto_free_ahash(md5); | |
263 | out_free_cksum: | |
264 | kfree(checksumdata); | |
44090cc8 LA |
265 | out_free_rc4salt: |
266 | kfree(rc4salt); | |
fffdaef2 KC |
267 | return err ? GSS_S_FAILURE : 0; |
268 | } | |
269 | ||
e1f6c07b KC |
270 | /* |
271 | * checksum the plaintext data and hdrlen bytes of the token header | |
272 | * The checksum is performed over the first 8 bytes of the | |
273 | * gss token header and then over the data body | |
274 | */ | |
275 | u32 | |
276 | make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen, | |
277 | struct xdr_buf *body, int body_offset, u8 *cksumkey, | |
8b237076 | 278 | unsigned int usage, struct xdr_netobj *cksumout) |
1da177e4 | 279 | { |
3b5cf20c HX |
280 | struct crypto_ahash *tfm; |
281 | struct ahash_request *req; | |
1da177e4 | 282 | struct scatterlist sg[1]; |
2876a344 BF |
283 | int err = -1; |
284 | u8 *checksumdata; | |
e1f6c07b KC |
285 | unsigned int checksumlen; |
286 | ||
fffdaef2 KC |
287 | if (kctx->gk5e->ctype == CKSUMTYPE_HMAC_MD5_ARCFOUR) |
288 | return make_checksum_hmac_md5(kctx, header, hdrlen, | |
289 | body, body_offset, | |
290 | cksumkey, usage, cksumout); | |
291 | ||
e1f6c07b KC |
292 | if (cksumout->len < kctx->gk5e->cksumlength) { |
293 | dprintk("%s: checksum buffer length, %u, too small for %s\n", | |
294 | __func__, cksumout->len, kctx->gk5e->name); | |
295 | return GSS_S_FAILURE; | |
296 | } | |
1da177e4 | 297 | |
2876a344 BF |
298 | checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_NOFS); |
299 | if (checksumdata == NULL) | |
300 | return GSS_S_FAILURE; | |
301 | ||
3b5cf20c HX |
302 | tfm = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC); |
303 | if (IS_ERR(tfm)) | |
2876a344 | 304 | goto out_free_cksum; |
1da177e4 | 305 | |
56094edd | 306 | req = ahash_request_alloc(tfm, GFP_NOFS); |
2876a344 BF |
307 | if (!req) |
308 | goto out_free_ahash; | |
3b5cf20c HX |
309 | |
310 | ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); | |
311 | ||
312 | checksumlen = crypto_ahash_digestsize(tfm); | |
e1f6c07b KC |
313 | |
314 | if (cksumkey != NULL) { | |
3b5cf20c HX |
315 | err = crypto_ahash_setkey(tfm, cksumkey, |
316 | kctx->gk5e->keylength); | |
e1f6c07b KC |
317 | if (err) |
318 | goto out; | |
319 | } | |
320 | ||
3b5cf20c | 321 | err = crypto_ahash_init(req); |
35058687 HX |
322 | if (err) |
323 | goto out; | |
68e3f5dd | 324 | sg_init_one(sg, header, hdrlen); |
3b5cf20c HX |
325 | ahash_request_set_crypt(req, sg, NULL, hdrlen); |
326 | err = crypto_ahash_update(req); | |
35058687 HX |
327 | if (err) |
328 | goto out; | |
37a4e6cb | 329 | err = xdr_process_buf(body, body_offset, body->len - body_offset, |
3b5cf20c | 330 | checksummer, req); |
35058687 HX |
331 | if (err) |
332 | goto out; | |
3b5cf20c HX |
333 | ahash_request_set_crypt(req, NULL, checksumdata, 0); |
334 | err = crypto_ahash_final(req); | |
e1f6c07b KC |
335 | if (err) |
336 | goto out; | |
35058687 | 337 | |
e1f6c07b KC |
338 | switch (kctx->gk5e->ctype) { |
339 | case CKSUMTYPE_RSA_MD5: | |
340 | err = kctx->gk5e->encrypt(kctx->seq, NULL, checksumdata, | |
341 | checksumdata, checksumlen); | |
342 | if (err) | |
343 | goto out; | |
344 | memcpy(cksumout->data, | |
345 | checksumdata + checksumlen - kctx->gk5e->cksumlength, | |
346 | kctx->gk5e->cksumlength); | |
347 | break; | |
958142e9 KC |
348 | case CKSUMTYPE_HMAC_SHA1_DES3: |
349 | memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength); | |
350 | break; | |
e1f6c07b KC |
351 | default: |
352 | BUG(); | |
353 | break; | |
354 | } | |
355 | cksumout->len = kctx->gk5e->cksumlength; | |
35058687 | 356 | out: |
3b5cf20c | 357 | ahash_request_free(req); |
2876a344 | 358 | out_free_ahash: |
3b5cf20c | 359 | crypto_free_ahash(tfm); |
2876a344 BF |
360 | out_free_cksum: |
361 | kfree(checksumdata); | |
35058687 | 362 | return err ? GSS_S_FAILURE : 0; |
1da177e4 LT |
363 | } |
364 | ||
de9c17eb KC |
365 | /* |
366 | * checksum the plaintext data and hdrlen bytes of the token header | |
367 | * Per rfc4121, sec. 4.2.4, the checksum is performed over the data | |
368 | * body then over the first 16 octets of the MIC token | |
369 | * Inclusion of the header data in the calculation of the | |
370 | * checksum is optional. | |
371 | */ | |
372 | u32 | |
373 | make_checksum_v2(struct krb5_ctx *kctx, char *header, int hdrlen, | |
374 | struct xdr_buf *body, int body_offset, u8 *cksumkey, | |
8b237076 | 375 | unsigned int usage, struct xdr_netobj *cksumout) |
de9c17eb | 376 | { |
3b5cf20c HX |
377 | struct crypto_ahash *tfm; |
378 | struct ahash_request *req; | |
de9c17eb | 379 | struct scatterlist sg[1]; |
2876a344 BF |
380 | int err = -1; |
381 | u8 *checksumdata; | |
de9c17eb KC |
382 | |
383 | if (kctx->gk5e->keyed_cksum == 0) { | |
384 | dprintk("%s: expected keyed hash for %s\n", | |
385 | __func__, kctx->gk5e->name); | |
386 | return GSS_S_FAILURE; | |
387 | } | |
388 | if (cksumkey == NULL) { | |
389 | dprintk("%s: no key supplied for %s\n", | |
390 | __func__, kctx->gk5e->name); | |
391 | return GSS_S_FAILURE; | |
392 | } | |
393 | ||
2876a344 BF |
394 | checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_NOFS); |
395 | if (!checksumdata) | |
396 | return GSS_S_FAILURE; | |
397 | ||
3b5cf20c HX |
398 | tfm = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC); |
399 | if (IS_ERR(tfm)) | |
2876a344 | 400 | goto out_free_cksum; |
3b5cf20c | 401 | |
56094edd | 402 | req = ahash_request_alloc(tfm, GFP_NOFS); |
2876a344 BF |
403 | if (!req) |
404 | goto out_free_ahash; | |
de9c17eb | 405 | |
3b5cf20c HX |
406 | ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); |
407 | ||
408 | err = crypto_ahash_setkey(tfm, cksumkey, kctx->gk5e->keylength); | |
de9c17eb KC |
409 | if (err) |
410 | goto out; | |
411 | ||
3b5cf20c | 412 | err = crypto_ahash_init(req); |
de9c17eb KC |
413 | if (err) |
414 | goto out; | |
415 | err = xdr_process_buf(body, body_offset, body->len - body_offset, | |
3b5cf20c | 416 | checksummer, req); |
de9c17eb KC |
417 | if (err) |
418 | goto out; | |
419 | if (header != NULL) { | |
420 | sg_init_one(sg, header, hdrlen); | |
3b5cf20c HX |
421 | ahash_request_set_crypt(req, sg, NULL, hdrlen); |
422 | err = crypto_ahash_update(req); | |
de9c17eb KC |
423 | if (err) |
424 | goto out; | |
425 | } | |
3b5cf20c HX |
426 | ahash_request_set_crypt(req, NULL, checksumdata, 0); |
427 | err = crypto_ahash_final(req); | |
de9c17eb KC |
428 | if (err) |
429 | goto out; | |
430 | ||
431 | cksumout->len = kctx->gk5e->cksumlength; | |
432 | ||
433 | switch (kctx->gk5e->ctype) { | |
434 | case CKSUMTYPE_HMAC_SHA1_96_AES128: | |
435 | case CKSUMTYPE_HMAC_SHA1_96_AES256: | |
436 | /* note that this truncates the hash */ | |
437 | memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength); | |
438 | break; | |
439 | default: | |
440 | BUG(); | |
441 | break; | |
442 | } | |
443 | out: | |
3b5cf20c | 444 | ahash_request_free(req); |
2876a344 | 445 | out_free_ahash: |
3b5cf20c | 446 | crypto_free_ahash(tfm); |
2876a344 BF |
447 | out_free_cksum: |
448 | kfree(checksumdata); | |
de9c17eb KC |
449 | return err ? GSS_S_FAILURE : 0; |
450 | } | |
451 | ||
14ae162c | 452 | struct encryptor_desc { |
81d4a433 | 453 | u8 iv[GSS_KRB5_MAX_BLOCKSIZE]; |
3b5cf20c | 454 | struct skcipher_request *req; |
14ae162c BF |
455 | int pos; |
456 | struct xdr_buf *outbuf; | |
457 | struct page **pages; | |
458 | struct scatterlist infrags[4]; | |
459 | struct scatterlist outfrags[4]; | |
460 | int fragno; | |
461 | int fraglen; | |
462 | }; | |
463 | ||
464 | static int | |
465 | encryptor(struct scatterlist *sg, void *data) | |
466 | { | |
467 | struct encryptor_desc *desc = data; | |
468 | struct xdr_buf *outbuf = desc->outbuf; | |
e9e575b8 KC |
469 | struct crypto_sync_skcipher *tfm = |
470 | crypto_sync_skcipher_reqtfm(desc->req); | |
14ae162c BF |
471 | struct page *in_page; |
472 | int thislen = desc->fraglen + sg->length; | |
473 | int fraglen, ret; | |
474 | int page_pos; | |
475 | ||
476 | /* Worst case is 4 fragments: head, end of page 1, start | |
477 | * of page 2, tail. Anything more is a bug. */ | |
478 | BUG_ON(desc->fragno > 3); | |
14ae162c BF |
479 | |
480 | page_pos = desc->pos - outbuf->head[0].iov_len; | |
481 | if (page_pos >= 0 && page_pos < outbuf->page_len) { | |
482 | /* pages are not in place: */ | |
09cbfeaf | 483 | int i = (page_pos + outbuf->page_base) >> PAGE_SHIFT; |
14ae162c BF |
484 | in_page = desc->pages[i]; |
485 | } else { | |
fa05f128 | 486 | in_page = sg_page(sg); |
14ae162c | 487 | } |
68e3f5dd HX |
488 | sg_set_page(&desc->infrags[desc->fragno], in_page, sg->length, |
489 | sg->offset); | |
490 | sg_set_page(&desc->outfrags[desc->fragno], sg_page(sg), sg->length, | |
491 | sg->offset); | |
14ae162c BF |
492 | desc->fragno++; |
493 | desc->fraglen += sg->length; | |
494 | desc->pos += sg->length; | |
495 | ||
e9e575b8 | 496 | fraglen = thislen & (crypto_sync_skcipher_blocksize(tfm) - 1); |
14ae162c BF |
497 | thislen -= fraglen; |
498 | ||
499 | if (thislen == 0) | |
500 | return 0; | |
501 | ||
c46f2334 JA |
502 | sg_mark_end(&desc->infrags[desc->fragno - 1]); |
503 | sg_mark_end(&desc->outfrags[desc->fragno - 1]); | |
68e3f5dd | 504 | |
3b5cf20c HX |
505 | skcipher_request_set_crypt(desc->req, desc->infrags, desc->outfrags, |
506 | thislen, desc->iv); | |
507 | ||
508 | ret = crypto_skcipher_encrypt(desc->req); | |
14ae162c BF |
509 | if (ret) |
510 | return ret; | |
68e3f5dd HX |
511 | |
512 | sg_init_table(desc->infrags, 4); | |
513 | sg_init_table(desc->outfrags, 4); | |
514 | ||
14ae162c | 515 | if (fraglen) { |
642f1490 JA |
516 | sg_set_page(&desc->outfrags[0], sg_page(sg), fraglen, |
517 | sg->offset + sg->length - fraglen); | |
14ae162c | 518 | desc->infrags[0] = desc->outfrags[0]; |
642f1490 | 519 | sg_assign_page(&desc->infrags[0], in_page); |
14ae162c BF |
520 | desc->fragno = 1; |
521 | desc->fraglen = fraglen; | |
522 | } else { | |
523 | desc->fragno = 0; | |
524 | desc->fraglen = 0; | |
525 | } | |
526 | return 0; | |
527 | } | |
528 | ||
529 | int | |
e9e575b8 | 530 | gss_encrypt_xdr_buf(struct crypto_sync_skcipher *tfm, struct xdr_buf *buf, |
378c6697 | 531 | int offset, struct page **pages) |
14ae162c BF |
532 | { |
533 | int ret; | |
534 | struct encryptor_desc desc; | |
e9e575b8 | 535 | SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); |
3b5cf20c | 536 | |
e9e575b8 | 537 | BUG_ON((buf->len - offset) % crypto_sync_skcipher_blocksize(tfm) != 0); |
14ae162c | 538 | |
e9e575b8 | 539 | skcipher_request_set_sync_tfm(req, tfm); |
3b5cf20c | 540 | skcipher_request_set_callback(req, 0, NULL, NULL); |
14ae162c BF |
541 | |
542 | memset(desc.iv, 0, sizeof(desc.iv)); | |
3b5cf20c | 543 | desc.req = req; |
14ae162c BF |
544 | desc.pos = offset; |
545 | desc.outbuf = buf; | |
546 | desc.pages = pages; | |
547 | desc.fragno = 0; | |
548 | desc.fraglen = 0; | |
549 | ||
68e3f5dd HX |
550 | sg_init_table(desc.infrags, 4); |
551 | sg_init_table(desc.outfrags, 4); | |
552 | ||
37a4e6cb | 553 | ret = xdr_process_buf(buf, offset, buf->len - offset, encryptor, &desc); |
3b5cf20c | 554 | skcipher_request_zero(req); |
14ae162c BF |
555 | return ret; |
556 | } | |
557 | ||
14ae162c | 558 | struct decryptor_desc { |
81d4a433 | 559 | u8 iv[GSS_KRB5_MAX_BLOCKSIZE]; |
3b5cf20c | 560 | struct skcipher_request *req; |
14ae162c BF |
561 | struct scatterlist frags[4]; |
562 | int fragno; | |
563 | int fraglen; | |
564 | }; | |
565 | ||
566 | static int | |
567 | decryptor(struct scatterlist *sg, void *data) | |
568 | { | |
569 | struct decryptor_desc *desc = data; | |
570 | int thislen = desc->fraglen + sg->length; | |
e9e575b8 KC |
571 | struct crypto_sync_skcipher *tfm = |
572 | crypto_sync_skcipher_reqtfm(desc->req); | |
14ae162c BF |
573 | int fraglen, ret; |
574 | ||
575 | /* Worst case is 4 fragments: head, end of page 1, start | |
576 | * of page 2, tail. Anything more is a bug. */ | |
577 | BUG_ON(desc->fragno > 3); | |
68e3f5dd HX |
578 | sg_set_page(&desc->frags[desc->fragno], sg_page(sg), sg->length, |
579 | sg->offset); | |
14ae162c BF |
580 | desc->fragno++; |
581 | desc->fraglen += sg->length; | |
582 | ||
e9e575b8 | 583 | fraglen = thislen & (crypto_sync_skcipher_blocksize(tfm) - 1); |
14ae162c BF |
584 | thislen -= fraglen; |
585 | ||
586 | if (thislen == 0) | |
587 | return 0; | |
588 | ||
c46f2334 | 589 | sg_mark_end(&desc->frags[desc->fragno - 1]); |
68e3f5dd | 590 | |
3b5cf20c HX |
591 | skcipher_request_set_crypt(desc->req, desc->frags, desc->frags, |
592 | thislen, desc->iv); | |
593 | ||
594 | ret = crypto_skcipher_decrypt(desc->req); | |
14ae162c BF |
595 | if (ret) |
596 | return ret; | |
68e3f5dd HX |
597 | |
598 | sg_init_table(desc->frags, 4); | |
599 | ||
14ae162c | 600 | if (fraglen) { |
642f1490 JA |
601 | sg_set_page(&desc->frags[0], sg_page(sg), fraglen, |
602 | sg->offset + sg->length - fraglen); | |
14ae162c BF |
603 | desc->fragno = 1; |
604 | desc->fraglen = fraglen; | |
605 | } else { | |
606 | desc->fragno = 0; | |
607 | desc->fraglen = 0; | |
608 | } | |
609 | return 0; | |
610 | } | |
611 | ||
612 | int | |
e9e575b8 | 613 | gss_decrypt_xdr_buf(struct crypto_sync_skcipher *tfm, struct xdr_buf *buf, |
378c6697 | 614 | int offset) |
14ae162c | 615 | { |
3b5cf20c | 616 | int ret; |
14ae162c | 617 | struct decryptor_desc desc; |
e9e575b8 | 618 | SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); |
14ae162c BF |
619 | |
620 | /* XXXJBF: */ | |
e9e575b8 | 621 | BUG_ON((buf->len - offset) % crypto_sync_skcipher_blocksize(tfm) != 0); |
3b5cf20c | 622 | |
e9e575b8 | 623 | skcipher_request_set_sync_tfm(req, tfm); |
3b5cf20c | 624 | skcipher_request_set_callback(req, 0, NULL, NULL); |
14ae162c BF |
625 | |
626 | memset(desc.iv, 0, sizeof(desc.iv)); | |
3b5cf20c | 627 | desc.req = req; |
14ae162c BF |
628 | desc.fragno = 0; |
629 | desc.fraglen = 0; | |
68e3f5dd HX |
630 | |
631 | sg_init_table(desc.frags, 4); | |
632 | ||
3b5cf20c HX |
633 | ret = xdr_process_buf(buf, offset, buf->len - offset, decryptor, &desc); |
634 | skcipher_request_zero(req); | |
635 | return ret; | |
14ae162c | 636 | } |
725f2865 KC |
637 | |
638 | /* | |
639 | * This function makes the assumption that it was ultimately called | |
640 | * from gss_wrap(). | |
641 | * | |
642 | * The client auth_gss code moves any existing tail data into a | |
643 | * separate page before calling gss_wrap. | |
644 | * The server svcauth_gss code ensures that both the head and the | |
645 | * tail have slack space of RPC_MAX_AUTH_SIZE before calling gss_wrap. | |
646 | * | |
647 | * Even with that guarantee, this function may be called more than | |
648 | * once in the processing of gss_wrap(). The best we can do is | |
649 | * verify at compile-time (see GSS_KRB5_SLACK_CHECK) that the | |
650 | * largest expected shift will fit within RPC_MAX_AUTH_SIZE. | |
651 | * At run-time we can verify that a single invocation of this | |
652 | * function doesn't attempt to use more the RPC_MAX_AUTH_SIZE. | |
653 | */ | |
654 | ||
655 | int | |
656 | xdr_extend_head(struct xdr_buf *buf, unsigned int base, unsigned int shiftlen) | |
657 | { | |
658 | u8 *p; | |
659 | ||
660 | if (shiftlen == 0) | |
661 | return 0; | |
662 | ||
663 | BUILD_BUG_ON(GSS_KRB5_MAX_SLACK_NEEDED > RPC_MAX_AUTH_SIZE); | |
664 | BUG_ON(shiftlen > RPC_MAX_AUTH_SIZE); | |
665 | ||
666 | p = buf->head[0].iov_base + base; | |
667 | ||
668 | memmove(p + shiftlen, p, buf->head[0].iov_len - base); | |
669 | ||
670 | buf->head[0].iov_len += shiftlen; | |
671 | buf->len += shiftlen; | |
672 | ||
673 | return 0; | |
674 | } | |
934a95aa KC |
675 | |
676 | static u32 | |
e9e575b8 | 677 | gss_krb5_cts_crypt(struct crypto_sync_skcipher *cipher, struct xdr_buf *buf, |
934a95aa KC |
678 | u32 offset, u8 *iv, struct page **pages, int encrypt) |
679 | { | |
680 | u32 ret; | |
681 | struct scatterlist sg[1]; | |
e9e575b8 | 682 | SYNC_SKCIPHER_REQUEST_ON_STACK(req, cipher); |
2876a344 | 683 | u8 *data; |
934a95aa KC |
684 | struct page **save_pages; |
685 | u32 len = buf->len - offset; | |
686 | ||
2876a344 | 687 | if (len > GSS_KRB5_MAX_BLOCKSIZE * 2) { |
0097143c TM |
688 | WARN_ON(0); |
689 | return -ENOMEM; | |
690 | } | |
2876a344 BF |
691 | data = kmalloc(GSS_KRB5_MAX_BLOCKSIZE * 2, GFP_NOFS); |
692 | if (!data) | |
693 | return -ENOMEM; | |
934a95aa KC |
694 | |
695 | /* | |
696 | * For encryption, we want to read from the cleartext | |
697 | * page cache pages, and write the encrypted data to | |
698 | * the supplied xdr_buf pages. | |
699 | */ | |
700 | save_pages = buf->pages; | |
701 | if (encrypt) | |
702 | buf->pages = pages; | |
703 | ||
704 | ret = read_bytes_from_xdr_buf(buf, offset, data, len); | |
705 | buf->pages = save_pages; | |
706 | if (ret) | |
707 | goto out; | |
708 | ||
709 | sg_init_one(sg, data, len); | |
710 | ||
e9e575b8 | 711 | skcipher_request_set_sync_tfm(req, cipher); |
3b5cf20c HX |
712 | skcipher_request_set_callback(req, 0, NULL, NULL); |
713 | skcipher_request_set_crypt(req, sg, sg, len, iv); | |
714 | ||
934a95aa | 715 | if (encrypt) |
3b5cf20c | 716 | ret = crypto_skcipher_encrypt(req); |
934a95aa | 717 | else |
3b5cf20c HX |
718 | ret = crypto_skcipher_decrypt(req); |
719 | ||
720 | skcipher_request_zero(req); | |
934a95aa KC |
721 | |
722 | if (ret) | |
723 | goto out; | |
724 | ||
725 | ret = write_bytes_to_xdr_buf(buf, offset, data, len); | |
726 | ||
727 | out: | |
2876a344 | 728 | kfree(data); |
934a95aa KC |
729 | return ret; |
730 | } | |
731 | ||
732 | u32 | |
733 | gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset, | |
ec25422c | 734 | struct xdr_buf *buf, struct page **pages) |
934a95aa KC |
735 | { |
736 | u32 err; | |
737 | struct xdr_netobj hmac; | |
738 | u8 *cksumkey; | |
739 | u8 *ecptr; | |
e9e575b8 | 740 | struct crypto_sync_skcipher *cipher, *aux_cipher; |
934a95aa KC |
741 | int blocksize; |
742 | struct page **save_pages; | |
743 | int nblocks, nbytes; | |
744 | struct encryptor_desc desc; | |
745 | u32 cbcbytes; | |
8b237076 | 746 | unsigned int usage; |
934a95aa KC |
747 | |
748 | if (kctx->initiate) { | |
749 | cipher = kctx->initiator_enc; | |
750 | aux_cipher = kctx->initiator_enc_aux; | |
751 | cksumkey = kctx->initiator_integ; | |
8b237076 | 752 | usage = KG_USAGE_INITIATOR_SEAL; |
934a95aa KC |
753 | } else { |
754 | cipher = kctx->acceptor_enc; | |
755 | aux_cipher = kctx->acceptor_enc_aux; | |
756 | cksumkey = kctx->acceptor_integ; | |
8b237076 | 757 | usage = KG_USAGE_ACCEPTOR_SEAL; |
934a95aa | 758 | } |
e9e575b8 | 759 | blocksize = crypto_sync_skcipher_blocksize(cipher); |
934a95aa KC |
760 | |
761 | /* hide the gss token header and insert the confounder */ | |
762 | offset += GSS_KRB5_TOK_HDR_LEN; | |
5af46547 | 763 | if (xdr_extend_head(buf, offset, kctx->gk5e->conflen)) |
934a95aa | 764 | return GSS_S_FAILURE; |
5af46547 | 765 | gss_krb5_make_confounder(buf->head[0].iov_base + offset, kctx->gk5e->conflen); |
934a95aa KC |
766 | offset -= GSS_KRB5_TOK_HDR_LEN; |
767 | ||
768 | if (buf->tail[0].iov_base != NULL) { | |
769 | ecptr = buf->tail[0].iov_base + buf->tail[0].iov_len; | |
770 | } else { | |
771 | buf->tail[0].iov_base = buf->head[0].iov_base | |
772 | + buf->head[0].iov_len; | |
773 | buf->tail[0].iov_len = 0; | |
774 | ecptr = buf->tail[0].iov_base; | |
775 | } | |
776 | ||
934a95aa | 777 | /* copy plaintext gss token header after filler (if any) */ |
ec25422c | 778 | memcpy(ecptr, buf->head[0].iov_base + offset, GSS_KRB5_TOK_HDR_LEN); |
934a95aa KC |
779 | buf->tail[0].iov_len += GSS_KRB5_TOK_HDR_LEN; |
780 | buf->len += GSS_KRB5_TOK_HDR_LEN; | |
781 | ||
782 | /* Do the HMAC */ | |
783 | hmac.len = GSS_KRB5_MAX_CKSUM_LEN; | |
784 | hmac.data = buf->tail[0].iov_base + buf->tail[0].iov_len; | |
785 | ||
786 | /* | |
787 | * When we are called, pages points to the real page cache | |
788 | * data -- which we can't go and encrypt! buf->pages points | |
789 | * to scratch pages which we are going to send off to the | |
790 | * client/server. Swap in the plaintext pages to calculate | |
791 | * the hmac. | |
792 | */ | |
793 | save_pages = buf->pages; | |
794 | buf->pages = pages; | |
795 | ||
796 | err = make_checksum_v2(kctx, NULL, 0, buf, | |
8b237076 KC |
797 | offset + GSS_KRB5_TOK_HDR_LEN, |
798 | cksumkey, usage, &hmac); | |
934a95aa KC |
799 | buf->pages = save_pages; |
800 | if (err) | |
801 | return GSS_S_FAILURE; | |
802 | ||
803 | nbytes = buf->len - offset - GSS_KRB5_TOK_HDR_LEN; | |
804 | nblocks = (nbytes + blocksize - 1) / blocksize; | |
805 | cbcbytes = 0; | |
806 | if (nblocks > 2) | |
807 | cbcbytes = (nblocks - 2) * blocksize; | |
808 | ||
809 | memset(desc.iv, 0, sizeof(desc.iv)); | |
810 | ||
811 | if (cbcbytes) { | |
e9e575b8 | 812 | SYNC_SKCIPHER_REQUEST_ON_STACK(req, aux_cipher); |
3b5cf20c | 813 | |
934a95aa KC |
814 | desc.pos = offset + GSS_KRB5_TOK_HDR_LEN; |
815 | desc.fragno = 0; | |
816 | desc.fraglen = 0; | |
817 | desc.pages = pages; | |
818 | desc.outbuf = buf; | |
3b5cf20c HX |
819 | desc.req = req; |
820 | ||
e9e575b8 | 821 | skcipher_request_set_sync_tfm(req, aux_cipher); |
3b5cf20c | 822 | skcipher_request_set_callback(req, 0, NULL, NULL); |
934a95aa KC |
823 | |
824 | sg_init_table(desc.infrags, 4); | |
825 | sg_init_table(desc.outfrags, 4); | |
826 | ||
827 | err = xdr_process_buf(buf, offset + GSS_KRB5_TOK_HDR_LEN, | |
828 | cbcbytes, encryptor, &desc); | |
3b5cf20c | 829 | skcipher_request_zero(req); |
934a95aa KC |
830 | if (err) |
831 | goto out_err; | |
832 | } | |
833 | ||
834 | /* Make sure IV carries forward from any CBC results. */ | |
835 | err = gss_krb5_cts_crypt(cipher, buf, | |
836 | offset + GSS_KRB5_TOK_HDR_LEN + cbcbytes, | |
837 | desc.iv, pages, 1); | |
838 | if (err) { | |
839 | err = GSS_S_FAILURE; | |
840 | goto out_err; | |
841 | } | |
842 | ||
843 | /* Now update buf to account for HMAC */ | |
844 | buf->tail[0].iov_len += kctx->gk5e->cksumlength; | |
845 | buf->len += kctx->gk5e->cksumlength; | |
846 | ||
847 | out_err: | |
848 | if (err) | |
849 | err = GSS_S_FAILURE; | |
850 | return err; | |
851 | } | |
852 | ||
853 | u32 | |
31c9590a CL |
854 | gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, u32 len, |
855 | struct xdr_buf *buf, u32 *headskip, u32 *tailskip) | |
934a95aa KC |
856 | { |
857 | struct xdr_buf subbuf; | |
858 | u32 ret = 0; | |
859 | u8 *cksum_key; | |
e9e575b8 | 860 | struct crypto_sync_skcipher *cipher, *aux_cipher; |
934a95aa KC |
861 | struct xdr_netobj our_hmac_obj; |
862 | u8 our_hmac[GSS_KRB5_MAX_CKSUM_LEN]; | |
863 | u8 pkt_hmac[GSS_KRB5_MAX_CKSUM_LEN]; | |
864 | int nblocks, blocksize, cbcbytes; | |
865 | struct decryptor_desc desc; | |
8b237076 | 866 | unsigned int usage; |
934a95aa KC |
867 | |
868 | if (kctx->initiate) { | |
869 | cipher = kctx->acceptor_enc; | |
870 | aux_cipher = kctx->acceptor_enc_aux; | |
871 | cksum_key = kctx->acceptor_integ; | |
8b237076 | 872 | usage = KG_USAGE_ACCEPTOR_SEAL; |
934a95aa KC |
873 | } else { |
874 | cipher = kctx->initiator_enc; | |
875 | aux_cipher = kctx->initiator_enc_aux; | |
876 | cksum_key = kctx->initiator_integ; | |
8b237076 | 877 | usage = KG_USAGE_INITIATOR_SEAL; |
934a95aa | 878 | } |
e9e575b8 | 879 | blocksize = crypto_sync_skcipher_blocksize(cipher); |
934a95aa KC |
880 | |
881 | ||
882 | /* create a segment skipping the header and leaving out the checksum */ | |
883 | xdr_buf_subsegment(buf, &subbuf, offset + GSS_KRB5_TOK_HDR_LEN, | |
31c9590a | 884 | (len - offset - GSS_KRB5_TOK_HDR_LEN - |
934a95aa KC |
885 | kctx->gk5e->cksumlength)); |
886 | ||
887 | nblocks = (subbuf.len + blocksize - 1) / blocksize; | |
888 | ||
889 | cbcbytes = 0; | |
890 | if (nblocks > 2) | |
891 | cbcbytes = (nblocks - 2) * blocksize; | |
892 | ||
893 | memset(desc.iv, 0, sizeof(desc.iv)); | |
894 | ||
895 | if (cbcbytes) { | |
e9e575b8 | 896 | SYNC_SKCIPHER_REQUEST_ON_STACK(req, aux_cipher); |
3b5cf20c | 897 | |
934a95aa KC |
898 | desc.fragno = 0; |
899 | desc.fraglen = 0; | |
3b5cf20c HX |
900 | desc.req = req; |
901 | ||
e9e575b8 | 902 | skcipher_request_set_sync_tfm(req, aux_cipher); |
3b5cf20c | 903 | skcipher_request_set_callback(req, 0, NULL, NULL); |
934a95aa KC |
904 | |
905 | sg_init_table(desc.frags, 4); | |
906 | ||
907 | ret = xdr_process_buf(&subbuf, 0, cbcbytes, decryptor, &desc); | |
3b5cf20c | 908 | skcipher_request_zero(req); |
934a95aa KC |
909 | if (ret) |
910 | goto out_err; | |
911 | } | |
912 | ||
913 | /* Make sure IV carries forward from any CBC results. */ | |
914 | ret = gss_krb5_cts_crypt(cipher, &subbuf, cbcbytes, desc.iv, NULL, 0); | |
915 | if (ret) | |
916 | goto out_err; | |
917 | ||
918 | ||
919 | /* Calculate our hmac over the plaintext data */ | |
920 | our_hmac_obj.len = sizeof(our_hmac); | |
921 | our_hmac_obj.data = our_hmac; | |
922 | ||
923 | ret = make_checksum_v2(kctx, NULL, 0, &subbuf, 0, | |
8b237076 | 924 | cksum_key, usage, &our_hmac_obj); |
934a95aa KC |
925 | if (ret) |
926 | goto out_err; | |
927 | ||
928 | /* Get the packet's hmac value */ | |
31c9590a | 929 | ret = read_bytes_from_xdr_buf(buf, len - kctx->gk5e->cksumlength, |
934a95aa KC |
930 | pkt_hmac, kctx->gk5e->cksumlength); |
931 | if (ret) | |
932 | goto out_err; | |
933 | ||
15a8b93f | 934 | if (crypto_memneq(pkt_hmac, our_hmac, kctx->gk5e->cksumlength) != 0) { |
934a95aa KC |
935 | ret = GSS_S_BAD_SIG; |
936 | goto out_err; | |
937 | } | |
5af46547 | 938 | *headskip = kctx->gk5e->conflen; |
934a95aa KC |
939 | *tailskip = kctx->gk5e->cksumlength; |
940 | out_err: | |
941 | if (ret && ret != GSS_S_BAD_SIG) | |
942 | ret = GSS_S_FAILURE; | |
943 | return ret; | |
944 | } | |
fffdaef2 KC |
945 | |
946 | /* | |
947 | * Compute Kseq given the initial session key and the checksum. | |
948 | * Set the key of the given cipher. | |
949 | */ | |
950 | int | |
e9e575b8 KC |
951 | krb5_rc4_setup_seq_key(struct krb5_ctx *kctx, |
952 | struct crypto_sync_skcipher *cipher, | |
fffdaef2 KC |
953 | unsigned char *cksum) |
954 | { | |
3b5cf20c HX |
955 | struct crypto_shash *hmac; |
956 | struct shash_desc *desc; | |
fffdaef2 KC |
957 | u8 Kseq[GSS_KRB5_MAX_KEYLEN]; |
958 | u32 zeroconstant = 0; | |
959 | int err; | |
960 | ||
961 | dprintk("%s: entered\n", __func__); | |
962 | ||
3b5cf20c | 963 | hmac = crypto_alloc_shash(kctx->gk5e->cksum_name, 0, 0); |
fffdaef2 KC |
964 | if (IS_ERR(hmac)) { |
965 | dprintk("%s: error %ld, allocating hash '%s'\n", | |
966 | __func__, PTR_ERR(hmac), kctx->gk5e->cksum_name); | |
967 | return PTR_ERR(hmac); | |
968 | } | |
969 | ||
ef609c23 | 970 | desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac), |
56094edd | 971 | GFP_NOFS); |
3b5cf20c HX |
972 | if (!desc) { |
973 | dprintk("%s: failed to allocate shash descriptor for '%s'\n", | |
974 | __func__, kctx->gk5e->cksum_name); | |
975 | crypto_free_shash(hmac); | |
976 | return -ENOMEM; | |
977 | } | |
fffdaef2 | 978 | |
3b5cf20c | 979 | desc->tfm = hmac; |
fffdaef2 KC |
980 | |
981 | /* Compute intermediate Kseq from session key */ | |
3b5cf20c | 982 | err = crypto_shash_setkey(hmac, kctx->Ksess, kctx->gk5e->keylength); |
fffdaef2 KC |
983 | if (err) |
984 | goto out_err; | |
985 | ||
3b5cf20c | 986 | err = crypto_shash_digest(desc, (u8 *)&zeroconstant, 4, Kseq); |
fffdaef2 KC |
987 | if (err) |
988 | goto out_err; | |
989 | ||
990 | /* Compute final Kseq from the checksum and intermediate Kseq */ | |
3b5cf20c | 991 | err = crypto_shash_setkey(hmac, Kseq, kctx->gk5e->keylength); |
fffdaef2 KC |
992 | if (err) |
993 | goto out_err; | |
994 | ||
3b5cf20c | 995 | err = crypto_shash_digest(desc, cksum, 8, Kseq); |
fffdaef2 KC |
996 | if (err) |
997 | goto out_err; | |
998 | ||
e9e575b8 | 999 | err = crypto_sync_skcipher_setkey(cipher, Kseq, kctx->gk5e->keylength); |
fffdaef2 KC |
1000 | if (err) |
1001 | goto out_err; | |
1002 | ||
1003 | err = 0; | |
1004 | ||
1005 | out_err: | |
3b5cf20c HX |
1006 | kzfree(desc); |
1007 | crypto_free_shash(hmac); | |
fffdaef2 KC |
1008 | dprintk("%s: returning %d\n", __func__, err); |
1009 | return err; | |
1010 | } | |
1011 | ||
1012 | /* | |
1013 | * Compute Kcrypt given the initial session key and the plaintext seqnum. | |
1014 | * Set the key of cipher kctx->enc. | |
1015 | */ | |
1016 | int | |
e9e575b8 KC |
1017 | krb5_rc4_setup_enc_key(struct krb5_ctx *kctx, |
1018 | struct crypto_sync_skcipher *cipher, | |
fffdaef2 KC |
1019 | s32 seqnum) |
1020 | { | |
3b5cf20c HX |
1021 | struct crypto_shash *hmac; |
1022 | struct shash_desc *desc; | |
fffdaef2 KC |
1023 | u8 Kcrypt[GSS_KRB5_MAX_KEYLEN]; |
1024 | u8 zeroconstant[4] = {0}; | |
1025 | u8 seqnumarray[4]; | |
1026 | int err, i; | |
1027 | ||
1028 | dprintk("%s: entered, seqnum %u\n", __func__, seqnum); | |
1029 | ||
3b5cf20c | 1030 | hmac = crypto_alloc_shash(kctx->gk5e->cksum_name, 0, 0); |
fffdaef2 KC |
1031 | if (IS_ERR(hmac)) { |
1032 | dprintk("%s: error %ld, allocating hash '%s'\n", | |
1033 | __func__, PTR_ERR(hmac), kctx->gk5e->cksum_name); | |
1034 | return PTR_ERR(hmac); | |
1035 | } | |
1036 | ||
ef609c23 | 1037 | desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac), |
56094edd | 1038 | GFP_NOFS); |
3b5cf20c HX |
1039 | if (!desc) { |
1040 | dprintk("%s: failed to allocate shash descriptor for '%s'\n", | |
1041 | __func__, kctx->gk5e->cksum_name); | |
1042 | crypto_free_shash(hmac); | |
1043 | return -ENOMEM; | |
1044 | } | |
fffdaef2 | 1045 | |
3b5cf20c | 1046 | desc->tfm = hmac; |
fffdaef2 KC |
1047 | |
1048 | /* Compute intermediate Kcrypt from session key */ | |
1049 | for (i = 0; i < kctx->gk5e->keylength; i++) | |
1050 | Kcrypt[i] = kctx->Ksess[i] ^ 0xf0; | |
1051 | ||
3b5cf20c | 1052 | err = crypto_shash_setkey(hmac, Kcrypt, kctx->gk5e->keylength); |
fffdaef2 KC |
1053 | if (err) |
1054 | goto out_err; | |
1055 | ||
3b5cf20c | 1056 | err = crypto_shash_digest(desc, zeroconstant, 4, Kcrypt); |
fffdaef2 KC |
1057 | if (err) |
1058 | goto out_err; | |
1059 | ||
1060 | /* Compute final Kcrypt from the seqnum and intermediate Kcrypt */ | |
3b5cf20c | 1061 | err = crypto_shash_setkey(hmac, Kcrypt, kctx->gk5e->keylength); |
fffdaef2 KC |
1062 | if (err) |
1063 | goto out_err; | |
1064 | ||
1065 | seqnumarray[0] = (unsigned char) ((seqnum >> 24) & 0xff); | |
1066 | seqnumarray[1] = (unsigned char) ((seqnum >> 16) & 0xff); | |
1067 | seqnumarray[2] = (unsigned char) ((seqnum >> 8) & 0xff); | |
1068 | seqnumarray[3] = (unsigned char) ((seqnum >> 0) & 0xff); | |
1069 | ||
3b5cf20c | 1070 | err = crypto_shash_digest(desc, seqnumarray, 4, Kcrypt); |
fffdaef2 KC |
1071 | if (err) |
1072 | goto out_err; | |
1073 | ||
e9e575b8 KC |
1074 | err = crypto_sync_skcipher_setkey(cipher, Kcrypt, |
1075 | kctx->gk5e->keylength); | |
fffdaef2 KC |
1076 | if (err) |
1077 | goto out_err; | |
1078 | ||
1079 | err = 0; | |
1080 | ||
1081 | out_err: | |
3b5cf20c HX |
1082 | kzfree(desc); |
1083 | crypto_free_shash(hmac); | |
fffdaef2 KC |
1084 | dprintk("%s: returning %d\n", __func__, err); |
1085 | return err; | |
1086 | } |