Whamcloud - gitweb
LU-2800 compat: remove crypto shims
[fs/lustre-release.git] / lustre / ptlrpc / gss / gss_krb5_mech.c
1 /*
2  * Modifications for Lustre
3  *
4  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
5  *
6  * Copyright (c) 2011, 2013, Intel Corporation.
7  *
8  * Author: Eric Mei <ericm@clusterfs.com>
9  */
10
11 /*
12  *  linux/net/sunrpc/gss_krb5_mech.c
13  *  linux/net/sunrpc/gss_krb5_crypto.c
14  *  linux/net/sunrpc/gss_krb5_seal.c
15  *  linux/net/sunrpc/gss_krb5_seqnum.c
16  *  linux/net/sunrpc/gss_krb5_unseal.c
17  *
18  *  Copyright (c) 2001 The Regents of the University of Michigan.
19  *  All rights reserved.
20  *
21  *  Andy Adamson <andros@umich.edu>
22  *  J. Bruce Fields <bfields@umich.edu>
23  *
24  *  Redistribution and use in source and binary forms, with or without
25  *  modification, are permitted provided that the following conditions
26  *  are met:
27  *
28  *  1. Redistributions of source code must retain the above copyright
29  *     notice, this list of conditions and the following disclaimer.
30  *  2. Redistributions in binary form must reproduce the above copyright
31  *     notice, this list of conditions and the following disclaimer in the
32  *     documentation and/or other materials provided with the distribution.
33  *  3. Neither the name of the University nor the names of its
34  *     contributors may be used to endorse or promote products derived
35  *     from this software without specific prior written permission.
36  *
37  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
38  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
39  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
41  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
43  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
44  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
45  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
46  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
47  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  *
49  */
50
51 #define DEBUG_SUBSYSTEM S_SEC
52 #ifdef __KERNEL__
53 #include <linux/init.h>
54 #include <linux/module.h>
55 #include <linux/slab.h>
56 #include <linux/crypto.h>
57 #include <linux/mutex.h>
58 #else
59 #include <liblustre.h>
60 #endif
61
62 #include <obd.h>
63 #include <obd_class.h>
64 #include <obd_support.h>
65 #include <lustre/lustre_idl.h>
66 #include <lustre_net.h>
67 #include <lustre_import.h>
68 #include <lustre_sec.h>
69
70 #include "gss_err.h"
71 #include "gss_internal.h"
72 #include "gss_api.h"
73 #include "gss_asn1.h"
74 #include "gss_krb5.h"
75
76 static spinlock_t krb5_seq_lock;
77
78 struct krb5_enctype {
79         char           *ke_dispname;
80         char           *ke_enc_name;            /* linux tfm name */
81         char           *ke_hash_name;           /* linux tfm name */
82         int             ke_enc_mode;            /* linux tfm mode */
83         int             ke_hash_size;           /* checksum size */
84         int             ke_conf_size;           /* confounder size */
85         unsigned int    ke_hash_hmac:1;         /* is hmac? */
86 };
87
88 /*
89  * NOTE: for aes128-cts and aes256-cts, MIT implementation use CTS encryption.
90  * but currently we simply CBC with padding, because linux doesn't support CTS
91  * yet. this need to be fixed in the future.
92  */
93 static struct krb5_enctype enctypes[] = {
94         [ENCTYPE_DES_CBC_RAW] = {               /* des-cbc-md5 */
95                 "des-cbc-md5",
96                 "cbc(des)",
97                 "md5",
98                 0,
99                 16,
100                 8,
101                 0,
102         },
103         [ENCTYPE_DES3_CBC_RAW] = {              /* des3-hmac-sha1 */
104                 "des3-hmac-sha1",
105                 "cbc(des3_ede)",
106                 "hmac(sha1)",
107                 0,
108                 20,
109                 8,
110                 1,
111         },
112         [ENCTYPE_AES128_CTS_HMAC_SHA1_96] = {   /* aes128-cts */
113                 "aes128-cts-hmac-sha1-96",
114                 "cbc(aes)",
115                 "hmac(sha1)",
116                 0,
117                 12,
118                 16,
119                 1,
120         },
121         [ENCTYPE_AES256_CTS_HMAC_SHA1_96] = {   /* aes256-cts */
122                 "aes256-cts-hmac-sha1-96",
123                 "cbc(aes)",
124                 "hmac(sha1)",
125                 0,
126                 12,
127                 16,
128                 1,
129         },
130         [ENCTYPE_ARCFOUR_HMAC] = {              /* arcfour-hmac-md5 */
131                 "arcfour-hmac-md5",
132                 "ecb(arc4)",
133                 "hmac(md5)",
134                 0,
135                 16,
136                 8,
137                 1,
138         },
139 };
140
141 #define MAX_ENCTYPES    sizeof(enctypes)/sizeof(struct krb5_enctype)
142
143 static const char * enctype2str(__u32 enctype)
144 {
145         if (enctype < MAX_ENCTYPES && enctypes[enctype].ke_dispname)
146                 return enctypes[enctype].ke_dispname;
147
148         return "unknown";
149 }
150
151 static
152 int keyblock_init(struct krb5_keyblock *kb, char *alg_name, int alg_mode)
153 {
154         kb->kb_tfm = crypto_alloc_blkcipher(alg_name, alg_mode, 0);
155         if (IS_ERR(kb->kb_tfm)) {
156                 CERROR("failed to alloc tfm: %s, mode %d\n",
157                        alg_name, alg_mode);
158                 return -1;
159         }
160
161         if (crypto_blkcipher_setkey(kb->kb_tfm, kb->kb_key.data, kb->kb_key.len)) {
162                 CERROR("failed to set %s key, len %d\n",
163                        alg_name, kb->kb_key.len);
164                 return -1;
165         }
166
167         return 0;
168 }
169
170 static
171 int krb5_init_keys(struct krb5_ctx *kctx)
172 {
173         struct krb5_enctype *ke;
174
175         if (kctx->kc_enctype >= MAX_ENCTYPES ||
176             enctypes[kctx->kc_enctype].ke_hash_size == 0) {
177                 CERROR("unsupported enctype %x\n", kctx->kc_enctype);
178                 return -1;
179         }
180
181         ke = &enctypes[kctx->kc_enctype];
182
183         /* tfm arc4 is stateful, user should alloc-use-free by his own */
184         if (kctx->kc_enctype != ENCTYPE_ARCFOUR_HMAC &&
185             keyblock_init(&kctx->kc_keye, ke->ke_enc_name, ke->ke_enc_mode))
186                 return -1;
187
188         /* tfm hmac is stateful, user should alloc-use-free by his own */
189         if (ke->ke_hash_hmac == 0 &&
190             keyblock_init(&kctx->kc_keyi, ke->ke_enc_name, ke->ke_enc_mode))
191                 return -1;
192         if (ke->ke_hash_hmac == 0 &&
193             keyblock_init(&kctx->kc_keyc, ke->ke_enc_name, ke->ke_enc_mode))
194                 return -1;
195
196         return 0;
197 }
198
199 static
200 void keyblock_free(struct krb5_keyblock *kb)
201 {
202         rawobj_free(&kb->kb_key);
203         if (kb->kb_tfm)
204                 crypto_free_blkcipher(kb->kb_tfm);
205 }
206
207 static
208 int keyblock_dup(struct krb5_keyblock *new, struct krb5_keyblock *kb)
209 {
210         return rawobj_dup(&new->kb_key, &kb->kb_key);
211 }
212
213 static
214 int get_bytes(char **ptr, const char *end, void *res, int len)
215 {
216         char *p, *q;
217         p = *ptr;
218         q = p + len;
219         if (q > end || q < p)
220                 return -1;
221         memcpy(res, p, len);
222         *ptr = q;
223         return 0;
224 }
225
226 static
227 int get_rawobj(char **ptr, const char *end, rawobj_t *res)
228 {
229         char   *p, *q;
230         __u32   len;
231
232         p = *ptr;
233         if (get_bytes(&p, end, &len, sizeof(len)))
234                 return -1;
235
236         q = p + len;
237         if (q > end || q < p)
238                 return -1;
239
240         OBD_ALLOC_LARGE(res->data, len);
241         if (!res->data)
242                 return -1;
243
244         res->len = len;
245         memcpy(res->data, p, len);
246         *ptr = q;
247         return 0;
248 }
249
250 static
251 int get_keyblock(char **ptr, const char *end,
252                  struct krb5_keyblock *kb, __u32 keysize)
253 {
254         char *buf;
255
256         OBD_ALLOC_LARGE(buf, keysize);
257         if (buf == NULL)
258                 return -1;
259
260         if (get_bytes(ptr, end, buf, keysize)) {
261                 OBD_FREE_LARGE(buf, keysize);
262                 return -1;
263         }
264
265         kb->kb_key.len = keysize;
266         kb->kb_key.data = buf;
267         return 0;
268 }
269
270 static
271 void delete_context_kerberos(struct krb5_ctx *kctx)
272 {
273         rawobj_free(&kctx->kc_mech_used);
274
275         keyblock_free(&kctx->kc_keye);
276         keyblock_free(&kctx->kc_keyi);
277         keyblock_free(&kctx->kc_keyc);
278 }
279
280 static
281 __u32 import_context_rfc1964(struct krb5_ctx *kctx, char *p, char *end)
282 {
283         unsigned int    tmp_uint, keysize;
284
285         /* seed_init flag */
286         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
287                 goto out_err;
288         kctx->kc_seed_init = (tmp_uint != 0);
289
290         /* seed */
291         if (get_bytes(&p, end, kctx->kc_seed, sizeof(kctx->kc_seed)))
292                 goto out_err;
293
294         /* sign/seal algorithm, not really used now */
295         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)) ||
296             get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
297                 goto out_err;
298
299         /* end time */
300         if (get_bytes(&p, end, &kctx->kc_endtime, sizeof(kctx->kc_endtime)))
301                 goto out_err;
302
303         /* seq send */
304         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
305                 goto out_err;
306         kctx->kc_seq_send = tmp_uint;
307
308         /* mech oid */
309         if (get_rawobj(&p, end, &kctx->kc_mech_used))
310                 goto out_err;
311
312         /* old style enc/seq keys in format:
313          *   - enctype (u32)
314          *   - keysize (u32)
315          *   - keydata
316          * we decompose them to fit into the new context
317          */
318
319         /* enc key */
320         if (get_bytes(&p, end, &kctx->kc_enctype, sizeof(kctx->kc_enctype)))
321                 goto out_err;
322
323         if (get_bytes(&p, end, &keysize, sizeof(keysize)))
324                 goto out_err;
325
326         if (get_keyblock(&p, end, &kctx->kc_keye, keysize))
327                 goto out_err;
328
329         /* seq key */
330         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)) ||
331             tmp_uint != kctx->kc_enctype)
332                 goto out_err;
333
334         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)) ||
335             tmp_uint != keysize)
336                 goto out_err;
337
338         if (get_keyblock(&p, end, &kctx->kc_keyc, keysize))
339                 goto out_err;
340
341         /* old style fallback */
342         if (keyblock_dup(&kctx->kc_keyi, &kctx->kc_keyc))
343                 goto out_err;
344
345         if (p != end)
346                 goto out_err;
347
348         CDEBUG(D_SEC, "succesfully imported rfc1964 context\n");
349         return 0;
350 out_err:
351         return GSS_S_FAILURE;
352 }
353
354 /* Flags for version 2 context flags */
355 #define KRB5_CTX_FLAG_INITIATOR         0x00000001
356 #define KRB5_CTX_FLAG_CFX               0x00000002
357 #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY   0x00000004
358
359 static
360 __u32 import_context_rfc4121(struct krb5_ctx *kctx, char *p, char *end)
361 {
362         unsigned int    tmp_uint, keysize;
363
364         /* end time */
365         if (get_bytes(&p, end, &kctx->kc_endtime, sizeof(kctx->kc_endtime)))
366                 goto out_err;
367
368         /* flags */
369         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
370                 goto out_err;
371
372         if (tmp_uint & KRB5_CTX_FLAG_INITIATOR)
373                 kctx->kc_initiate = 1;
374         if (tmp_uint & KRB5_CTX_FLAG_CFX)
375                 kctx->kc_cfx = 1;
376         if (tmp_uint & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY)
377                 kctx->kc_have_acceptor_subkey = 1;
378
379         /* seq send */
380         if (get_bytes(&p, end, &kctx->kc_seq_send, sizeof(kctx->kc_seq_send)))
381                 goto out_err;
382
383         /* enctype */
384         if (get_bytes(&p, end, &kctx->kc_enctype, sizeof(kctx->kc_enctype)))
385                 goto out_err;
386
387         /* size of each key */
388         if (get_bytes(&p, end, &keysize, sizeof(keysize)))
389                 goto out_err;
390
391         /* number of keys - should always be 3 */
392         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint)))
393                 goto out_err;
394
395         if (tmp_uint != 3) {
396                 CERROR("Invalid number of keys: %u\n", tmp_uint);
397                 goto out_err;
398         }
399
400         /* ke */
401         if (get_keyblock(&p, end, &kctx->kc_keye, keysize))
402                 goto out_err;
403         /* ki */
404         if (get_keyblock(&p, end, &kctx->kc_keyi, keysize))
405                 goto out_err;
406         /* ki */
407         if (get_keyblock(&p, end, &kctx->kc_keyc, keysize))
408                 goto out_err;
409
410         CDEBUG(D_SEC, "succesfully imported v2 context\n");
411         return 0;
412 out_err:
413         return GSS_S_FAILURE;
414 }
415
416 /*
417  * The whole purpose here is trying to keep user level gss context parsing
418  * from nfs-utils unchanged as possible as we can, they are not quite mature
419  * yet, and many stuff still not clear, like heimdal etc.
420  */
421 static
422 __u32 gss_import_sec_context_kerberos(rawobj_t *inbuf,
423                                       struct gss_ctx *gctx)
424 {
425         struct krb5_ctx *kctx;
426         char            *p = (char *) inbuf->data;
427         char            *end = (char *) (inbuf->data + inbuf->len);
428         unsigned int     tmp_uint, rc;
429
430         if (get_bytes(&p, end, &tmp_uint, sizeof(tmp_uint))) {
431                 CERROR("Fail to read version\n");
432                 return GSS_S_FAILURE;
433         }
434
435         /* only support 0, 1 for the moment */
436         if (tmp_uint > 2) {
437                 CERROR("Invalid version %u\n", tmp_uint);
438                 return GSS_S_FAILURE;
439         }
440
441         OBD_ALLOC_PTR(kctx);
442         if (!kctx)
443                 return GSS_S_FAILURE;
444
445         if (tmp_uint == 0 || tmp_uint == 1) {
446                 kctx->kc_initiate = tmp_uint;
447                 rc = import_context_rfc1964(kctx, p, end);
448         } else {
449                 rc = import_context_rfc4121(kctx, p, end);
450         }
451
452         if (rc == 0)
453                 rc = krb5_init_keys(kctx);
454
455         if (rc) {
456                 delete_context_kerberos(kctx);
457                 OBD_FREE_PTR(kctx);
458
459                 return GSS_S_FAILURE;
460         }
461
462         gctx->internal_ctx_id = kctx;
463         return GSS_S_COMPLETE;
464 }
465
466 static
467 __u32 gss_copy_reverse_context_kerberos(struct gss_ctx *gctx,
468                                         struct gss_ctx *gctx_new)
469 {
470         struct krb5_ctx *kctx = gctx->internal_ctx_id;
471         struct krb5_ctx *knew;
472
473         OBD_ALLOC_PTR(knew);
474         if (!knew)
475                 return GSS_S_FAILURE;
476
477         knew->kc_initiate = kctx->kc_initiate ? 0 : 1;
478         knew->kc_cfx = kctx->kc_cfx;
479         knew->kc_seed_init = kctx->kc_seed_init;
480         knew->kc_have_acceptor_subkey = kctx->kc_have_acceptor_subkey;
481         knew->kc_endtime = kctx->kc_endtime;
482
483         memcpy(knew->kc_seed, kctx->kc_seed, sizeof(kctx->kc_seed));
484         knew->kc_seq_send = kctx->kc_seq_recv;
485         knew->kc_seq_recv = kctx->kc_seq_send;
486         knew->kc_enctype = kctx->kc_enctype;
487
488         if (rawobj_dup(&knew->kc_mech_used, &kctx->kc_mech_used))
489                 goto out_err;
490
491         if (keyblock_dup(&knew->kc_keye, &kctx->kc_keye))
492                 goto out_err;
493         if (keyblock_dup(&knew->kc_keyi, &kctx->kc_keyi))
494                 goto out_err;
495         if (keyblock_dup(&knew->kc_keyc, &kctx->kc_keyc))
496                 goto out_err;
497         if (krb5_init_keys(knew))
498                 goto out_err;
499
500         gctx_new->internal_ctx_id = knew;
501         CDEBUG(D_SEC, "succesfully copied reverse context\n");
502         return GSS_S_COMPLETE;
503
504 out_err:
505         delete_context_kerberos(knew);
506         OBD_FREE_PTR(knew);
507         return GSS_S_FAILURE;
508 }
509
510 static
511 __u32 gss_inquire_context_kerberos(struct gss_ctx *gctx,
512                                    unsigned long  *endtime)
513 {
514         struct krb5_ctx *kctx = gctx->internal_ctx_id;
515
516         *endtime = (unsigned long) ((__u32) kctx->kc_endtime);
517         return GSS_S_COMPLETE;
518 }
519
520 static
521 void gss_delete_sec_context_kerberos(void *internal_ctx)
522 {
523         struct krb5_ctx *kctx = internal_ctx;
524
525         delete_context_kerberos(kctx);
526         OBD_FREE_PTR(kctx);
527 }
528
529 static
530 void buf_to_sg(struct scatterlist *sg, void *ptr, int len)
531 {
532         sg_set_buf(sg, ptr, len);
533 }
534
535 static
536 __u32 krb5_encrypt(struct crypto_blkcipher *tfm,
537                    int decrypt,
538                    void * iv,
539                    void * in,
540                    void * out,
541                    int length)
542 {
543         struct blkcipher_desc desc;
544         struct scatterlist    sg;
545         __u8 local_iv[16] = {0};
546         __u32 ret = -EINVAL;
547
548         LASSERT(tfm);
549         desc.tfm  = tfm;
550         desc.info = local_iv;
551         desc.flags= 0;
552
553         if (length % crypto_blkcipher_blocksize(tfm) != 0) {
554                 CERROR("output length %d mismatch blocksize %d\n",
555                        length, crypto_blkcipher_blocksize(tfm));
556                 goto out;
557         }
558
559         if (crypto_blkcipher_ivsize(tfm) > 16) {
560                 CERROR("iv size too large %d\n", crypto_blkcipher_ivsize(tfm));
561                 goto out;
562         }
563
564         if (iv)
565                 memcpy(local_iv, iv, crypto_blkcipher_ivsize(tfm));
566
567         memcpy(out, in, length);
568         buf_to_sg(&sg, out, length);
569
570         if (decrypt)
571                 ret = crypto_blkcipher_decrypt_iv(&desc, &sg, &sg, length);
572         else
573                 ret = crypto_blkcipher_encrypt_iv(&desc, &sg, &sg, length);
574
575 out:
576         return(ret);
577 }
578
579 static inline
580 int krb5_digest_hmac(struct crypto_hash *tfm,
581                      rawobj_t *key,
582                      struct krb5_header *khdr,
583                      int msgcnt, rawobj_t *msgs,
584                      int iovcnt, lnet_kiov_t *iovs,
585                      rawobj_t *cksum)
586 {
587         struct hash_desc   desc;
588         struct scatterlist sg[1];
589         int                i;
590
591         crypto_hash_setkey(tfm, key->data, key->len);
592         desc.tfm  = tfm;
593         desc.flags= 0;
594
595         crypto_hash_init(&desc);
596
597         for (i = 0; i < msgcnt; i++) {
598                 if (msgs[i].len == 0)
599                         continue;
600                 buf_to_sg(sg, (char *) msgs[i].data, msgs[i].len);
601                 crypto_hash_update(&desc, sg, msgs[i].len);
602         }
603
604         for (i = 0; i < iovcnt; i++) {
605                 if (iovs[i].kiov_len == 0)
606                         continue;
607
608                 sg_set_page(&sg[0], iovs[i].kiov_page, iovs[i].kiov_len,
609                             iovs[i].kiov_offset);
610                 crypto_hash_update(&desc, sg, iovs[i].kiov_len);
611         }
612
613         if (khdr) {
614                 buf_to_sg(sg, (char *) khdr, sizeof(*khdr));
615                 crypto_hash_update(&desc, sg, sizeof(*khdr));
616         }
617
618         return crypto_hash_final(&desc, cksum->data);
619 }
620
621 static inline
622 int krb5_digest_norm(struct crypto_hash *tfm,
623                      struct krb5_keyblock *kb,
624                      struct krb5_header *khdr,
625                      int msgcnt, rawobj_t *msgs,
626                      int iovcnt, lnet_kiov_t *iovs,
627                      rawobj_t *cksum)
628 {
629         struct hash_desc   desc;
630         struct scatterlist sg[1];
631         int                i;
632
633         LASSERT(kb->kb_tfm);
634         desc.tfm  = tfm;
635         desc.flags= 0;
636
637         crypto_hash_init(&desc);
638
639         for (i = 0; i < msgcnt; i++) {
640                 if (msgs[i].len == 0)
641                         continue;
642                 buf_to_sg(sg, (char *) msgs[i].data, msgs[i].len);
643                 crypto_hash_update(&desc, sg, msgs[i].len);
644         }
645
646         for (i = 0; i < iovcnt; i++) {
647                 if (iovs[i].kiov_len == 0)
648                         continue;
649
650                 sg_set_page(&sg[0], iovs[i].kiov_page, iovs[i].kiov_len,
651                             iovs[i].kiov_offset);
652                 crypto_hash_update(&desc, sg, iovs[i].kiov_len);
653         }
654
655         if (khdr) {
656                 buf_to_sg(sg, (char *) khdr, sizeof(*khdr));
657                 crypto_hash_update(&desc, sg, sizeof(*khdr));
658         }
659
660         crypto_hash_final(&desc, cksum->data);
661
662         return krb5_encrypt(kb->kb_tfm, 0, NULL, cksum->data,
663                             cksum->data, cksum->len);
664 }
665
666 /*
667  * compute (keyed/keyless) checksum against the plain text which appended
668  * with krb5 wire token header.
669  */
670 static
671 __s32 krb5_make_checksum(__u32 enctype,
672                          struct krb5_keyblock *kb,
673                          struct krb5_header *khdr,
674                          int msgcnt, rawobj_t *msgs,
675                          int iovcnt, lnet_kiov_t *iovs,
676                          rawobj_t *cksum)
677 {
678         struct krb5_enctype   *ke = &enctypes[enctype];
679         struct crypto_hash    *tfm;
680         __u32                  code = GSS_S_FAILURE;
681         int                    rc;
682
683         if (!(tfm = crypto_alloc_hash(ke->ke_hash_name, 0, 0))) {
684                 CERROR("failed to alloc TFM: %s\n", ke->ke_hash_name);
685                 return GSS_S_FAILURE;
686         }
687
688         cksum->len = crypto_hash_digestsize(tfm);
689         OBD_ALLOC_LARGE(cksum->data, cksum->len);
690         if (!cksum->data) {
691                 cksum->len = 0;
692                 goto out_tfm;
693         }
694
695         if (ke->ke_hash_hmac)
696                 rc = krb5_digest_hmac(tfm, &kb->kb_key,
697                                       khdr, msgcnt, msgs, iovcnt, iovs, cksum);
698         else
699                 rc = krb5_digest_norm(tfm, kb,
700                                       khdr, msgcnt, msgs, iovcnt, iovs, cksum);
701
702         if (rc == 0)
703                 code = GSS_S_COMPLETE;
704 out_tfm:
705         crypto_free_hash(tfm);
706         return code;
707 }
708
709 static void fill_krb5_header(struct krb5_ctx *kctx,
710                              struct krb5_header *khdr,
711                              int privacy)
712 {
713         unsigned char acceptor_flag;
714
715         acceptor_flag = kctx->kc_initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
716
717         if (privacy) {
718                 khdr->kh_tok_id = cpu_to_be16(KG_TOK_WRAP_MSG);
719                 khdr->kh_flags = acceptor_flag | FLAG_WRAP_CONFIDENTIAL;
720                 khdr->kh_ec = cpu_to_be16(0);
721                 khdr->kh_rrc = cpu_to_be16(0);
722         } else {
723                 khdr->kh_tok_id = cpu_to_be16(KG_TOK_MIC_MSG);
724                 khdr->kh_flags = acceptor_flag;
725                 khdr->kh_ec = cpu_to_be16(0xffff);
726                 khdr->kh_rrc = cpu_to_be16(0xffff);
727         }
728
729         khdr->kh_filler = 0xff;
730         spin_lock(&krb5_seq_lock);
731         khdr->kh_seq = cpu_to_be64(kctx->kc_seq_send++);
732         spin_unlock(&krb5_seq_lock);
733 }
734
735 static __u32 verify_krb5_header(struct krb5_ctx *kctx,
736                                 struct krb5_header *khdr,
737                                 int privacy)
738 {
739         unsigned char acceptor_flag;
740         __u16         tok_id, ec_rrc;
741
742         acceptor_flag = kctx->kc_initiate ? FLAG_SENDER_IS_ACCEPTOR : 0;
743
744         if (privacy) {
745                 tok_id = KG_TOK_WRAP_MSG;
746                 ec_rrc = 0x0;
747         } else {
748                 tok_id = KG_TOK_MIC_MSG;
749                 ec_rrc = 0xffff;
750         }
751
752         /* sanity checks */
753         if (be16_to_cpu(khdr->kh_tok_id) != tok_id) {
754                 CERROR("bad token id\n");
755                 return GSS_S_DEFECTIVE_TOKEN;
756         }
757         if ((khdr->kh_flags & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
758                 CERROR("bad direction flag\n");
759                 return GSS_S_BAD_SIG;
760         }
761         if (privacy && (khdr->kh_flags & FLAG_WRAP_CONFIDENTIAL) == 0) {
762                 CERROR("missing confidential flag\n");
763                 return GSS_S_BAD_SIG;
764         }
765         if (khdr->kh_filler != 0xff) {
766                 CERROR("bad filler\n");
767                 return GSS_S_DEFECTIVE_TOKEN;
768         }
769         if (be16_to_cpu(khdr->kh_ec) != ec_rrc ||
770             be16_to_cpu(khdr->kh_rrc) != ec_rrc) {
771                 CERROR("bad EC or RRC\n");
772                 return GSS_S_DEFECTIVE_TOKEN;
773         }
774         return GSS_S_COMPLETE;
775 }
776
777 static
778 __u32 gss_get_mic_kerberos(struct gss_ctx *gctx,
779                            int msgcnt,
780                            rawobj_t *msgs,
781                            int iovcnt,
782                            lnet_kiov_t *iovs,
783                            rawobj_t *token)
784 {
785         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
786         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
787         struct krb5_header  *khdr;
788         rawobj_t             cksum = RAWOBJ_EMPTY;
789
790         /* fill krb5 header */
791         LASSERT(token->len >= sizeof(*khdr));
792         khdr = (struct krb5_header *) token->data;
793         fill_krb5_header(kctx, khdr, 0);
794
795         /* checksum */
796         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyc,
797                                khdr, msgcnt, msgs, iovcnt, iovs, &cksum))
798                 return GSS_S_FAILURE;
799
800         LASSERT(cksum.len >= ke->ke_hash_size);
801         LASSERT(token->len >= sizeof(*khdr) + ke->ke_hash_size);
802         memcpy(khdr + 1, cksum.data + cksum.len - ke->ke_hash_size,
803                ke->ke_hash_size);
804
805         token->len = sizeof(*khdr) + ke->ke_hash_size;
806         rawobj_free(&cksum);
807         return GSS_S_COMPLETE;
808 }
809
810 static
811 __u32 gss_verify_mic_kerberos(struct gss_ctx *gctx,
812                               int msgcnt,
813                               rawobj_t *msgs,
814                               int iovcnt,
815                               lnet_kiov_t *iovs,
816                               rawobj_t *token)
817 {
818         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
819         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
820         struct krb5_header  *khdr;
821         rawobj_t             cksum = RAWOBJ_EMPTY;
822         __u32                major;
823
824         if (token->len < sizeof(*khdr)) {
825                 CERROR("short signature: %u\n", token->len);
826                 return GSS_S_DEFECTIVE_TOKEN;
827         }
828
829         khdr = (struct krb5_header *) token->data;
830
831         major = verify_krb5_header(kctx, khdr, 0);
832         if (major != GSS_S_COMPLETE) {
833                 CERROR("bad krb5 header\n");
834                 return major;
835         }
836
837         if (token->len < sizeof(*khdr) + ke->ke_hash_size) {
838                 CERROR("short signature: %u, require %d\n",
839                        token->len, (int) sizeof(*khdr) + ke->ke_hash_size);
840                 return GSS_S_FAILURE;
841         }
842
843         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyc,
844                                khdr, msgcnt, msgs, iovcnt, iovs, &cksum)) {
845                 CERROR("failed to make checksum\n");
846                 return GSS_S_FAILURE;
847         }
848
849         LASSERT(cksum.len >= ke->ke_hash_size);
850         if (memcmp(khdr + 1, cksum.data + cksum.len - ke->ke_hash_size,
851                    ke->ke_hash_size)) {
852                 CERROR("checksum mismatch\n");
853                 rawobj_free(&cksum);
854                 return GSS_S_BAD_SIG;
855         }
856
857         rawobj_free(&cksum);
858         return GSS_S_COMPLETE;
859 }
860
861 static
862 int add_padding(rawobj_t *msg, int msg_buflen, int blocksize)
863 {
864         int padding;
865
866         padding = (blocksize - (msg->len & (blocksize - 1))) &
867                   (blocksize - 1);
868         if (!padding)
869                 return 0;
870
871         if (msg->len + padding > msg_buflen) {
872                 CERROR("bufsize %u too small: datalen %u, padding %u\n",
873                         msg_buflen, msg->len, padding);
874                 return -EINVAL;
875         }
876
877         memset(msg->data + msg->len, padding, padding);
878         msg->len += padding;
879         return 0;
880 }
881
882 static
883 int krb5_encrypt_rawobjs(struct crypto_blkcipher *tfm,
884                          int mode_ecb,
885                          int inobj_cnt,
886                          rawobj_t *inobjs,
887                          rawobj_t *outobj,
888                          int enc)
889 {
890         struct blkcipher_desc desc;
891         struct scatterlist    src, dst;
892         __u8                  local_iv[16] = {0}, *buf;
893         __u32                 datalen = 0;
894         int                   i, rc;
895         ENTRY;
896
897         buf = outobj->data;
898         desc.tfm  = tfm;
899         desc.info = local_iv;
900         desc.flags = 0;
901
902         for (i = 0; i < inobj_cnt; i++) {
903                 LASSERT(buf + inobjs[i].len <= outobj->data + outobj->len);
904
905                 buf_to_sg(&src, inobjs[i].data, inobjs[i].len);
906                 buf_to_sg(&dst, buf, outobj->len - datalen);
907
908                 if (mode_ecb) {
909                         if (enc)
910                                 rc = crypto_blkcipher_encrypt(
911                                         &desc, &dst, &src, src.length);
912                         else
913                                 rc = crypto_blkcipher_decrypt(
914                                         &desc, &dst, &src, src.length);
915                 } else {
916                         if (enc)
917                                 rc = crypto_blkcipher_encrypt_iv(
918                                         &desc, &dst, &src, src.length);
919                         else
920                                 rc = crypto_blkcipher_decrypt_iv(
921                                         &desc, &dst, &src, src.length);
922                 }
923
924                 if (rc) {
925                         CERROR("encrypt error %d\n", rc);
926                         RETURN(rc);
927                 }
928
929                 datalen += inobjs[i].len;
930                 buf += inobjs[i].len;
931         }
932
933         outobj->len = datalen;
934         RETURN(0);
935 }
936
937 /*
938  * if adj_nob != 0, we adjust desc->bd_nob to the actual cipher text size.
939  */
940 static
941 int krb5_encrypt_bulk(struct crypto_blkcipher *tfm,
942                       struct krb5_header *khdr,
943                       char *confounder,
944                       struct ptlrpc_bulk_desc *desc,
945                       rawobj_t *cipher,
946                       int adj_nob)
947 {
948         struct blkcipher_desc   ciph_desc;
949         __u8                    local_iv[16] = {0};
950         struct scatterlist      src, dst;
951         int                     blocksize, i, rc, nob = 0;
952
953         LASSERT(desc->bd_iov_count);
954         LASSERT(desc->bd_enc_iov);
955
956         blocksize = crypto_blkcipher_blocksize(tfm);
957         LASSERT(blocksize > 1);
958         LASSERT(cipher->len == blocksize + sizeof(*khdr));
959
960         ciph_desc.tfm  = tfm;
961         ciph_desc.info = local_iv;
962         ciph_desc.flags = 0;
963
964         /* encrypt confounder */
965         buf_to_sg(&src, confounder, blocksize);
966         buf_to_sg(&dst, cipher->data, blocksize);
967
968         rc = crypto_blkcipher_encrypt_iv(&ciph_desc, &dst, &src, blocksize);
969         if (rc) {
970                 CERROR("error to encrypt confounder: %d\n", rc);
971                 return rc;
972         }
973
974         /* encrypt clear pages */
975         for (i = 0; i < desc->bd_iov_count; i++) {
976                 sg_set_page(&src, desc->bd_iov[i].kiov_page,
977                             (desc->bd_iov[i].kiov_len + blocksize - 1) &
978                             (~(blocksize - 1)),
979                             desc->bd_iov[i].kiov_offset);
980                 if (adj_nob)
981                         nob += src.length;
982                 sg_set_page(&dst, desc->bd_enc_iov[i].kiov_page, src.length,
983                             src.offset);
984
985                 desc->bd_enc_iov[i].kiov_offset = dst.offset;
986                 desc->bd_enc_iov[i].kiov_len = dst.length;
987
988                 rc = crypto_blkcipher_encrypt_iv(&ciph_desc, &dst, &src,
989                                                     src.length);
990                 if (rc) {
991                         CERROR("error to encrypt page: %d\n", rc);
992                         return rc;
993                 }
994         }
995
996         /* encrypt krb5 header */
997         buf_to_sg(&src, khdr, sizeof(*khdr));
998         buf_to_sg(&dst, cipher->data + blocksize, sizeof(*khdr));
999
1000         rc = crypto_blkcipher_encrypt_iv(&ciph_desc, &dst, &src,
1001                                          sizeof(*khdr));
1002         if (rc) {
1003                 CERROR("error to encrypt krb5 header: %d\n", rc);
1004                 return rc;
1005         }
1006
1007         if (adj_nob)
1008                 desc->bd_nob = nob;
1009
1010         return 0;
1011 }
1012
1013 /*
1014  * desc->bd_nob_transferred is the size of cipher text received.
1015  * desc->bd_nob is the target size of plain text supposed to be.
1016  *
1017  * if adj_nob != 0, we adjust each page's kiov_len to the actual
1018  * plain text size.
1019  * - for client read: we don't know data size for each page, so
1020  *   bd_iov[]->kiov_len is set to PAGE_SIZE, but actual data received might
1021  *   be smaller, so we need to adjust it according to bd_enc_iov[]->kiov_len.
1022  *   this means we DO NOT support the situation that server send an odd size
1023  *   data in a page which is not the last one.
1024  * - for server write: we knows exactly data size for each page being expected,
1025  *   thus kiov_len is accurate already, so we should not adjust it at all.
1026  *   and bd_enc_iov[]->kiov_len should be round_up(bd_iov[]->kiov_len) which
1027  *   should have been done by prep_bulk().
1028  */
1029 static
1030 int krb5_decrypt_bulk(struct crypto_blkcipher *tfm,
1031                       struct krb5_header *khdr,
1032                       struct ptlrpc_bulk_desc *desc,
1033                       rawobj_t *cipher,
1034                       rawobj_t *plain,
1035                       int adj_nob)
1036 {
1037         struct blkcipher_desc   ciph_desc;
1038         __u8                    local_iv[16] = {0};
1039         struct scatterlist      src, dst;
1040         int                     ct_nob = 0, pt_nob = 0;
1041         int                     blocksize, i, rc;
1042
1043         LASSERT(desc->bd_iov_count);
1044         LASSERT(desc->bd_enc_iov);
1045         LASSERT(desc->bd_nob_transferred);
1046
1047         blocksize = crypto_blkcipher_blocksize(tfm);
1048         LASSERT(blocksize > 1);
1049         LASSERT(cipher->len == blocksize + sizeof(*khdr));
1050
1051         ciph_desc.tfm  = tfm;
1052         ciph_desc.info = local_iv;
1053         ciph_desc.flags = 0;
1054
1055         if (desc->bd_nob_transferred % blocksize) {
1056                 CERROR("odd transferred nob: %d\n", desc->bd_nob_transferred);
1057                 return -EPROTO;
1058         }
1059
1060         /* decrypt head (confounder) */
1061         buf_to_sg(&src, cipher->data, blocksize);
1062         buf_to_sg(&dst, plain->data, blocksize);
1063
1064         rc = crypto_blkcipher_decrypt_iv(&ciph_desc, &dst, &src, blocksize);
1065         if (rc) {
1066                 CERROR("error to decrypt confounder: %d\n", rc);
1067                 return rc;
1068         }
1069
1070         for (i = 0; i < desc->bd_iov_count && ct_nob < desc->bd_nob_transferred;
1071              i++) {
1072                 if (desc->bd_enc_iov[i].kiov_offset % blocksize != 0 ||
1073                     desc->bd_enc_iov[i].kiov_len % blocksize != 0) {
1074                         CERROR("page %d: odd offset %u len %u, blocksize %d\n",
1075                                i, desc->bd_enc_iov[i].kiov_offset,
1076                                desc->bd_enc_iov[i].kiov_len, blocksize);
1077                         return -EFAULT;
1078                 }
1079
1080                 if (adj_nob) {
1081                         if (ct_nob + desc->bd_enc_iov[i].kiov_len >
1082                             desc->bd_nob_transferred)
1083                                 desc->bd_enc_iov[i].kiov_len =
1084                                         desc->bd_nob_transferred - ct_nob;
1085
1086                         desc->bd_iov[i].kiov_len = desc->bd_enc_iov[i].kiov_len;
1087                         if (pt_nob + desc->bd_enc_iov[i].kiov_len >desc->bd_nob)
1088                                 desc->bd_iov[i].kiov_len = desc->bd_nob -pt_nob;
1089                 } else {
1090                         /* this should be guaranteed by LNET */
1091                         LASSERT(ct_nob + desc->bd_enc_iov[i].kiov_len <=
1092                                 desc->bd_nob_transferred);
1093                         LASSERT(desc->bd_iov[i].kiov_len <=
1094                                 desc->bd_enc_iov[i].kiov_len);
1095                 }
1096
1097                 if (desc->bd_enc_iov[i].kiov_len == 0)
1098                         continue;
1099
1100                 sg_set_page(&src, desc->bd_enc_iov[i].kiov_page,
1101                             desc->bd_enc_iov[i].kiov_len,
1102                             desc->bd_enc_iov[i].kiov_offset);
1103                 dst = src;
1104                 if (desc->bd_iov[i].kiov_len % blocksize == 0)
1105                         sg_assign_page(&dst, desc->bd_iov[i].kiov_page);
1106
1107                 rc = crypto_blkcipher_decrypt_iv(&ciph_desc, &dst, &src,
1108                                                  src.length);
1109                 if (rc) {
1110                         CERROR("error to decrypt page: %d\n", rc);
1111                         return rc;
1112                 }
1113
1114                 if (desc->bd_iov[i].kiov_len % blocksize != 0) {
1115                         memcpy(page_address(desc->bd_iov[i].kiov_page) +
1116                                desc->bd_iov[i].kiov_offset,
1117                                page_address(desc->bd_enc_iov[i].kiov_page) +
1118                                desc->bd_iov[i].kiov_offset,
1119                                desc->bd_iov[i].kiov_len);
1120                 }
1121
1122                 ct_nob += desc->bd_enc_iov[i].kiov_len;
1123                 pt_nob += desc->bd_iov[i].kiov_len;
1124         }
1125
1126         if (unlikely(ct_nob != desc->bd_nob_transferred)) {
1127                 CERROR("%d cipher text transferred but only %d decrypted\n",
1128                        desc->bd_nob_transferred, ct_nob);
1129                 return -EFAULT;
1130         }
1131
1132         if (unlikely(!adj_nob && pt_nob != desc->bd_nob)) {
1133                 CERROR("%d plain text expected but only %d received\n",
1134                        desc->bd_nob, pt_nob);
1135                 return -EFAULT;
1136         }
1137
1138         /* if needed, clear up the rest unused iovs */
1139         if (adj_nob)
1140                 while (i < desc->bd_iov_count)
1141                         desc->bd_iov[i++].kiov_len = 0;
1142
1143         /* decrypt tail (krb5 header) */
1144         buf_to_sg(&src, cipher->data + blocksize, sizeof(*khdr));
1145         buf_to_sg(&dst, cipher->data + blocksize, sizeof(*khdr));
1146
1147         rc = crypto_blkcipher_decrypt_iv(&ciph_desc, &dst, &src,
1148                                          sizeof(*khdr));
1149         if (rc) {
1150                 CERROR("error to decrypt tail: %d\n", rc);
1151                 return rc;
1152         }
1153
1154         if (memcmp(cipher->data + blocksize, khdr, sizeof(*khdr))) {
1155                 CERROR("krb5 header doesn't match\n");
1156                 return -EACCES;
1157         }
1158
1159         return 0;
1160 }
1161
1162 static
1163 __u32 gss_wrap_kerberos(struct gss_ctx *gctx,
1164                         rawobj_t *gsshdr,
1165                         rawobj_t *msg,
1166                         int msg_buflen,
1167                         rawobj_t *token)
1168 {
1169         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
1170         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
1171         struct krb5_header  *khdr;
1172         int                  blocksize;
1173         rawobj_t             cksum = RAWOBJ_EMPTY;
1174         rawobj_t             data_desc[3], cipher;
1175         __u8                 conf[GSS_MAX_CIPHER_BLOCK];
1176         int                  rc = 0;
1177
1178         LASSERT(ke);
1179         LASSERT(ke->ke_conf_size <= GSS_MAX_CIPHER_BLOCK);
1180         LASSERT(kctx->kc_keye.kb_tfm == NULL ||
1181                 ke->ke_conf_size >=
1182                 crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm));
1183
1184         /*
1185          * final token format:
1186          * ---------------------------------------------------
1187          * | krb5 header | cipher text | checksum (16 bytes) |
1188          * ---------------------------------------------------
1189          */
1190
1191         /* fill krb5 header */
1192         LASSERT(token->len >= sizeof(*khdr));
1193         khdr = (struct krb5_header *) token->data;
1194         fill_krb5_header(kctx, khdr, 1);
1195
1196         /* generate confounder */
1197         cfs_get_random_bytes(conf, ke->ke_conf_size);
1198
1199         /* get encryption blocksize. note kc_keye might not associated with
1200          * a tfm, currently only for arcfour-hmac */
1201         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1202                 LASSERT(kctx->kc_keye.kb_tfm == NULL);
1203                 blocksize = 1;
1204         } else {
1205                 LASSERT(kctx->kc_keye.kb_tfm);
1206                 blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
1207         }
1208         LASSERT(blocksize <= ke->ke_conf_size);
1209
1210         /* padding the message */
1211         if (add_padding(msg, msg_buflen, blocksize))
1212                 return GSS_S_FAILURE;
1213
1214         /*
1215          * clear text layout for checksum:
1216          * ------------------------------------------------------
1217          * | confounder | gss header | clear msgs | krb5 header |
1218          * ------------------------------------------------------
1219          */
1220         data_desc[0].data = conf;
1221         data_desc[0].len = ke->ke_conf_size;
1222         data_desc[1].data = gsshdr->data;
1223         data_desc[1].len = gsshdr->len;
1224         data_desc[2].data = msg->data;
1225         data_desc[2].len = msg->len;
1226
1227         /* compute checksum */
1228         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyi,
1229                                khdr, 3, data_desc, 0, NULL, &cksum))
1230                 return GSS_S_FAILURE;
1231         LASSERT(cksum.len >= ke->ke_hash_size);
1232
1233         /*
1234          * clear text layout for encryption:
1235          * -----------------------------------------
1236          * | confounder | clear msgs | krb5 header |
1237          * -----------------------------------------
1238          */
1239         data_desc[0].data = conf;
1240         data_desc[0].len = ke->ke_conf_size;
1241         data_desc[1].data = msg->data;
1242         data_desc[1].len = msg->len;
1243         data_desc[2].data = (__u8 *) khdr;
1244         data_desc[2].len = sizeof(*khdr);
1245
1246         /* cipher text will be directly inplace */
1247         cipher.data = (__u8 *) (khdr + 1);
1248         cipher.len = token->len - sizeof(*khdr);
1249         LASSERT(cipher.len >= ke->ke_conf_size + msg->len + sizeof(*khdr));
1250
1251         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1252                 rawobj_t                 arc4_keye;
1253                 struct crypto_blkcipher *arc4_tfm;
1254
1255                 if (krb5_make_checksum(ENCTYPE_ARCFOUR_HMAC, &kctx->kc_keyi,
1256                                        NULL, 1, &cksum, 0, NULL, &arc4_keye)) {
1257                         CERROR("failed to obtain arc4 enc key\n");
1258                         GOTO(arc4_out, rc = -EACCES);
1259                 }
1260
1261                 arc4_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, 0);
1262                 if (IS_ERR(arc4_tfm)) {
1263                         CERROR("failed to alloc tfm arc4 in ECB mode\n");
1264                         GOTO(arc4_out_key, rc = -EACCES);
1265                 }
1266
1267                 if (crypto_blkcipher_setkey(arc4_tfm, arc4_keye.data,
1268                                                arc4_keye.len)) {
1269                         CERROR("failed to set arc4 key, len %d\n",
1270                                arc4_keye.len);
1271                         GOTO(arc4_out_tfm, rc = -EACCES);
1272                 }
1273
1274                 rc = krb5_encrypt_rawobjs(arc4_tfm, 1,
1275                                           3, data_desc, &cipher, 1);
1276 arc4_out_tfm:
1277                 crypto_free_blkcipher(arc4_tfm);
1278 arc4_out_key:
1279                 rawobj_free(&arc4_keye);
1280 arc4_out:
1281                 do {} while(0); /* just to avoid compile warning */
1282         } else {
1283                 rc = krb5_encrypt_rawobjs(kctx->kc_keye.kb_tfm, 0,
1284                                           3, data_desc, &cipher, 1);
1285         }
1286
1287         if (rc != 0) {
1288                 rawobj_free(&cksum);
1289                 return GSS_S_FAILURE;
1290         }
1291
1292         /* fill in checksum */
1293         LASSERT(token->len >= sizeof(*khdr) + cipher.len + ke->ke_hash_size);
1294         memcpy((char *)(khdr + 1) + cipher.len,
1295                cksum.data + cksum.len - ke->ke_hash_size,
1296                ke->ke_hash_size);
1297         rawobj_free(&cksum);
1298
1299         /* final token length */
1300         token->len = sizeof(*khdr) + cipher.len + ke->ke_hash_size;
1301         return GSS_S_COMPLETE;
1302 }
1303
1304 static
1305 __u32 gss_prep_bulk_kerberos(struct gss_ctx *gctx,
1306                              struct ptlrpc_bulk_desc *desc)
1307 {
1308         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
1309         int                  blocksize, i;
1310
1311         LASSERT(desc->bd_iov_count);
1312         LASSERT(desc->bd_enc_iov);
1313         LASSERT(kctx->kc_keye.kb_tfm);
1314
1315         blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
1316
1317         for (i = 0; i < desc->bd_iov_count; i++) {
1318                 LASSERT(desc->bd_enc_iov[i].kiov_page);
1319                 /*
1320                  * offset should always start at page boundary of either
1321                  * client or server side.
1322                  */
1323                 if (desc->bd_iov[i].kiov_offset & blocksize) {
1324                         CERROR("odd offset %d in page %d\n",
1325                                desc->bd_iov[i].kiov_offset, i);
1326                         return GSS_S_FAILURE;
1327                 }
1328
1329                 desc->bd_enc_iov[i].kiov_offset = desc->bd_iov[i].kiov_offset;
1330                 desc->bd_enc_iov[i].kiov_len = (desc->bd_iov[i].kiov_len +
1331                                                 blocksize - 1) & (~(blocksize - 1));
1332         }
1333
1334         return GSS_S_COMPLETE;
1335 }
1336
1337 static
1338 __u32 gss_wrap_bulk_kerberos(struct gss_ctx *gctx,
1339                              struct ptlrpc_bulk_desc *desc,
1340                              rawobj_t *token, int adj_nob)
1341 {
1342         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
1343         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
1344         struct krb5_header  *khdr;
1345         int                  blocksize;
1346         rawobj_t             cksum = RAWOBJ_EMPTY;
1347         rawobj_t             data_desc[1], cipher;
1348         __u8                 conf[GSS_MAX_CIPHER_BLOCK];
1349         int                  rc = 0;
1350
1351         LASSERT(ke);
1352         LASSERT(ke->ke_conf_size <= GSS_MAX_CIPHER_BLOCK);
1353
1354         /*
1355          * final token format:
1356          * --------------------------------------------------
1357          * | krb5 header | head/tail cipher text | checksum |
1358          * --------------------------------------------------
1359          */
1360
1361         /* fill krb5 header */
1362         LASSERT(token->len >= sizeof(*khdr));
1363         khdr = (struct krb5_header *) token->data;
1364         fill_krb5_header(kctx, khdr, 1);
1365
1366         /* generate confounder */
1367         cfs_get_random_bytes(conf, ke->ke_conf_size);
1368
1369         /* get encryption blocksize. note kc_keye might not associated with
1370          * a tfm, currently only for arcfour-hmac */
1371         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1372                 LASSERT(kctx->kc_keye.kb_tfm == NULL);
1373                 blocksize = 1;
1374         } else {
1375                 LASSERT(kctx->kc_keye.kb_tfm);
1376                 blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
1377         }
1378
1379         /*
1380          * we assume the size of krb5_header (16 bytes) must be n * blocksize.
1381          * the bulk token size would be exactly (sizeof(krb5_header) +
1382          * blocksize + sizeof(krb5_header) + hashsize)
1383          */
1384         LASSERT(blocksize <= ke->ke_conf_size);
1385         LASSERT(sizeof(*khdr) >= blocksize && sizeof(*khdr) % blocksize == 0);
1386         LASSERT(token->len >= sizeof(*khdr) + blocksize + sizeof(*khdr) + 16);
1387
1388         /*
1389          * clear text layout for checksum:
1390          * ------------------------------------------
1391          * | confounder | clear pages | krb5 header |
1392          * ------------------------------------------
1393          */
1394         data_desc[0].data = conf;
1395         data_desc[0].len = ke->ke_conf_size;
1396
1397         /* compute checksum */
1398         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyi,
1399                                khdr, 1, data_desc,
1400                                desc->bd_iov_count, desc->bd_iov,
1401                                &cksum))
1402                 return GSS_S_FAILURE;
1403         LASSERT(cksum.len >= ke->ke_hash_size);
1404
1405         /*
1406          * clear text layout for encryption:
1407          * ------------------------------------------
1408          * | confounder | clear pages | krb5 header |
1409          * ------------------------------------------
1410          *        |              |             |
1411          *        ----------  (cipher pages)   |
1412          * result token:   |                   |
1413          * -------------------------------------------
1414          * | krb5 header | cipher text | cipher text |
1415          * -------------------------------------------
1416          */
1417         data_desc[0].data = conf;
1418         data_desc[0].len = ke->ke_conf_size;
1419
1420         cipher.data = (__u8 *) (khdr + 1);
1421         cipher.len = blocksize + sizeof(*khdr);
1422
1423         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1424                 LBUG();
1425                 rc = 0;
1426         } else {
1427                 rc = krb5_encrypt_bulk(kctx->kc_keye.kb_tfm, khdr,
1428                                        conf, desc, &cipher, adj_nob);
1429         }
1430
1431         if (rc != 0) {
1432                 rawobj_free(&cksum);
1433                 return GSS_S_FAILURE;
1434         }
1435
1436         /* fill in checksum */
1437         LASSERT(token->len >= sizeof(*khdr) + cipher.len + ke->ke_hash_size);
1438         memcpy((char *)(khdr + 1) + cipher.len,
1439                cksum.data + cksum.len - ke->ke_hash_size,
1440                ke->ke_hash_size);
1441         rawobj_free(&cksum);
1442
1443         /* final token length */
1444         token->len = sizeof(*khdr) + cipher.len + ke->ke_hash_size;
1445         return GSS_S_COMPLETE;
1446 }
1447
1448 static
1449 __u32 gss_unwrap_kerberos(struct gss_ctx  *gctx,
1450                           rawobj_t        *gsshdr,
1451                           rawobj_t        *token,
1452                           rawobj_t        *msg)
1453 {
1454         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
1455         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
1456         struct krb5_header  *khdr;
1457         unsigned char       *tmpbuf;
1458         int                  blocksize, bodysize;
1459         rawobj_t             cksum = RAWOBJ_EMPTY;
1460         rawobj_t             cipher_in, plain_out;
1461         rawobj_t             hash_objs[3];
1462         int                  rc = 0;
1463         __u32                major;
1464
1465         LASSERT(ke);
1466
1467         if (token->len < sizeof(*khdr)) {
1468                 CERROR("short signature: %u\n", token->len);
1469                 return GSS_S_DEFECTIVE_TOKEN;
1470         }
1471
1472         khdr = (struct krb5_header *) token->data;
1473
1474         major = verify_krb5_header(kctx, khdr, 1);
1475         if (major != GSS_S_COMPLETE) {
1476                 CERROR("bad krb5 header\n");
1477                 return major;
1478         }
1479
1480         /* block size */
1481         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1482                 LASSERT(kctx->kc_keye.kb_tfm == NULL);
1483                 blocksize = 1;
1484         } else {
1485                 LASSERT(kctx->kc_keye.kb_tfm);
1486                 blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
1487         }
1488
1489         /* expected token layout:
1490          * ----------------------------------------
1491          * | krb5 header | cipher text | checksum |
1492          * ----------------------------------------
1493          */
1494         bodysize = token->len - sizeof(*khdr) - ke->ke_hash_size;
1495
1496         if (bodysize % blocksize) {
1497                 CERROR("odd bodysize %d\n", bodysize);
1498                 return GSS_S_DEFECTIVE_TOKEN;
1499         }
1500
1501         if (bodysize <= ke->ke_conf_size + sizeof(*khdr)) {
1502                 CERROR("incomplete token: bodysize %d\n", bodysize);
1503                 return GSS_S_DEFECTIVE_TOKEN;
1504         }
1505
1506         if (msg->len < bodysize - ke->ke_conf_size - sizeof(*khdr)) {
1507                 CERROR("buffer too small: %u, require %d\n",
1508                        msg->len, bodysize - ke->ke_conf_size);
1509                 return GSS_S_FAILURE;
1510         }
1511
1512         /* decrypting */
1513         OBD_ALLOC_LARGE(tmpbuf, bodysize);
1514         if (!tmpbuf)
1515                 return GSS_S_FAILURE;
1516
1517         major = GSS_S_FAILURE;
1518
1519         cipher_in.data = (__u8 *) (khdr + 1);
1520         cipher_in.len = bodysize;
1521         plain_out.data = tmpbuf;
1522         plain_out.len = bodysize;
1523
1524         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1525                 rawobj_t                 arc4_keye;
1526                 struct crypto_blkcipher *arc4_tfm;
1527
1528                 cksum.data = token->data + token->len - ke->ke_hash_size;
1529                 cksum.len = ke->ke_hash_size;
1530
1531                 if (krb5_make_checksum(ENCTYPE_ARCFOUR_HMAC, &kctx->kc_keyi,
1532                                        NULL, 1, &cksum, 0, NULL, &arc4_keye)) {
1533                         CERROR("failed to obtain arc4 enc key\n");
1534                         GOTO(arc4_out, rc = -EACCES);
1535                 }
1536
1537                 arc4_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, 0);
1538                 if (IS_ERR(arc4_tfm)) {
1539                         CERROR("failed to alloc tfm arc4 in ECB mode\n");
1540                         GOTO(arc4_out_key, rc = -EACCES);
1541                 }
1542
1543                 if (crypto_blkcipher_setkey(arc4_tfm,
1544                                          arc4_keye.data, arc4_keye.len)) {
1545                         CERROR("failed to set arc4 key, len %d\n",
1546                                arc4_keye.len);
1547                         GOTO(arc4_out_tfm, rc = -EACCES);
1548                 }
1549
1550                 rc = krb5_encrypt_rawobjs(arc4_tfm, 1,
1551                                           1, &cipher_in, &plain_out, 0);
1552 arc4_out_tfm:
1553                 crypto_free_blkcipher(arc4_tfm);
1554 arc4_out_key:
1555                 rawobj_free(&arc4_keye);
1556 arc4_out:
1557                 cksum = RAWOBJ_EMPTY;
1558         } else {
1559                 rc = krb5_encrypt_rawobjs(kctx->kc_keye.kb_tfm, 0,
1560                                           1, &cipher_in, &plain_out, 0);
1561         }
1562
1563         if (rc != 0) {
1564                 CERROR("error decrypt\n");
1565                 goto out_free;
1566         }
1567         LASSERT(plain_out.len == bodysize);
1568
1569         /* expected clear text layout:
1570          * -----------------------------------------
1571          * | confounder | clear msgs | krb5 header |
1572          * -----------------------------------------
1573          */
1574
1575         /* verify krb5 header in token is not modified */
1576         if (memcmp(khdr, plain_out.data + plain_out.len - sizeof(*khdr),
1577                    sizeof(*khdr))) {
1578                 CERROR("decrypted krb5 header mismatch\n");
1579                 goto out_free;
1580         }
1581
1582         /* verify checksum, compose clear text as layout:
1583          * ------------------------------------------------------
1584          * | confounder | gss header | clear msgs | krb5 header |
1585          * ------------------------------------------------------
1586          */
1587         hash_objs[0].len = ke->ke_conf_size;
1588         hash_objs[0].data = plain_out.data;
1589         hash_objs[1].len = gsshdr->len;
1590         hash_objs[1].data = gsshdr->data;
1591         hash_objs[2].len = plain_out.len - ke->ke_conf_size - sizeof(*khdr);
1592         hash_objs[2].data = plain_out.data + ke->ke_conf_size;
1593         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyi,
1594                                khdr, 3, hash_objs, 0, NULL, &cksum))
1595                 goto out_free;
1596
1597         LASSERT(cksum.len >= ke->ke_hash_size);
1598         if (memcmp((char *)(khdr + 1) + bodysize,
1599                    cksum.data + cksum.len - ke->ke_hash_size,
1600                    ke->ke_hash_size)) {
1601                 CERROR("checksum mismatch\n");
1602                 goto out_free;
1603         }
1604
1605         msg->len =  bodysize - ke->ke_conf_size - sizeof(*khdr);
1606         memcpy(msg->data, tmpbuf + ke->ke_conf_size, msg->len);
1607
1608         major = GSS_S_COMPLETE;
1609 out_free:
1610         OBD_FREE_LARGE(tmpbuf, bodysize);
1611         rawobj_free(&cksum);
1612         return major;
1613 }
1614
1615 static
1616 __u32 gss_unwrap_bulk_kerberos(struct gss_ctx *gctx,
1617                                struct ptlrpc_bulk_desc *desc,
1618                                rawobj_t *token, int adj_nob)
1619 {
1620         struct krb5_ctx     *kctx = gctx->internal_ctx_id;
1621         struct krb5_enctype *ke = &enctypes[kctx->kc_enctype];
1622         struct krb5_header  *khdr;
1623         int                  blocksize;
1624         rawobj_t             cksum = RAWOBJ_EMPTY;
1625         rawobj_t             cipher, plain;
1626         rawobj_t             data_desc[1];
1627         int                  rc;
1628         __u32                major;
1629
1630         LASSERT(ke);
1631
1632         if (token->len < sizeof(*khdr)) {
1633                 CERROR("short signature: %u\n", token->len);
1634                 return GSS_S_DEFECTIVE_TOKEN;
1635         }
1636
1637         khdr = (struct krb5_header *) token->data;
1638
1639         major = verify_krb5_header(kctx, khdr, 1);
1640         if (major != GSS_S_COMPLETE) {
1641                 CERROR("bad krb5 header\n");
1642                 return major;
1643         }
1644
1645         /* block size */
1646         if (kctx->kc_enctype == ENCTYPE_ARCFOUR_HMAC) {
1647                 LASSERT(kctx->kc_keye.kb_tfm == NULL);
1648                 blocksize = 1;
1649                 LBUG();
1650         } else {
1651                 LASSERT(kctx->kc_keye.kb_tfm);
1652                 blocksize = crypto_blkcipher_blocksize(kctx->kc_keye.kb_tfm);
1653         }
1654         LASSERT(sizeof(*khdr) >= blocksize && sizeof(*khdr) % blocksize == 0);
1655
1656         /*
1657          * token format is expected as:
1658          * -----------------------------------------------
1659          * | krb5 header | head/tail cipher text | cksum |
1660          * -----------------------------------------------
1661          */
1662         if (token->len < sizeof(*khdr) + blocksize + sizeof(*khdr) +
1663                          ke->ke_hash_size) {
1664                 CERROR("short token size: %u\n", token->len);
1665                 return GSS_S_DEFECTIVE_TOKEN;
1666         }
1667
1668         cipher.data = (__u8 *) (khdr + 1);
1669         cipher.len = blocksize + sizeof(*khdr);
1670         plain.data = cipher.data;
1671         plain.len = cipher.len;
1672
1673         rc = krb5_decrypt_bulk(kctx->kc_keye.kb_tfm, khdr,
1674                                desc, &cipher, &plain, adj_nob);
1675         if (rc)
1676                 return GSS_S_DEFECTIVE_TOKEN;
1677
1678         /*
1679          * verify checksum, compose clear text as layout:
1680          * ------------------------------------------
1681          * | confounder | clear pages | krb5 header |
1682          * ------------------------------------------
1683          */
1684         data_desc[0].data = plain.data;
1685         data_desc[0].len = blocksize;
1686
1687         if (krb5_make_checksum(kctx->kc_enctype, &kctx->kc_keyi,
1688                                khdr, 1, data_desc,
1689                                desc->bd_iov_count, desc->bd_iov,
1690                                &cksum))
1691                 return GSS_S_FAILURE;
1692         LASSERT(cksum.len >= ke->ke_hash_size);
1693
1694         if (memcmp(plain.data + blocksize + sizeof(*khdr),
1695                    cksum.data + cksum.len - ke->ke_hash_size,
1696                    ke->ke_hash_size)) {
1697                 CERROR("checksum mismatch\n");
1698                 rawobj_free(&cksum);
1699                 return GSS_S_BAD_SIG;
1700         }
1701
1702         rawobj_free(&cksum);
1703         return GSS_S_COMPLETE;
1704 }
1705
1706 int gss_display_kerberos(struct gss_ctx        *ctx,
1707                          char                  *buf,
1708                          int                    bufsize)
1709 {
1710         struct krb5_ctx    *kctx = ctx->internal_ctx_id;
1711         int                 written;
1712
1713         written = snprintf(buf, bufsize, "krb5 (%s)",
1714                            enctype2str(kctx->kc_enctype));
1715         return written;
1716 }
1717
1718 static struct gss_api_ops gss_kerberos_ops = {
1719         .gss_import_sec_context     = gss_import_sec_context_kerberos,
1720         .gss_copy_reverse_context   = gss_copy_reverse_context_kerberos,
1721         .gss_inquire_context        = gss_inquire_context_kerberos,
1722         .gss_get_mic                = gss_get_mic_kerberos,
1723         .gss_verify_mic             = gss_verify_mic_kerberos,
1724         .gss_wrap                   = gss_wrap_kerberos,
1725         .gss_unwrap                 = gss_unwrap_kerberos,
1726         .gss_prep_bulk              = gss_prep_bulk_kerberos,
1727         .gss_wrap_bulk              = gss_wrap_bulk_kerberos,
1728         .gss_unwrap_bulk            = gss_unwrap_bulk_kerberos,
1729         .gss_delete_sec_context     = gss_delete_sec_context_kerberos,
1730         .gss_display                = gss_display_kerberos,
1731 };
1732
1733 static struct subflavor_desc gss_kerberos_sfs[] = {
1734         {
1735                 .sf_subflavor   = SPTLRPC_SUBFLVR_KRB5N,
1736                 .sf_qop         = 0,
1737                 .sf_service     = SPTLRPC_SVC_NULL,
1738                 .sf_name        = "krb5n"
1739         },
1740         {
1741                 .sf_subflavor   = SPTLRPC_SUBFLVR_KRB5A,
1742                 .sf_qop         = 0,
1743                 .sf_service     = SPTLRPC_SVC_AUTH,
1744                 .sf_name        = "krb5a"
1745         },
1746         {
1747                 .sf_subflavor   = SPTLRPC_SUBFLVR_KRB5I,
1748                 .sf_qop         = 0,
1749                 .sf_service     = SPTLRPC_SVC_INTG,
1750                 .sf_name        = "krb5i"
1751         },
1752         {
1753                 .sf_subflavor   = SPTLRPC_SUBFLVR_KRB5P,
1754                 .sf_qop         = 0,
1755                 .sf_service     = SPTLRPC_SVC_PRIV,
1756                 .sf_name        = "krb5p"
1757         },
1758 };
1759
1760 /*
1761  * currently we leave module owner NULL
1762  */
1763 static struct gss_api_mech gss_kerberos_mech = {
1764         .gm_owner       = NULL, /*THIS_MODULE, */
1765         .gm_name        = "krb5",
1766         .gm_oid         = (rawobj_t)
1767                                 {9, "\052\206\110\206\367\022\001\002\002"},
1768         .gm_ops         = &gss_kerberos_ops,
1769         .gm_sf_num      = 4,
1770         .gm_sfs         = gss_kerberos_sfs,
1771 };
1772
1773 int __init init_kerberos_module(void)
1774 {
1775         int status;
1776
1777         spin_lock_init(&krb5_seq_lock);
1778
1779         status = lgss_mech_register(&gss_kerberos_mech);
1780         if (status)
1781                 CERROR("Failed to register kerberos gss mechanism!\n");
1782         return status;
1783 }
1784
1785 void __exit cleanup_kerberos_module(void)
1786 {
1787         lgss_mech_unregister(&gss_kerberos_mech);
1788 }