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