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