Whamcloud - gitweb
current branches now use lnet from HEAD
[fs/lustre-release.git] / lustre / sec / gss / gss_krb5_crypto.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  * Copyright 2004, Cluster File Systems, Inc.
6  * All rights reserved
7  * Author: Eric Mei <ericm@clusterfs.com>
8  */
9
10 /*
11  *  linux/net/sunrpc/gss_krb5_crypto.c
12  *
13  *  Copyright (c) 2000 The Regents of the University of Michigan.
14  *  All rights reserved.
15  *
16  *  Andy Adamson   <andros@umich.edu>
17  *  Bruce Fields   <bfields@umich.edu>
18  */
19
20 /*
21  * Copyright (C) 1998 by the FundsXpress, INC.
22  *
23  * All rights reserved.
24  *
25  * Export of this software from the United States of America may require
26  * a specific license from the United States Government.  It is the
27  * responsibility of any person or organization contemplating export to
28  * obtain such a license before exporting.
29  *
30  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
31  * distribute this software and its documentation for any purpose and
32  * without fee is hereby granted, provided that the above copyright
33  * notice appear in all copies and that both that copyright notice and
34  * this permission notice appear in supporting documentation, and that
35  * the name of FundsXpress. not be used in advertising or publicity pertaining
36  * to distribution of the software without specific, written prior
37  * permission.  FundsXpress makes no representations about the suitability of
38  * this software for any purpose.  It is provided "as is" without express
39  * or implied warranty.
40  *
41  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
42  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
43  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
44  */
45
46 #ifndef EXPORT_SYMTAB
47 # define EXPORT_SYMTAB
48 #endif
49 #define DEBUG_SUBSYSTEM S_SEC
50 #ifdef __KERNEL__
51 #include <linux/init.h>
52 #include <linux/module.h>
53 #include <linux/slab.h>
54 #include <linux/crypto.h>
55 #else
56 #include <liblustre.h>
57 //#include "../kcrypto/libcrypto.h"
58 #endif
59
60 #include <libcfs/kp30.h>
61 #include <linux/obd.h>
62 #include <linux/obd_class.h>
63 #include <linux/obd_support.h>
64 #include <linux/lustre_idl.h>
65 #include <linux/lustre_net.h>
66 #include <linux/lustre_import.h>
67 #include <linux/lustre_sec.h>
68
69 #include "gss_err.h"
70 #include "gss_internal.h"
71 #include "gss_api.h"
72 #include "gss_krb5.h"
73
74 __u32
75 krb5_encrypt(struct crypto_tfm *tfm,
76              void * iv,
77              void * in,
78              void * out,
79              int length)
80 {
81         __u32 ret = -EINVAL;
82 #ifdef __KERNEL__
83         struct scatterlist sg[1];
84         __u8 local_iv[16] = {0};
85
86         if (length % crypto_tfm_alg_blocksize(tfm) != 0)
87                 goto out;
88
89         if (crypto_tfm_alg_ivsize(tfm) > 16) {
90                 CERROR("tfm iv size to large %d\n", crypto_tfm_alg_ivsize(tfm));
91                 goto out;
92         }
93
94         if (iv)
95                 memcpy(local_iv, iv, crypto_tfm_alg_ivsize(tfm));
96
97         memcpy(out, in, length);
98         sg[0].page = virt_to_page(out);
99         sg[0].offset = offset_in_page(out);
100         sg[0].length = length;
101
102         ret = crypto_cipher_encrypt_iv(tfm, sg, sg, length, local_iv);
103
104 out:
105 #endif  
106         return(ret);
107 }
108
109 //EXPORT_SYMBOL(krb5_encrypt);
110
111 __u32
112 krb5_decrypt(struct crypto_tfm *tfm,
113              void * iv,
114              void * in,
115              void * out,
116              int length)
117 {
118         __u32 ret = -EINVAL;
119 #ifdef __KERNEL__
120         struct scatterlist sg[1];
121         __u8 local_iv[16] = {0};
122
123         if (length % crypto_tfm_alg_blocksize(tfm) != 0)
124                 goto out;
125
126         if (crypto_tfm_alg_ivsize(tfm) > 16) {
127                 CERROR("tfm iv size to large %d\n", crypto_tfm_alg_ivsize(tfm));
128                 goto out;
129         }
130         if (iv)
131                 memcpy(local_iv,iv, crypto_tfm_alg_ivsize(tfm));
132
133         memcpy(out, in, length);
134         sg[0].page = virt_to_page(out);
135         sg[0].offset = offset_in_page(out);
136         sg[0].length = length;
137
138         ret = crypto_cipher_decrypt_iv(tfm, sg, sg, length, local_iv);
139
140 out:
141 #endif
142         return(ret);
143 }
144
145 //EXPORT_SYMBOL(krb5_decrypt);
146
147 #ifdef __KERNEL__
148 void
149 buf_to_sg(struct scatterlist *sg, char *ptr, int len)
150 {
151         sg->page = virt_to_page(ptr);
152         sg->offset = offset_in_page(ptr);
153         sg->length = len;
154 }
155
156 /* checksum the plaintext data and hdrlen bytes of the token header */
157 __s32
158 make_checksum(__s32 cksumtype,
159               char *header, int hdrlen,
160               rawobj_t *body,
161               rawobj_t *cksum)
162 {
163         char                           *cksumname;
164         struct crypto_tfm              *tfm = NULL; /* XXX add to ctx? */
165         struct scatterlist              sg[1];
166         __u32                           code = GSS_S_FAILURE;
167
168         switch (cksumtype) {
169                 case CKSUMTYPE_RSA_MD5:
170                         cksumname = "md5";
171                         break;
172                 default:
173                         CERROR("unsupported checksum %d", cksumtype);
174                         goto out;
175         }
176         if (!(tfm = crypto_alloc_tfm(cksumname, 0)))
177                 goto out;
178         cksum->len = crypto_tfm_alg_digestsize(tfm);
179         OBD_ALLOC(cksum->data, cksum->len);
180         if (!cksum->data)
181                 goto out;
182
183         crypto_digest_init(tfm);
184         buf_to_sg(sg, header, hdrlen);
185         crypto_digest_update(tfm, sg, 1);
186         if (body->len) {
187                 buf_to_sg(sg, (char *)body->data, body->len);
188                 crypto_digest_update(tfm, sg, 1);
189         }
190
191         crypto_digest_final(tfm, cksum->data);
192         code = 0;
193 out:
194         if (tfm)
195                 crypto_free_tfm(tfm);
196         return code;
197 }
198
199 //EXPORT_SYMBOL(make_checksum);
200
201 static
202 void obj_to_scatter_list(rawobj_t *obj, struct scatterlist *list,
203                          int listlen)
204 {
205         __u8   *ptr = obj->data;
206         __u32   size = obj->len;
207         int index = 0;
208
209         while (size) {
210                 LASSERT(index++ < listlen);
211                 list->page = virt_to_page(ptr);
212                 list->offset = (int) ptr & (~PAGE_MASK);
213                 list->length = (list->offset + size) > PAGE_SIZE ?
214                                 (PAGE_SIZE - list->offset) : size;
215                 ptr += list->length;
216                 size -= list->length;
217                 list++;
218         }
219 }
220 #endif
221
222 int gss_encrypt_rawobj(struct crypto_tfm *tfm,
223                        rawobj_t *inobj, rawobj_t *outobj,
224                        int enc)
225 {
226         int rc = -EINVAL;
227 #ifdef __KERNEL__
228         struct scatterlist *src_list, *dst_list;
229         __u8 local_iv[16] = {0};
230         int list_len;
231         ENTRY;
232
233         LASSERT(outobj->len >= inobj->len);
234
235         list_len = ((inobj->len + PAGE_SIZE - 1) >> PAGE_SHIFT) + 1;
236         OBD_ALLOC(src_list, sizeof(*src_list) * list_len * 2);
237         if (!src_list) {
238                 CERROR("can't alloc %d\n", sizeof(*src_list) * list_len * 2);
239                 RETURN(-ENOMEM);
240         }
241         dst_list = src_list + list_len;
242
243         obj_to_scatter_list(inobj, src_list, list_len);
244         obj_to_scatter_list(outobj, dst_list, list_len);
245
246         if (enc)
247                 rc = crypto_cipher_encrypt_iv(tfm, dst_list, src_list,
248                                               inobj->len, local_iv);
249         else
250                 rc = crypto_cipher_decrypt_iv(tfm, dst_list, src_list,
251                                               inobj->len, local_iv);
252
253         if (rc) {
254                 CERROR("encrypt error %u\n", rc);
255                 GOTO(out_free, rc);
256         }
257
258         outobj->len = inobj->len;
259         EXIT;
260 out_free:
261         OBD_FREE(src_list, sizeof(*src_list) * list_len * 2);
262 #endif
263         return rc;
264 }