03f1dcddbd29d352c3041fbbfd6e7f76e1fcb968
[safe/jmp/linux-2.6] / net / sunrpc / auth_gss / gss_krb5_mech.c
1 /*
2  *  linux/net/sunrpc/gss_krb5_mech.c
3  *
4  *  Copyright (c) 2001-2008 The Regents of the University of Michigan.
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
37 #include <linux/err.h>
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>
43 #include <linux/sunrpc/gss_krb5.h>
44 #include <linux/sunrpc/xdr.h>
45 #include <linux/crypto.h>
46
47 #ifdef RPC_DEBUG
48 # define RPCDBG_FACILITY        RPCDBG_AUTH
49 #endif
50
51 static struct gss_api_mech gss_kerberos_mech;   /* forward declaration */
52
53 static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
54         /*
55          * DES (All DES enctypes are mapped to the same gss functionality)
56          */
57         {
58           .etype = ENCTYPE_DES_CBC_RAW,
59           .ctype = CKSUMTYPE_RSA_MD5,
60           .name = "des-cbc-crc",
61           .encrypt_name = "cbc(des)",
62           .cksum_name = "md5",
63           .encrypt = krb5_encrypt,
64           .decrypt = krb5_decrypt,
65           .mk_key = NULL,
66           .signalg = SGN_ALG_DES_MAC_MD5,
67           .sealalg = SEAL_ALG_DES,
68           .keybytes = 7,
69           .keylength = 8,
70           .blocksize = 8,
71           .cksumlength = 8,
72           .keyed_cksum = 0,
73         },
74 };
75
76 static const int num_supported_enctypes =
77         ARRAY_SIZE(supported_gss_krb5_enctypes);
78
79 static int
80 supported_gss_krb5_enctype(int etype)
81 {
82         int i;
83         for (i = 0; i < num_supported_enctypes; i++)
84                 if (supported_gss_krb5_enctypes[i].etype == etype)
85                         return 1;
86         return 0;
87 }
88
89 static const struct gss_krb5_enctype *
90 get_gss_krb5_enctype(int etype)
91 {
92         int i;
93         for (i = 0; i < num_supported_enctypes; i++)
94                 if (supported_gss_krb5_enctypes[i].etype == etype)
95                         return &supported_gss_krb5_enctypes[i];
96         return NULL;
97 }
98
99 static const void *
100 simple_get_bytes(const void *p, const void *end, void *res, int len)
101 {
102         const void *q = (const void *)((const char *)p + len);
103         if (unlikely(q > end || q < p))
104                 return ERR_PTR(-EFAULT);
105         memcpy(res, p, len);
106         return q;
107 }
108
109 static const void *
110 simple_get_netobj(const void *p, const void *end, struct xdr_netobj *res)
111 {
112         const void *q;
113         unsigned int len;
114
115         p = simple_get_bytes(p, end, &len, sizeof(len));
116         if (IS_ERR(p))
117                 return p;
118         q = (const void *)((const char *)p + len);
119         if (unlikely(q > end || q < p))
120                 return ERR_PTR(-EFAULT);
121         res->data = kmemdup(p, len, GFP_NOFS);
122         if (unlikely(res->data == NULL))
123                 return ERR_PTR(-ENOMEM);
124         res->len = len;
125         return q;
126 }
127
128 static inline const void *
129 get_key(const void *p, const void *end,
130         struct krb5_ctx *ctx, struct crypto_blkcipher **res)
131 {
132         struct xdr_netobj       key;
133         int                     alg;
134
135         p = simple_get_bytes(p, end, &alg, sizeof(alg));
136         if (IS_ERR(p))
137                 goto out_err;
138
139         switch (alg) {
140         case ENCTYPE_DES_CBC_CRC:
141         case ENCTYPE_DES_CBC_MD4:
142         case ENCTYPE_DES_CBC_MD5:
143                 /* Map all these key types to ENCTYPE_DES_CBC_RAW */
144                 alg = ENCTYPE_DES_CBC_RAW;
145                 break;
146         }
147
148         if (!supported_gss_krb5_enctype(alg)) {
149                 printk(KERN_WARNING "gss_kerberos_mech: unsupported "
150                         "encryption key algorithm %d\n", alg);
151                 goto out_err;
152         }
153         p = simple_get_netobj(p, end, &key);
154         if (IS_ERR(p))
155                 goto out_err;
156
157         *res = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name, 0,
158                                                         CRYPTO_ALG_ASYNC);
159         if (IS_ERR(*res)) {
160                 printk(KERN_WARNING "gss_kerberos_mech: unable to initialize "
161                         "crypto algorithm %s\n", ctx->gk5e->encrypt_name);
162                 *res = NULL;
163                 goto out_err_free_key;
164         }
165         if (crypto_blkcipher_setkey(*res, key.data, key.len)) {
166                 printk(KERN_WARNING "gss_kerberos_mech: error setting key for "
167                         "crypto algorithm %s\n", ctx->gk5e->encrypt_name);
168                 goto out_err_free_tfm;
169         }
170
171         kfree(key.data);
172         return p;
173
174 out_err_free_tfm:
175         crypto_free_blkcipher(*res);
176 out_err_free_key:
177         kfree(key.data);
178         p = ERR_PTR(-EINVAL);
179 out_err:
180         return p;
181 }
182
183 static int
184 gss_import_v1_context(const void *p, const void *end, struct krb5_ctx *ctx)
185 {
186         int tmp;
187
188         p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate));
189         if (IS_ERR(p))
190                 goto out_err;
191
192         /* Old format supports only DES!  Any other enctype uses new format */
193         ctx->enctype = ENCTYPE_DES_CBC_RAW;
194
195         ctx->gk5e = get_gss_krb5_enctype(ctx->enctype);
196         if (ctx->gk5e == NULL)
197                 goto out_err;
198
199         /* The downcall format was designed before we completely understood
200          * the uses of the context fields; so it includes some stuff we
201          * just give some minimal sanity-checking, and some we ignore
202          * completely (like the next twenty bytes): */
203         if (unlikely(p + 20 > end || p + 20 < p))
204                 goto out_err;
205         p += 20;
206         p = simple_get_bytes(p, end, &tmp, sizeof(tmp));
207         if (IS_ERR(p))
208                 goto out_err;
209         if (tmp != SGN_ALG_DES_MAC_MD5) {
210                 p = ERR_PTR(-ENOSYS);
211                 goto out_err;
212         }
213         p = simple_get_bytes(p, end, &tmp, sizeof(tmp));
214         if (IS_ERR(p))
215                 goto out_err;
216         if (tmp != SEAL_ALG_DES) {
217                 p = ERR_PTR(-ENOSYS);
218                 goto out_err;
219         }
220         p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime));
221         if (IS_ERR(p))
222                 goto out_err;
223         p = simple_get_bytes(p, end, &ctx->seq_send, sizeof(ctx->seq_send));
224         if (IS_ERR(p))
225                 goto out_err;
226         p = simple_get_netobj(p, end, &ctx->mech_used);
227         if (IS_ERR(p))
228                 goto out_err;
229         p = get_key(p, end, ctx, &ctx->enc);
230         if (IS_ERR(p))
231                 goto out_err_free_mech;
232         p = get_key(p, end, ctx, &ctx->seq);
233         if (IS_ERR(p))
234                 goto out_err_free_key1;
235         if (p != end) {
236                 p = ERR_PTR(-EFAULT);
237                 goto out_err_free_key2;
238         }
239
240         return 0;
241
242 out_err_free_key2:
243         crypto_free_blkcipher(ctx->seq);
244 out_err_free_key1:
245         crypto_free_blkcipher(ctx->enc);
246 out_err_free_mech:
247         kfree(ctx->mech_used.data);
248 out_err:
249         return PTR_ERR(p);
250 }
251
252 struct crypto_blkcipher *
253 context_v2_alloc_cipher(struct krb5_ctx *ctx, u8 *key)
254 {
255         struct crypto_blkcipher *cp;
256
257         cp = crypto_alloc_blkcipher(ctx->gk5e->encrypt_name,
258                                         0, CRYPTO_ALG_ASYNC);
259         if (IS_ERR(cp)) {
260                 dprintk("gss_kerberos_mech: unable to initialize "
261                         "crypto algorithm %s\n", ctx->gk5e->encrypt_name);
262                 return NULL;
263         }
264         if (crypto_blkcipher_setkey(cp, key, ctx->gk5e->keylength)) {
265                 dprintk("gss_kerberos_mech: error setting key for "
266                         "crypto algorithm %s\n", ctx->gk5e->encrypt_name);
267                 crypto_free_blkcipher(cp);
268                 return NULL;
269         }
270         return cp;
271 }
272
273 static inline void
274 set_cdata(u8 cdata[GSS_KRB5_K5CLENGTH], u32 usage, u8 seed)
275 {
276         cdata[0] = (usage>>24)&0xff;
277         cdata[1] = (usage>>16)&0xff;
278         cdata[2] = (usage>>8)&0xff;
279         cdata[3] = usage&0xff;
280         cdata[4] = seed;
281 }
282
283 static int
284 context_derive_keys_des3(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen)
285 {
286         struct xdr_netobj c, keyin, keyout;
287         u8 cdata[GSS_KRB5_K5CLENGTH];
288         u32 err;
289
290         c.len = GSS_KRB5_K5CLENGTH;
291         c.data = cdata;
292
293         keyin.data = rawkey;
294         keyin.len = keylen;
295         keyout.len = keylen;
296
297         /* seq uses the raw key */
298         ctx->seq = context_v2_alloc_cipher(ctx, rawkey);
299         if (ctx->seq == NULL)
300                 goto out_err;
301
302         ctx->enc = context_v2_alloc_cipher(ctx, rawkey);
303         if (ctx->enc == NULL)
304                 goto out_free_seq;
305
306         /* derive cksum */
307         set_cdata(cdata, KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM);
308         keyout.data = ctx->cksum;
309         err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
310         if (err) {
311                 dprintk("%s: Error %d deriving cksum key\n",
312                         __func__, err);
313                 goto out_free_enc;
314         }
315
316         return 0;
317
318 out_free_enc:
319         crypto_free_blkcipher(ctx->enc);
320 out_free_seq:
321         crypto_free_blkcipher(ctx->seq);
322 out_err:
323         return -EINVAL;
324 }
325
326 static int
327 context_derive_keys_new(struct krb5_ctx *ctx, u8 *rawkey, u32 keylen)
328 {
329         struct xdr_netobj c, keyin, keyout;
330         u8 cdata[GSS_KRB5_K5CLENGTH];
331         u32 err;
332
333         c.len = GSS_KRB5_K5CLENGTH;
334         c.data = cdata;
335
336         keyin.data = rawkey;
337         keyin.len = keylen;
338         keyout.len = keylen;
339
340         /* initiator seal encryption */
341         set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_ENCRYPTION);
342         keyout.data = ctx->initiator_seal;
343         err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
344         if (err) {
345                 dprintk("%s: Error %d deriving initiator_seal key\n",
346                         __func__, err);
347                 goto out_err;
348         }
349         ctx->initiator_enc = context_v2_alloc_cipher(ctx, ctx->initiator_seal);
350         if (ctx->initiator_enc == NULL)
351                 goto out_err;
352
353         /* acceptor seal encryption */
354         set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_ENCRYPTION);
355         keyout.data = ctx->acceptor_seal;
356         err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
357         if (err) {
358                 dprintk("%s: Error %d deriving acceptor_seal key\n",
359                         __func__, err);
360                 goto out_free_initiator_enc;
361         }
362         ctx->acceptor_enc = context_v2_alloc_cipher(ctx, ctx->acceptor_seal);
363         if (ctx->acceptor_enc == NULL)
364                 goto out_free_initiator_enc;
365
366         /* initiator sign checksum */
367         set_cdata(cdata, KG_USAGE_INITIATOR_SIGN, KEY_USAGE_SEED_CHECKSUM);
368         keyout.data = ctx->initiator_sign;
369         err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
370         if (err) {
371                 dprintk("%s: Error %d deriving initiator_sign key\n",
372                         __func__, err);
373                 goto out_free_acceptor_enc;
374         }
375
376         /* acceptor sign checksum */
377         set_cdata(cdata, KG_USAGE_ACCEPTOR_SIGN, KEY_USAGE_SEED_CHECKSUM);
378         keyout.data = ctx->acceptor_sign;
379         err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
380         if (err) {
381                 dprintk("%s: Error %d deriving acceptor_sign key\n",
382                         __func__, err);
383                 goto out_free_acceptor_enc;
384         }
385
386         /* initiator seal integrity */
387         set_cdata(cdata, KG_USAGE_INITIATOR_SEAL, KEY_USAGE_SEED_INTEGRITY);
388         keyout.data = ctx->initiator_integ;
389         err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
390         if (err) {
391                 dprintk("%s: Error %d deriving initiator_integ key\n",
392                         __func__, err);
393                 goto out_free_acceptor_enc;
394         }
395
396         /* acceptor seal integrity */
397         set_cdata(cdata, KG_USAGE_ACCEPTOR_SEAL, KEY_USAGE_SEED_INTEGRITY);
398         keyout.data = ctx->acceptor_integ;
399         err = krb5_derive_key(ctx->gk5e, &keyin, &keyout, &c);
400         if (err) {
401                 dprintk("%s: Error %d deriving acceptor_integ key\n",
402                         __func__, err);
403                 goto out_free_acceptor_enc;
404         }
405
406         return 0;
407
408 out_free_acceptor_enc:
409         crypto_free_blkcipher(ctx->acceptor_enc);
410 out_free_initiator_enc:
411         crypto_free_blkcipher(ctx->initiator_enc);
412 out_err:
413         return -EINVAL;
414 }
415
416 static int
417 gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx)
418 {
419         u8 rawkey[GSS_KRB5_MAX_KEYLEN];
420         int keylen;
421
422         p = simple_get_bytes(p, end, &ctx->flags, sizeof(ctx->flags));
423         if (IS_ERR(p))
424                 goto out_err;
425         ctx->initiate = ctx->flags & KRB5_CTX_FLAG_INITIATOR;
426
427         p = simple_get_bytes(p, end, &ctx->endtime, sizeof(ctx->endtime));
428         if (IS_ERR(p))
429                 goto out_err;
430         p = simple_get_bytes(p, end, &ctx->seq_send64, sizeof(ctx->seq_send64));
431         if (IS_ERR(p))
432                 goto out_err;
433         /* set seq_send for use by "older" enctypes */
434         ctx->seq_send = ctx->seq_send64;
435         if (ctx->seq_send64 != ctx->seq_send) {
436                 dprintk("%s: seq_send64 %lx, seq_send %x overflow?\n", __func__,
437                         (long unsigned)ctx->seq_send64, ctx->seq_send);
438                 goto out_err;
439         }
440         p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype));
441         if (IS_ERR(p))
442                 goto out_err;
443         ctx->gk5e = get_gss_krb5_enctype(ctx->enctype);
444         if (ctx->gk5e == NULL) {
445                 dprintk("gss_kerberos_mech: unsupported krb5 enctype %u\n",
446                         ctx->enctype);
447                 p = ERR_PTR(-EINVAL);
448                 goto out_err;
449         }
450         keylen = ctx->gk5e->keylength;
451
452         p = simple_get_bytes(p, end, rawkey, keylen);
453         if (IS_ERR(p))
454                 goto out_err;
455
456         if (p != end) {
457                 p = ERR_PTR(-EINVAL);
458                 goto out_err;
459         }
460
461         ctx->mech_used.data = kmemdup(gss_kerberos_mech.gm_oid.data,
462                                       gss_kerberos_mech.gm_oid.len, GFP_KERNEL);
463         if (unlikely(ctx->mech_used.data == NULL)) {
464                 p = ERR_PTR(-ENOMEM);
465                 goto out_err;
466         }
467         ctx->mech_used.len = gss_kerberos_mech.gm_oid.len;
468
469         switch (ctx->enctype) {
470         case ENCTYPE_DES3_CBC_RAW:
471                 return context_derive_keys_des3(ctx, rawkey, keylen);
472         case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
473         case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
474                 return context_derive_keys_new(ctx, rawkey, keylen);
475         default:
476                 return -EINVAL;
477         }
478
479 out_err:
480         return PTR_ERR(p);
481 }
482
483 static int
484 gss_import_sec_context_kerberos(const void *p, size_t len,
485                                 struct gss_ctx *ctx_id)
486 {
487         const void *end = (const void *)((const char *)p + len);
488         struct  krb5_ctx *ctx;
489         int ret;
490
491         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
492         if (ctx == NULL)
493                 return -ENOMEM;
494
495         if (len == 85)
496                 ret = gss_import_v1_context(p, end, ctx);
497         else
498                 ret = gss_import_v2_context(p, end, ctx);
499
500         if (ret == 0)
501                 ctx_id->internal_ctx_id = ctx;
502         else
503                 kfree(ctx);
504
505         dprintk("RPC:       %s: returning %d\n", __func__, ret);
506         return ret;
507 }
508
509 static void
510 gss_delete_sec_context_kerberos(void *internal_ctx) {
511         struct krb5_ctx *kctx = internal_ctx;
512
513         crypto_free_blkcipher(kctx->seq);
514         crypto_free_blkcipher(kctx->enc);
515         crypto_free_blkcipher(kctx->acceptor_enc);
516         crypto_free_blkcipher(kctx->initiator_enc);
517         kfree(kctx->mech_used.data);
518         kfree(kctx);
519 }
520
521 static const struct gss_api_ops gss_kerberos_ops = {
522         .gss_import_sec_context = gss_import_sec_context_kerberos,
523         .gss_get_mic            = gss_get_mic_kerberos,
524         .gss_verify_mic         = gss_verify_mic_kerberos,
525         .gss_wrap               = gss_wrap_kerberos,
526         .gss_unwrap             = gss_unwrap_kerberos,
527         .gss_delete_sec_context = gss_delete_sec_context_kerberos,
528 };
529
530 static struct pf_desc gss_kerberos_pfs[] = {
531         [0] = {
532                 .pseudoflavor = RPC_AUTH_GSS_KRB5,
533                 .service = RPC_GSS_SVC_NONE,
534                 .name = "krb5",
535         },
536         [1] = {
537                 .pseudoflavor = RPC_AUTH_GSS_KRB5I,
538                 .service = RPC_GSS_SVC_INTEGRITY,
539                 .name = "krb5i",
540         },
541         [2] = {
542                 .pseudoflavor = RPC_AUTH_GSS_KRB5P,
543                 .service = RPC_GSS_SVC_PRIVACY,
544                 .name = "krb5p",
545         },
546 };
547
548 static struct gss_api_mech gss_kerberos_mech = {
549         .gm_name        = "krb5",
550         .gm_owner       = THIS_MODULE,
551         .gm_oid         = {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"},
552         .gm_ops         = &gss_kerberos_ops,
553         .gm_pf_num      = ARRAY_SIZE(gss_kerberos_pfs),
554         .gm_pfs         = gss_kerberos_pfs,
555         .gm_upcall_enctypes = "enctypes=3,1,2 ",
556 };
557
558 static int __init init_kerberos_module(void)
559 {
560         int status;
561
562         status = gss_mech_register(&gss_kerberos_mech);
563         if (status)
564                 printk("Failed to register kerberos gss mechanism!\n");
565         return status;
566 }
567
568 static void __exit cleanup_kerberos_module(void)
569 {
570         gss_mech_unregister(&gss_kerberos_mech);
571 }
572
573 MODULE_LICENSE("GPL");
574 module_init(init_kerberos_module);
575 module_exit(cleanup_kerberos_module);