Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/net/sunrpc/gss_krb5_mech.c | |
3 | * | |
81d4a433 | 4 | * Copyright (c) 2001-2008 The Regents of the University of Michigan. |
1da177e4 LT |
5 | * All rights reserved. |
6 | * | |
7 | * Andy Adamson <andros@umich.edu> | |
8 | * J. Bruce Fields <bfields@umich.edu> | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | |
13 | * | |
14 | * 1. Redistributions of source code must retain the above copyright | |
15 | * notice, this list of conditions and the following disclaimer. | |
16 | * 2. Redistributions in binary form must reproduce the above copyright | |
17 | * notice, this list of conditions and the following disclaimer in the | |
18 | * documentation and/or other materials provided with the distribution. | |
19 | * 3. Neither the name of the University nor the names of its | |
20 | * contributors may be used to endorse or promote products derived | |
21 | * from this software without specific prior written permission. | |
22 | * | |
23 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
24 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
25 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
26 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | |
30 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
31 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
32 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
33 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
34 | * | |
35 | */ | |
36 | ||
378c6697 | 37 | #include <linux/err.h> |
1da177e4 LT |
38 | #include <linux/module.h> |
39 | #include <linux/init.h> | |
40 | #include <linux/types.h> | |
41 | #include <linux/slab.h> | |
42 | #include <linux/sunrpc/auth.h> | |
1da177e4 LT |
43 | #include <linux/sunrpc/gss_krb5.h> |
44 | #include <linux/sunrpc/xdr.h> | |
45 | #include <linux/crypto.h> | |
b084f598 | 46 | #include <linux/sunrpc/gss_krb5_enctypes.h> |
1da177e4 LT |
47 | |
48 | #ifdef RPC_DEBUG | |
49 | # define RPCDBG_FACILITY RPCDBG_AUTH | |
50 | #endif | |
51 | ||
47d84807 KC |
52 | static struct gss_api_mech gss_kerberos_mech; /* forward declaration */ |
53 | ||
81d4a433 KC |
54 | static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = { |
55 | /* | |
56 | * DES (All DES enctypes are mapped to the same gss functionality) | |
57 | */ | |
58 | { | |
59 | .etype = ENCTYPE_DES_CBC_RAW, | |
60 | .ctype = CKSUMTYPE_RSA_MD5, | |
61 | .name = "des-cbc-crc", | |
62 | .encrypt_name = "cbc(des)", | |
63 | .cksum_name = "md5", | |
64 | .encrypt = krb5_encrypt, | |
65 | .decrypt = krb5_decrypt, | |
4891f2d0 | 66 | .mk_key = NULL, |
81d4a433 KC |
67 | .signalg = SGN_ALG_DES_MAC_MD5, |
68 | .sealalg = SEAL_ALG_DES, | |
69 | .keybytes = 7, | |
70 | .keylength = 8, | |
71 | .blocksize = 8, | |
5af46547 | 72 | .conflen = 8, |
81d4a433 | 73 | .cksumlength = 8, |
e1f6c07b | 74 | .keyed_cksum = 0, |
81d4a433 | 75 | }, |
fffdaef2 KC |
76 | /* |
77 | * RC4-HMAC | |
78 | */ | |
79 | { | |
80 | .etype = ENCTYPE_ARCFOUR_HMAC, | |
81 | .ctype = CKSUMTYPE_HMAC_MD5_ARCFOUR, | |
82 | .name = "rc4-hmac", | |
83 | .encrypt_name = "ecb(arc4)", | |
84 | .cksum_name = "hmac(md5)", | |
85 | .encrypt = krb5_encrypt, | |
86 | .decrypt = krb5_decrypt, | |
87 | .mk_key = NULL, | |
88 | .signalg = SGN_ALG_HMAC_MD5, | |
89 | .sealalg = SEAL_ALG_MICROSOFT_RC4, | |
90 | .keybytes = 16, | |
91 | .keylength = 16, | |
92 | .blocksize = 1, | |
93 | .conflen = 8, | |
94 | .cksumlength = 8, | |
95 | .keyed_cksum = 1, | |
96 | }, | |
958142e9 KC |
97 | /* |
98 | * 3DES | |
99 | */ | |
100 | { | |
101 | .etype = ENCTYPE_DES3_CBC_RAW, | |
102 | .ctype = CKSUMTYPE_HMAC_SHA1_DES3, | |
103 | .name = "des3-hmac-sha1", | |
104 | .encrypt_name = "cbc(des3_ede)", | |
105 | .cksum_name = "hmac(sha1)", | |
106 | .encrypt = krb5_encrypt, | |
107 | .decrypt = krb5_decrypt, | |
108 | .mk_key = gss_krb5_des3_make_key, | |
109 | .signalg = SGN_ALG_HMAC_SHA1_DES3_KD, | |
110 | .sealalg = SEAL_ALG_DES3KD, | |
111 | .keybytes = 21, | |
112 | .keylength = 24, | |
113 | .blocksize = 8, | |
5af46547 | 114 | .conflen = 8, |
958142e9 KC |
115 | .cksumlength = 20, |
116 | .keyed_cksum = 1, | |
117 | }, | |
934a95aa KC |
118 | /* |
119 | * AES128 | |
120 | */ | |
121 | { | |
122 | .etype = ENCTYPE_AES128_CTS_HMAC_SHA1_96, | |
123 | .ctype = CKSUMTYPE_HMAC_SHA1_96_AES128, | |
124 | .name = "aes128-cts", | |
125 | .encrypt_name = "cts(cbc(aes))", | |
126 | .cksum_name = "hmac(sha1)", | |
127 | .encrypt = krb5_encrypt, | |
128 | .decrypt = krb5_decrypt, | |
129 | .mk_key = gss_krb5_aes_make_key, | |
130 | .encrypt_v2 = gss_krb5_aes_encrypt, | |
131 | .decrypt_v2 = gss_krb5_aes_decrypt, | |
132 | .signalg = -1, | |
133 | .sealalg = -1, | |
134 | .keybytes = 16, | |
135 | .keylength = 16, | |
136 | .blocksize = 16, | |
5af46547 | 137 | .conflen = 16, |
934a95aa KC |
138 | .cksumlength = 12, |
139 | .keyed_cksum = 1, | |
140 | }, | |
141 | /* | |
142 | * AES256 | |
143 | */ | |
144 | { | |
145 | .etype = ENCTYPE_AES256_CTS_HMAC_SHA1_96, | |
146 | .ctype = CKSUMTYPE_HMAC_SHA1_96_AES256, | |
147 | .name = "aes256-cts", | |
148 | .encrypt_name = "cts(cbc(aes))", | |
149 | .cksum_name = "hmac(sha1)", | |
150 | .encrypt = krb5_encrypt, | |
151 | .decrypt = krb5_decrypt, | |
152 | .mk_key = gss_krb5_aes_make_key, | |
153 | .encrypt_v2 = gss_krb5_aes_encrypt, | |
154 | .decrypt_v2 = gss_krb5_aes_decrypt, | |
155 | .signalg = -1, | |
156 | .sealalg = -1, | |
157 | .keybytes = 32, | |
158 | .keylength = 32, | |
159 | .blocksize = 16, | |
5af46547 | 160 | .conflen = 16, |
934a95aa KC |
161 | .cksumlength = 12, |
162 | .keyed_cksum = 1, | |
163 | }, | |
81d4a433 KC |
164 | }; |
165 | ||
166 | static const int num_supported_enctypes = | |
167 | ARRAY_SIZE(supported_gss_krb5_enctypes); | |
168 | ||
169 | static int | |
170 | supported_gss_krb5_enctype(int etype) | |
171 | { | |
172 | int i; | |
173 | for (i = 0; i < num_supported_enctypes; i++) | |
174 | if (supported_gss_krb5_enctypes[i].etype == etype) | |
175 | return 1; | |
176 | return 0; | |
177 | } | |
178 | ||
179 | static const struct gss_krb5_enctype * | |
180 | get_gss_krb5_enctype(int etype) | |
181 | { | |
182 | int i; | |
183 | for (i = 0; i < num_supported_enctypes; i++) | |
184 | if (supported_gss_krb5_enctypes[i].etype == etype) | |
185 | return &supported_gss_krb5_enctypes[i]; | |
186 | return NULL; | |
187 | } | |
188 | ||
1da177e4 LT |
189 | static const void * |
190 | simple_get_bytes(const void *p, const void *end, void *res, int len) | |
191 | { | |
192 | const void *q = (const void *)((const char *)p + len); | |
193 | if (unlikely(q > end || q < p)) | |
194 | return ERR_PTR(-EFAULT); | |
195 | memcpy(res, p, len); | |
196 | return q; | |
197 | } | |
198 | ||
199 | static const void * | |
200 | simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res) | |
201 | { | |
202 | const void *q; | |
203 | unsigned int len; | |
204 | ||
205 | p = simple_get_bytes(p, end, &len, sizeof(len)); | |
206 | if (IS_ERR(p)) | |
207 | return p; | |
208 | q = (const void *)((const char *)p + len); | |
209 | if (unlikely(q > end || q < p)) | |
210 | return ERR_PTR(-EFAULT); | |
0f38b873 | 211 | res->data = kmemdup(p, len, GFP_NOFS); |
1da177e4 LT |
212 | if (unlikely(res->data == NULL)) |
213 | return ERR_PTR(-ENOMEM); | |
1da177e4 LT |
214 | res->len = len; |
215 | return q; | |
216 | } | |
217 | ||
218 | static inline const void * | |
81d4a433 KC |
219 | get_key(const void *p, const void *end, |
220 | struct krb5_ctx *ctx, struct crypto_blkcipher **res) | |
1da177e4 LT |
221 | { |
222 | struct xdr_netobj key; | |
378c6697 | 223 | int alg; |
1da177e4 LT |
224 | |
225 | p = simple_get_bytes(p, end, &alg, sizeof(alg)); | |
226 | if (IS_ERR(p)) | |
227 | goto out_err; | |
81d4a433 KC |
228 | |
229 | switch (alg) { | |
230 | case ENCTYPE_DES_CBC_CRC: | |
231 | case ENCTYPE_DES_CBC_MD4: | |
232 | case ENCTYPE_DES_CBC_MD5: | |
233 | /* Map all these key types to ENCTYPE_DES_CBC_RAW */ | |
234 | alg = ENCTYPE_DES_CBC_RAW; | |
235 | break; | |
236 | } | |
237 | ||
238 | if (!supported_gss_krb5_enctype(alg)) { | |
239 | printk(KERN_WARNING "gss_kerberos_mech: unsupported " | |
240 | "encryption key algorithm %d\n", alg); | |
ce8477e1 | 241 | p = ERR_PTR(-EINVAL); |
81d4a433 KC |
242 | goto out_err; |
243 | } | |
1da177e4 LT |
244 | p = simple_get_netobj(p, end, &key); |
245 | if (IS_ERR(p)) | |
246 | goto out_err; | |
247 | ||
81d4a433 KC |
248 | *res = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name, 0, |
249 | CRYPTO_ALG_ASYNC); | |
378c6697 | 250 | if (IS_ERR(*res)) { |
81d4a433 KC |
251 | printk(KERN_WARNING "gss_kerberos_mech: unable to initialize " |
252 | "crypto algorithm %s\n", ctx->gk5e->encrypt_name); | |
378c6697 | 253 | *res = NULL; |
1da177e4 | 254 | goto out_err_free_key; |
9e56904e | 255 | } |
378c6697 | 256 | if (crypto_blkcipher_setkey(*res, key.data, key.len)) { |
81d4a433 KC |
257 | printk(KERN_WARNING "gss_kerberos_mech: error setting key for " |
258 | "crypto algorithm %s\n", ctx->gk5e->encrypt_name); | |
1da177e4 | 259 | goto out_err_free_tfm; |
9e56904e | 260 | } |
1da177e4 LT |
261 | |
262 | kfree(key.data); | |
263 | return p; | |
264 | ||
265 | out_err_free_tfm: | |
378c6697 | 266 | crypto_free_blkcipher(*res); |
1da177e4 LT |
267 | out_err_free_key: |
268 | kfree(key.data); | |
269 | p = ERR_PTR(-EINVAL); | |
270 | out_err: | |
271 | return p; | |
272 | } | |
273 | ||
274 | static int | |
a8cc1cb7 | 275 | gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx) |
1da177e4 | 276 | { |
e678e06b | 277 | int tmp; |
1da177e4 | 278 | |
1da177e4 LT |
279 | p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate)); |
280 | if (IS_ERR(p)) | |
a8cc1cb7 KC |
281 | goto out_err; |
282 | ||
283 | /* Old format supports only DES! Any other enctype uses new format */ | |
1ac3719a | 284 | ctx->enctype = ENCTYPE_DES_CBC_RAW; |
a8cc1cb7 | 285 | |
81d4a433 | 286 | ctx->gk5e = get_gss_krb5_enctype(ctx->enctype); |
ce8477e1 BN |
287 | if (ctx->gk5e == NULL) { |
288 | p = ERR_PTR(-EINVAL); | |
81d4a433 | 289 | goto out_err; |
ce8477e1 | 290 | } |
81d4a433 | 291 | |
717757ad BF |
292 | /* The downcall format was designed before we completely understood |
293 | * the uses of the context fields; so it includes some stuff we | |
294 | * just give some minimal sanity-checking, and some we ignore | |
295 | * completely (like the next twenty bytes): */ | |
ce8477e1 BN |
296 | if (unlikely(p + 20 > end || p + 20 < p)) { |
297 | p = ERR_PTR(-EFAULT); | |
a8cc1cb7 | 298 | goto out_err; |
ce8477e1 | 299 | } |
717757ad | 300 | p += 20; |
e678e06b | 301 | p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); |
1da177e4 | 302 | if (IS_ERR(p)) |
a8cc1cb7 | 303 | goto out_err; |
ef338bee KC |
304 | if (tmp != SGN_ALG_DES_MAC_MD5) { |
305 | p = ERR_PTR(-ENOSYS); | |
a8cc1cb7 | 306 | goto out_err; |
ef338bee | 307 | } |
d922a84a | 308 | p = simple_get_bytes(p, end, &tmp, sizeof(tmp)); |
1da177e4 | 309 | if (IS_ERR(p)) |
a8cc1cb7 | 310 | goto out_err; |
ef338bee KC |
311 | if (tmp != SEAL_ALG_DES) { |
312 | p = ERR_PTR(-ENOSYS); | |
a8cc1cb7 | 313 | goto out_err; |
ef338bee | 314 | } |
1da177e4 LT |
315 | p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); |
316 | if (IS_ERR(p)) | |
a8cc1cb7 | 317 | goto out_err; |
1da177e4 LT |
318 | p = simple_get_bytes(p, end, &ctx->seq_send, sizeof(ctx->seq_send)); |
319 | if (IS_ERR(p)) | |
a8cc1cb7 | 320 | goto out_err; |
1da177e4 LT |
321 | p = simple_get_netobj(p, end, &ctx->mech_used); |
322 | if (IS_ERR(p)) | |
a8cc1cb7 | 323 | goto out_err; |
81d4a433 | 324 | p = get_key(p, end, ctx, &ctx->enc); |
1da177e4 LT |
325 | if (IS_ERR(p)) |
326 | goto out_err_free_mech; | |
81d4a433 | 327 | p = get_key(p, end, ctx, &ctx->seq); |
1da177e4 LT |
328 | if (IS_ERR(p)) |
329 | goto out_err_free_key1; | |
330 | if (p != end) { | |
331 | p = ERR_PTR(-EFAULT); | |
332 | goto out_err_free_key2; | |
333 | } | |
334 | ||
1da177e4 LT |
335 | return 0; |
336 | ||
337 | out_err_free_key2: | |
378c6697 | 338 | crypto_free_blkcipher(ctx->seq); |
1da177e4 | 339 | out_err_free_key1: |
378c6697 | 340 | crypto_free_blkcipher(ctx->enc); |
1da177e4 LT |
341 | out_err_free_mech: |
342 | kfree(ctx->mech_used.data); | |
1da177e4 LT |
343 | out_err: |
344 | return PTR_ERR(p); | |
345 | } | |
346 | ||
09acfea5 | 347 | static struct crypto_blkcipher * |
934a95aa | 348 | context_v2_alloc_cipher(struct krb5_ctx *ctx, const char *cname, u8 *key) |
47d84807 KC |
349 | { |
350 | struct crypto_blkcipher *cp; | |
351 | ||
934a95aa | 352 | cp = crypto_alloc_blkcipher(cname, 0, CRYPTO_ALG_ASYNC); |
47d84807 KC |
353 | if (IS_ERR(cp)) { |
354 | dprintk("gss_kerberos_mech: unable to initialize " | |
934a95aa | 355 | "crypto algorithm %s\n", cname); |
47d84807 KC |
356 | return NULL; |
357 | } | |
358 | if (crypto_blkcipher_setkey(cp, key, ctx->gk5e->keylength)) { | |
359 | dprintk("gss_kerberos_mech: error setting key for " | |
934a95aa | 360 | "crypto algorithm %s\n", cname); |
47d84807 KC |
361 | crypto_free_blkcipher(cp); |
362 | return NULL; | |
363 | } | |
364 | return cp; | |
365 | } | |
366 | ||
367 | static inline void | |
368 | set_cdata(u8 cdata[GSS_KRB5_K5CLENGTH], u32 usage, u8 seed) | |
369 | { | |
370 | cdata[0] = (usage>>24)&0xff; | |
371 | cdata[1] = (usage>>16)&0xff; | |
372 | cdata[2] = (usage>>8)&0xff; | |
373 | cdata[3] = usage&0xff; | |
374 | cdata[4] = seed; | |
375 | } | |
376 | ||
377 | static int | |
1f4c86c0 | 378 | context_derive_keys_des3(struct krb5_ctx *ctx, gfp_t gfp_mask) |
47d84807 KC |
379 | { |
380 | struct xdr_netobj c, keyin, keyout; | |
381 | u8 cdata[GSS_KRB5_K5CLENGTH]; | |
382 | u32 err; | |
383 | ||
384 | c.len = GSS_KRB5_K5CLENGTH; | |
385 | c.data = cdata; | |
386 | ||
fc263a91 KC |
387 | keyin.data = ctx->Ksess; |
388 | keyin.len = ctx->gk5e->keylength; | |
389 | keyout.len = ctx->gk5e->keylength; | |
47d84807 KC |
390 | |
391 | /* seq uses the raw key */ | |
934a95aa | 392 | ctx->seq = context_v2_alloc_cipher(ctx, ctx->gk5e->encrypt_name, |
fc263a91 | 393 | ctx->Ksess); |
47d84807 KC |
394 | if (ctx->seq == NULL) |
395 | goto out_err; | |
396 | ||
934a95aa | 397 | ctx->enc = context_v2_alloc_cipher(ctx, ctx->gk5e->encrypt_name, |
fc263a91 | 398 | ctx->Ksess); |
47d84807 KC |
399 | if (ctx->enc == NULL) |
400 | goto out_free_seq; | |
401 | ||
402 | /* derive cksum */ | |
403 | set_cdata(cdata, KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM); | |
404 | keyout.data = ctx->cksum; | |
1f4c86c0 | 405 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); |
47d84807 KC |
406 | if (err) { |
407 | dprintk("%s: Error %d deriving cksum key\n", | |
408 | __func__, err); | |
409 | goto out_free_enc; | |
410 | } | |
411 | ||
412 | return 0; | |
413 | ||
414 | out_free_enc: | |
415 | crypto_free_blkcipher(ctx->enc); | |
416 | out_free_seq: | |
417 | crypto_free_blkcipher(ctx->seq); | |
418 | out_err: | |
419 | return -EINVAL; | |
420 | } | |
421 | ||
fffdaef2 KC |
422 | /* |
423 | * Note that RC4 depends on deriving keys using the sequence | |
424 | * number or the checksum of a token. Therefore, the final keys | |
425 | * cannot be calculated until the token is being constructed! | |
426 | */ | |
427 | static int | |
428 | context_derive_keys_rc4(struct krb5_ctx *ctx) | |
429 | { | |
430 | struct crypto_hash *hmac; | |
0867659f | 431 | char sigkeyconstant[] = "signaturekey"; |
fffdaef2 KC |
432 | int slen = strlen(sigkeyconstant) + 1; /* include null terminator */ |
433 | struct hash_desc desc; | |
434 | struct scatterlist sg[1]; | |
435 | int err; | |
436 | ||
437 | dprintk("RPC: %s: entered\n", __func__); | |
438 | /* | |
439 | * derive cksum (aka Ksign) key | |
440 | */ | |
441 | hmac = crypto_alloc_hash(ctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC); | |
442 | if (IS_ERR(hmac)) { | |
443 | dprintk("%s: error %ld allocating hash '%s'\n", | |
444 | __func__, PTR_ERR(hmac), ctx->gk5e->cksum_name); | |
445 | err = PTR_ERR(hmac); | |
446 | goto out_err; | |
447 | } | |
448 | ||
449 | err = crypto_hash_setkey(hmac, ctx->Ksess, ctx->gk5e->keylength); | |
450 | if (err) | |
451 | goto out_err_free_hmac; | |
452 | ||
453 | sg_init_table(sg, 1); | |
454 | sg_set_buf(sg, sigkeyconstant, slen); | |
455 | ||
456 | desc.tfm = hmac; | |
457 | desc.flags = 0; | |
458 | ||
459 | err = crypto_hash_init(&desc); | |
460 | if (err) | |
461 | goto out_err_free_hmac; | |
462 | ||
463 | err = crypto_hash_digest(&desc, sg, slen, ctx->cksum); | |
464 | if (err) | |
465 | goto out_err_free_hmac; | |
466 | /* | |
467 | * allocate hash, and blkciphers for data and seqnum encryption | |
468 | */ | |
469 | ctx->enc = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name, 0, | |
470 | CRYPTO_ALG_ASYNC); | |
471 | if (IS_ERR(ctx->enc)) { | |
472 | err = PTR_ERR(ctx->enc); | |
473 | goto out_err_free_hmac; | |
474 | } | |
475 | ||
476 | ctx->seq = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name, 0, | |
477 | CRYPTO_ALG_ASYNC); | |
478 | if (IS_ERR(ctx->seq)) { | |
479 | crypto_free_blkcipher(ctx->enc); | |
480 | err = PTR_ERR(ctx->seq); | |
481 | goto out_err_free_hmac; | |
482 | } | |
483 | ||
484 | dprintk("RPC: %s: returning success\n", __func__); | |
485 | ||
486 | err = 0; | |
487 | ||
488 | out_err_free_hmac: | |
489 | crypto_free_hash(hmac); | |
490 | out_err: | |
491 | dprintk("RPC: %s: returning %d\n", __func__, err); | |
492 | return err; | |
493 | } | |
494 | ||
47d84807 | 495 | static int |
1f4c86c0 | 496 | context_derive_keys_new(struct krb5_ctx *ctx, gfp_t gfp_mask) |
47d84807 KC |
497 | { |
498 | struct xdr_netobj c, keyin, keyout; | |
499 | u8 cdata[GSS_KRB5_K5CLENGTH]; | |
500 | u32 err; | |
501 | ||
502 | c.len = GSS_KRB5_K5CLENGTH; | |
503 | c.data = cdata; | |
504 | ||
fc263a91 KC |
505 | keyin.data = ctx->Ksess; |
506 | keyin.len = ctx->gk5e->keylength; | |
507 | keyout.len = ctx->gk5e->keylength; | |
47d84807 KC |
508 | |
509 | /* initiator seal encryption */ | |
510 | set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_ENCRYPTION); | |
511 | keyout.data = ctx->initiator_seal; | |
1f4c86c0 | 512 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); |
47d84807 KC |
513 | if (err) { |
514 | dprintk("%s: Error %d deriving initiator_seal key\n", | |
515 | __func__, err); | |
516 | goto out_err; | |
517 | } | |
934a95aa KC |
518 | ctx->initiator_enc = context_v2_alloc_cipher(ctx, |
519 | ctx->gk5e->encrypt_name, | |
520 | ctx->initiator_seal); | |
47d84807 KC |
521 | if (ctx->initiator_enc == NULL) |
522 | goto out_err; | |
523 | ||
524 | /* acceptor seal encryption */ | |
525 | set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_ENCRYPTION); | |
526 | keyout.data = ctx->acceptor_seal; | |
1f4c86c0 | 527 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); |
47d84807 KC |
528 | if (err) { |
529 | dprintk("%s: Error %d deriving acceptor_seal key\n", | |
530 | __func__, err); | |
531 | goto out_free_initiator_enc; | |
532 | } | |
934a95aa KC |
533 | ctx->acceptor_enc = context_v2_alloc_cipher(ctx, |
534 | ctx->gk5e->encrypt_name, | |
535 | ctx->acceptor_seal); | |
47d84807 KC |
536 | if (ctx->acceptor_enc == NULL) |
537 | goto out_free_initiator_enc; | |
538 | ||
539 | /* initiator sign checksum */ | |
540 | set_cdata(cdata, KG_USAGE_INITIATOR_SIGN, KEY_USAGE_SEED_CHECKSUM); | |
541 | keyout.data = ctx->initiator_sign; | |
1f4c86c0 | 542 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); |
47d84807 KC |
543 | if (err) { |
544 | dprintk("%s: Error %d deriving initiator_sign key\n", | |
545 | __func__, err); | |
546 | goto out_free_acceptor_enc; | |
547 | } | |
548 | ||
549 | /* acceptor sign checksum */ | |
550 | set_cdata(cdata, KG_USAGE_ACCEPTOR_SIGN, KEY_USAGE_SEED_CHECKSUM); | |
551 | keyout.data = ctx->acceptor_sign; | |
1f4c86c0 | 552 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); |
47d84807 KC |
553 | if (err) { |
554 | dprintk("%s: Error %d deriving acceptor_sign key\n", | |
555 | __func__, err); | |
556 | goto out_free_acceptor_enc; | |
557 | } | |
558 | ||
559 | /* initiator seal integrity */ | |
560 | set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_INTEGRITY); | |
561 | keyout.data = ctx->initiator_integ; | |
1f4c86c0 | 562 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); |
47d84807 KC |
563 | if (err) { |
564 | dprintk("%s: Error %d deriving initiator_integ key\n", | |
565 | __func__, err); | |
566 | goto out_free_acceptor_enc; | |
567 | } | |
568 | ||
569 | /* acceptor seal integrity */ | |
570 | set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_INTEGRITY); | |
571 | keyout.data = ctx->acceptor_integ; | |
1f4c86c0 | 572 | err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c, gfp_mask); |
47d84807 KC |
573 | if (err) { |
574 | dprintk("%s: Error %d deriving acceptor_integ key\n", | |
575 | __func__, err); | |
576 | goto out_free_acceptor_enc; | |
577 | } | |
578 | ||
934a95aa KC |
579 | switch (ctx->enctype) { |
580 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: | |
581 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | |
582 | ctx->initiator_enc_aux = | |
583 | context_v2_alloc_cipher(ctx, "cbc(aes)", | |
584 | ctx->initiator_seal); | |
585 | if (ctx->initiator_enc_aux == NULL) | |
586 | goto out_free_acceptor_enc; | |
587 | ctx->acceptor_enc_aux = | |
588 | context_v2_alloc_cipher(ctx, "cbc(aes)", | |
589 | ctx->acceptor_seal); | |
590 | if (ctx->acceptor_enc_aux == NULL) { | |
591 | crypto_free_blkcipher(ctx->initiator_enc_aux); | |
592 | goto out_free_acceptor_enc; | |
593 | } | |
594 | } | |
595 | ||
47d84807 KC |
596 | return 0; |
597 | ||
598 | out_free_acceptor_enc: | |
599 | crypto_free_blkcipher(ctx->acceptor_enc); | |
600 | out_free_initiator_enc: | |
601 | crypto_free_blkcipher(ctx->initiator_enc); | |
602 | out_err: | |
603 | return -EINVAL; | |
604 | } | |
605 | ||
606 | static int | |
1f4c86c0 TM |
607 | gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx, |
608 | gfp_t gfp_mask) | |
47d84807 | 609 | { |
47d84807 KC |
610 | int keylen; |
611 | ||
612 | p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags)); | |
613 | if (IS_ERR(p)) | |
614 | goto out_err; | |
615 | ctx->initiate = ctx->flags & KRB5_CTX_FLAG_INITIATOR; | |
616 | ||
617 | p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime)); | |
618 | if (IS_ERR(p)) | |
619 | goto out_err; | |
620 | p = simple_get_bytes(p, end, &ctx->seq_send64, sizeof(ctx->seq_send64)); | |
621 | if (IS_ERR(p)) | |
622 | goto out_err; | |
623 | /* set seq_send for use by "older" enctypes */ | |
624 | ctx->seq_send = ctx->seq_send64; | |
625 | if (ctx->seq_send64 != ctx->seq_send) { | |
626 | dprintk("%s: seq_send64 %lx, seq_send %x overflow?\n", __func__, | |
95c96174 | 627 | (unsigned long)ctx->seq_send64, ctx->seq_send); |
ce8477e1 | 628 | p = ERR_PTR(-EINVAL); |
47d84807 KC |
629 | goto out_err; |
630 | } | |
631 | p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype)); | |
632 | if (IS_ERR(p)) | |
633 | goto out_err; | |
958142e9 KC |
634 | /* Map ENCTYPE_DES3_CBC_SHA1 to ENCTYPE_DES3_CBC_RAW */ |
635 | if (ctx->enctype == ENCTYPE_DES3_CBC_SHA1) | |
636 | ctx->enctype = ENCTYPE_DES3_CBC_RAW; | |
47d84807 KC |
637 | ctx->gk5e = get_gss_krb5_enctype(ctx->enctype); |
638 | if (ctx->gk5e == NULL) { | |
639 | dprintk("gss_kerberos_mech: unsupported krb5 enctype %u\n", | |
640 | ctx->enctype); | |
641 | p = ERR_PTR(-EINVAL); | |
642 | goto out_err; | |
643 | } | |
644 | keylen = ctx->gk5e->keylength; | |
645 | ||
fc263a91 | 646 | p = simple_get_bytes(p, end, ctx->Ksess, keylen); |
47d84807 KC |
647 | if (IS_ERR(p)) |
648 | goto out_err; | |
649 | ||
650 | if (p != end) { | |
651 | p = ERR_PTR(-EINVAL); | |
652 | goto out_err; | |
653 | } | |
654 | ||
655 | ctx->mech_used.data = kmemdup(gss_kerberos_mech.gm_oid.data, | |
1f4c86c0 | 656 | gss_kerberos_mech.gm_oid.len, gfp_mask); |
47d84807 KC |
657 | if (unlikely(ctx->mech_used.data == NULL)) { |
658 | p = ERR_PTR(-ENOMEM); | |
659 | goto out_err; | |
660 | } | |
661 | ctx->mech_used.len = gss_kerberos_mech.gm_oid.len; | |
662 | ||
663 | switch (ctx->enctype) { | |
664 | case ENCTYPE_DES3_CBC_RAW: | |
1f4c86c0 | 665 | return context_derive_keys_des3(ctx, gfp_mask); |
fffdaef2 KC |
666 | case ENCTYPE_ARCFOUR_HMAC: |
667 | return context_derive_keys_rc4(ctx); | |
47d84807 KC |
668 | case ENCTYPE_AES128_CTS_HMAC_SHA1_96: |
669 | case ENCTYPE_AES256_CTS_HMAC_SHA1_96: | |
1f4c86c0 | 670 | return context_derive_keys_new(ctx, gfp_mask); |
47d84807 KC |
671 | default: |
672 | return -EINVAL; | |
673 | } | |
674 | ||
675 | out_err: | |
676 | return PTR_ERR(p); | |
677 | } | |
678 | ||
a8cc1cb7 KC |
679 | static int |
680 | gss_import_sec_context_kerberos(const void *p, size_t len, | |
1f4c86c0 | 681 | struct gss_ctx *ctx_id, |
400f26b5 | 682 | time_t *endtime, |
1f4c86c0 | 683 | gfp_t gfp_mask) |
a8cc1cb7 KC |
684 | { |
685 | const void *end = (const void *)((const char *)p + len); | |
686 | struct krb5_ctx *ctx; | |
687 | int ret; | |
688 | ||
1f4c86c0 | 689 | ctx = kzalloc(sizeof(*ctx), gfp_mask); |
a8cc1cb7 KC |
690 | if (ctx == NULL) |
691 | return -ENOMEM; | |
692 | ||
693 | if (len == 85) | |
694 | ret = gss_import_v1_context(p, end, ctx); | |
695 | else | |
1f4c86c0 | 696 | ret = gss_import_v2_context(p, end, ctx, gfp_mask); |
a8cc1cb7 | 697 | |
400f26b5 | 698 | if (ret == 0) { |
a8cc1cb7 | 699 | ctx_id->internal_ctx_id = ctx; |
400f26b5 SS |
700 | if (endtime) |
701 | *endtime = ctx->endtime; | |
702 | } else | |
a8cc1cb7 KC |
703 | kfree(ctx); |
704 | ||
705 | dprintk("RPC: %s: returning %d\n", __func__, ret); | |
706 | return ret; | |
707 | } | |
708 | ||
1da177e4 LT |
709 | static void |
710 | gss_delete_sec_context_kerberos(void *internal_ctx) { | |
711 | struct krb5_ctx *kctx = internal_ctx; | |
712 | ||
378c6697 HX |
713 | crypto_free_blkcipher(kctx->seq); |
714 | crypto_free_blkcipher(kctx->enc); | |
47d84807 KC |
715 | crypto_free_blkcipher(kctx->acceptor_enc); |
716 | crypto_free_blkcipher(kctx->initiator_enc); | |
934a95aa KC |
717 | crypto_free_blkcipher(kctx->acceptor_enc_aux); |
718 | crypto_free_blkcipher(kctx->initiator_enc_aux); | |
573dbd95 | 719 | kfree(kctx->mech_used.data); |
1da177e4 LT |
720 | kfree(kctx); |
721 | } | |
722 | ||
f1c0a861 | 723 | static const struct gss_api_ops gss_kerberos_ops = { |
1da177e4 LT |
724 | .gss_import_sec_context = gss_import_sec_context_kerberos, |
725 | .gss_get_mic = gss_get_mic_kerberos, | |
726 | .gss_verify_mic = gss_verify_mic_kerberos, | |
14ae162c BF |
727 | .gss_wrap = gss_wrap_kerberos, |
728 | .gss_unwrap = gss_unwrap_kerberos, | |
1da177e4 LT |
729 | .gss_delete_sec_context = gss_delete_sec_context_kerberos, |
730 | }; | |
731 | ||
732 | static struct pf_desc gss_kerberos_pfs[] = { | |
733 | [0] = { | |
734 | .pseudoflavor = RPC_AUTH_GSS_KRB5, | |
83523d08 | 735 | .qop = GSS_C_QOP_DEFAULT, |
1da177e4 LT |
736 | .service = RPC_GSS_SVC_NONE, |
737 | .name = "krb5", | |
738 | }, | |
739 | [1] = { | |
740 | .pseudoflavor = RPC_AUTH_GSS_KRB5I, | |
83523d08 | 741 | .qop = GSS_C_QOP_DEFAULT, |
1da177e4 LT |
742 | .service = RPC_GSS_SVC_INTEGRITY, |
743 | .name = "krb5i", | |
744 | }, | |
14ae162c BF |
745 | [2] = { |
746 | .pseudoflavor = RPC_AUTH_GSS_KRB5P, | |
83523d08 | 747 | .qop = GSS_C_QOP_DEFAULT, |
14ae162c BF |
748 | .service = RPC_GSS_SVC_PRIVACY, |
749 | .name = "krb5p", | |
750 | }, | |
1da177e4 LT |
751 | }; |
752 | ||
058c5c99 BF |
753 | MODULE_ALIAS("rpc-auth-gss-krb5"); |
754 | MODULE_ALIAS("rpc-auth-gss-krb5i"); | |
755 | MODULE_ALIAS("rpc-auth-gss-krb5p"); | |
756 | MODULE_ALIAS("rpc-auth-gss-390003"); | |
757 | MODULE_ALIAS("rpc-auth-gss-390004"); | |
758 | MODULE_ALIAS("rpc-auth-gss-390005"); | |
f783288f | 759 | MODULE_ALIAS("rpc-auth-gss-1.2.840.113554.1.2.2"); |
058c5c99 | 760 | |
1da177e4 LT |
761 | static struct gss_api_mech gss_kerberos_mech = { |
762 | .gm_name = "krb5", | |
763 | .gm_owner = THIS_MODULE, | |
fb15b26f | 764 | .gm_oid = { 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }, |
1da177e4 LT |
765 | .gm_ops = &gss_kerberos_ops, |
766 | .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), | |
767 | .gm_pfs = gss_kerberos_pfs, | |
b084f598 | 768 | .gm_upcall_enctypes = KRB5_SUPPORTED_ENCTYPES, |
1da177e4 LT |
769 | }; |
770 | ||
771 | static int __init init_kerberos_module(void) | |
772 | { | |
773 | int status; | |
774 | ||
775 | status = gss_mech_register(&gss_kerberos_mech); | |
776 | if (status) | |
777 | printk("Failed to register kerberos gss mechanism!\n"); | |
778 | return status; | |
779 | } | |
780 | ||
781 | static void __exit cleanup_kerberos_module(void) | |
782 | { | |
783 | gss_mech_unregister(&gss_kerberos_mech); | |
784 | } | |
785 | ||
786 | MODULE_LICENSE("GPL"); | |
787 | module_init(init_kerberos_module); | |
788 | module_exit(cleanup_kerberos_module); |