Whamcloud - gitweb
LU-8901 misc: update Intel copyright messages for 2016
[fs/lustre-release.git] / lustre / ptlrpc / gss / gss_crypto.c
1 /*
2  * Modifications for Lustre
3  *
4  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
5  *
6  * Author: Eric Mei <ericm@clusterfs.com>
7  */
8
9 /*
10  *  linux/net/sunrpc/gss_krb5_mech.c
11  *  linux/net/sunrpc/gss_krb5_crypto.c
12  *  linux/net/sunrpc/gss_krb5_seal.c
13  *  linux/net/sunrpc/gss_krb5_seqnum.c
14  *  linux/net/sunrpc/gss_krb5_unseal.c
15  *
16  *  Copyright (c) 2001 The Regents of the University of Michigan.
17  *  All rights reserved.
18  *
19  *  Andy Adamson <andros@umich.edu>
20  *  J. Bruce Fields <bfields@umich.edu>
21  *
22  *  Redistribution and use in source and binary forms, with or without
23  *  modification, are permitted provided that the following conditions
24  *  are met:
25  *
26  *  1. Redistributions of source code must retain the above copyright
27  *     notice, this list of conditions and the following disclaimer.
28  *  2. Redistributions in binary form must reproduce the above copyright
29  *     notice, this list of conditions and the following disclaimer in the
30  *     documentation and/or other materials provided with the distribution.
31  *  3. Neither the name of the University nor the names of its
32  *     contributors may be used to endorse or promote products derived
33  *     from this software without specific prior written permission.
34  *
35  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
36  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
37  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
43  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
44  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
45  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46  *
47  */
48
49 #define DEBUG_SUBSYSTEM S_SEC
50
51 #include <libcfs/linux/linux-crypto.h>
52 #include <obd.h>
53 #include <obd_support.h>
54
55 #include "gss_internal.h"
56 #include "gss_crypto.h"
57
58 int gss_keyblock_init(struct gss_keyblock *kb, char *alg_name,
59                       const int alg_mode)
60 {
61         int rc;
62
63         kb->kb_tfm = crypto_alloc_blkcipher(alg_name, alg_mode, 0);
64         if (IS_ERR(kb->kb_tfm)) {
65                 rc = PTR_ERR(kb->kb_tfm);
66                 kb->kb_tfm = NULL;
67                 CERROR("failed to alloc tfm: %s, mode %d: rc = %d\n", alg_name,
68                        alg_mode, rc);
69                 return rc;
70         }
71
72         rc = crypto_blkcipher_setkey(kb->kb_tfm, kb->kb_key.data,
73                                      kb->kb_key.len);
74         if (rc) {
75                 CERROR("failed to set %s key, len %d, rc = %d\n", alg_name,
76                        kb->kb_key.len, rc);
77                 return rc;
78         }
79
80         return 0;
81 }
82
83 void gss_keyblock_free(struct gss_keyblock *kb)
84 {
85         rawobj_free(&kb->kb_key);
86         if (kb->kb_tfm)
87                 crypto_free_blkcipher(kb->kb_tfm);
88 }
89
90 int gss_keyblock_dup(struct gss_keyblock *new, struct gss_keyblock *kb)
91 {
92         return rawobj_dup(&new->kb_key, &kb->kb_key);
93 }
94
95 int gss_get_bytes(char **ptr, const char *end, void *res, size_t len)
96 {
97         char *p, *q;
98         p = *ptr;
99         q = p + len;
100         if (q > end || q < p)
101                 return -EINVAL;
102         memcpy(res, p, len);
103         *ptr = q;
104         return 0;
105 }
106
107 int gss_get_rawobj(char **ptr, const char *end, rawobj_t *res)
108 {
109         char   *p, *q;
110         __u32   len;
111
112         p = *ptr;
113         if (gss_get_bytes(&p, end, &len, sizeof(len)))
114                 return -EINVAL;
115
116         q = p + len;
117         if (q > end || q < p)
118                 return -EINVAL;
119
120         /* Support empty objects */
121         if (len != 0) {
122                 OBD_ALLOC_LARGE(res->data, len);
123                 if (!res->data)
124                         return -ENOMEM;
125         } else {
126                 res->len = len;
127                 res->data = NULL;
128                 return 0;
129         }
130
131         res->len = len;
132         memcpy(res->data, p, len);
133         *ptr = q;
134         return 0;
135 }
136
137 int gss_get_keyblock(char **ptr, const char *end,
138                      struct gss_keyblock *kb, __u32 keysize)
139 {
140         char *buf;
141         int rc;
142
143         OBD_ALLOC_LARGE(buf, keysize);
144         if (buf == NULL)
145                 return -ENOMEM;
146
147         rc = gss_get_bytes(ptr, end, buf, keysize);
148         if (rc) {
149                 OBD_FREE_LARGE(buf, keysize);
150                 return rc;
151         }
152
153         kb->kb_key.len = keysize;
154         kb->kb_key.data = buf;
155         return 0;
156 }
157
158 /*
159  * Should be used for buffers allocated with k/vmalloc().
160  *
161  * Dispose of @sgt with gss_teardown_sgtable().
162  *
163  * @prealloc_sg is to avoid memory allocation inside sg_alloc_table()
164  * in cases where a single sg is sufficient.  No attempt to reduce the
165  * number of sgs by squeezing physically contiguous pages together is
166  * made though, for simplicity.
167  *
168  * This function is copied from the ceph filesystem code.
169  */
170 int gss_setup_sgtable(struct sg_table *sgt, struct scatterlist *prealloc_sg,
171                       const void *buf, unsigned int buf_len)
172 {
173         struct scatterlist *sg;
174         const bool is_vmalloc = is_vmalloc_addr(buf);
175         unsigned int off = offset_in_page(buf);
176         unsigned int chunk_cnt = 1;
177         unsigned int chunk_len = PAGE_ALIGN(off + buf_len);
178         int i;
179         int rc;
180
181         if (buf_len == 0) {
182                 memset(sgt, 0, sizeof(*sgt));
183                 return -EINVAL;
184         }
185
186         if (is_vmalloc) {
187                 chunk_cnt = chunk_len >> PAGE_SHIFT;
188                 chunk_len = PAGE_SIZE;
189         }
190
191         if (chunk_cnt > 1) {
192                 rc = sg_alloc_table(sgt, chunk_cnt, GFP_NOFS);
193                 if (rc)
194                         return rc;
195         } else {
196                 WARN_ON_ONCE(chunk_cnt != 1);
197                 sg_init_table(prealloc_sg, 1);
198                 sgt->sgl = prealloc_sg;
199                 sgt->nents = sgt->orig_nents = 1;
200         }
201
202         for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) {
203                 struct page *page;
204                 unsigned int len = min(chunk_len - off, buf_len);
205
206                 if (is_vmalloc)
207                         page = vmalloc_to_page(buf);
208                 else
209                         page = virt_to_page(buf);
210
211                 sg_set_page(sg, page, len, off);
212
213                 off = 0;
214                 buf += len;
215                 buf_len -= len;
216         }
217
218         WARN_ON_ONCE(buf_len != 0);
219
220         return 0;
221 }
222
223 void gss_teardown_sgtable(struct sg_table *sgt)
224 {
225         if (sgt->orig_nents > 1)
226                 sg_free_table(sgt);
227 }
228
229 int gss_crypt_generic(struct crypto_blkcipher *tfm, int decrypt, const void *iv,
230                       const void *in, void *out, size_t length)
231 {
232         struct blkcipher_desc desc;
233         struct scatterlist sg;
234         struct sg_table sg_out;
235         __u8 local_iv[16] = {0};
236         __u32 ret = -EINVAL;
237
238         LASSERT(tfm);
239         desc.tfm = tfm;
240         desc.info = local_iv;
241         desc.flags = 0;
242
243         if (length % crypto_blkcipher_blocksize(tfm) != 0) {
244                 CERROR("output length %zu mismatch blocksize %d\n",
245                        length, crypto_blkcipher_blocksize(tfm));
246                 goto out;
247         }
248
249         if (crypto_blkcipher_ivsize(tfm) > ARRAY_SIZE(local_iv)) {
250                 CERROR("iv size too large %d\n", crypto_blkcipher_ivsize(tfm));
251                 goto out;
252         }
253
254         if (iv)
255                 memcpy(local_iv, iv, crypto_blkcipher_ivsize(tfm));
256
257         memcpy(out, in, length);
258
259         ret = gss_setup_sgtable(&sg_out, &sg, out, length);
260         if (ret != 0)
261                 goto out;
262
263         if (decrypt)
264                 ret = crypto_blkcipher_decrypt_iv(&desc, &sg, &sg, length);
265         else
266                 ret = crypto_blkcipher_encrypt_iv(&desc, &sg, &sg, length);
267
268         gss_teardown_sgtable(&sg_out);
269 out:
270         return ret;
271 }
272
273 int gss_digest_hmac(struct crypto_hash *tfm,
274                     rawobj_t *key,
275                     rawobj_t *hdr,
276                     int msgcnt, rawobj_t *msgs,
277                     int iovcnt, lnet_kiov_t *iovs,
278                     rawobj_t *cksum)
279 {
280         struct hash_desc desc = {
281                 .tfm = tfm,
282                 .flags = 0,
283         };
284         struct scatterlist sg[1];
285         struct sg_table sgt;
286         int i;
287         int rc;
288
289         rc = crypto_hash_setkey(tfm, key->data, key->len);
290         if (rc)
291                 return rc;
292
293         rc = crypto_hash_init(&desc);
294         if (rc)
295                 return rc;
296
297         for (i = 0; i < msgcnt; i++) {
298                 if (msgs[i].len == 0)
299                         continue;
300
301                 rc = gss_setup_sgtable(&sgt, sg, msgs[i].data, msgs[i].len);
302                 if (rc != 0)
303                         return rc;
304                 rc = crypto_hash_update(&desc, sg, msgs[i].len);
305                 if (rc)
306                         return rc;
307
308                 gss_teardown_sgtable(&sgt);
309         }
310
311         for (i = 0; i < iovcnt; i++) {
312                 if (iovs[i].kiov_len == 0)
313                         continue;
314
315                 sg_init_table(sg, 1);
316                 sg_set_page(&sg[0], iovs[i].kiov_page, iovs[i].kiov_len,
317                             iovs[i].kiov_offset);
318                 rc = crypto_hash_update(&desc, sg, iovs[i].kiov_len);
319                 if (rc)
320                         return rc;
321         }
322
323         if (hdr) {
324                 rc = gss_setup_sgtable(&sgt, sg, hdr, sizeof(*hdr));
325                 if (rc != 0)
326                         return rc;
327                 rc = crypto_hash_update(&desc, sg, sizeof(hdr->len));
328                 if (rc)
329                         return rc;
330
331                 gss_teardown_sgtable(&sgt);
332         }
333
334         return crypto_hash_final(&desc, cksum->data);
335 }
336
337 int gss_digest_norm(struct crypto_hash *tfm,
338                     struct gss_keyblock *kb,
339                     rawobj_t *hdr,
340                     int msgcnt, rawobj_t *msgs,
341                     int iovcnt, lnet_kiov_t *iovs,
342                     rawobj_t *cksum)
343 {
344         struct hash_desc   desc;
345         struct scatterlist sg[1];
346         struct sg_table sgt;
347         int                i;
348         int                rc;
349
350         LASSERT(kb->kb_tfm);
351         desc.tfm = tfm;
352         desc.flags = 0;
353
354         rc = crypto_hash_init(&desc);
355         if (rc)
356                 return rc;
357
358         for (i = 0; i < msgcnt; i++) {
359                 if (msgs[i].len == 0)
360                         continue;
361
362                 rc = gss_setup_sgtable(&sgt, sg, msgs[i].data, msgs[i].len);
363                 if (rc != 0)
364                         return rc;
365
366                 rc = crypto_hash_update(&desc, sg, msgs[i].len);
367                 if (rc)
368                         return rc;
369
370                 gss_teardown_sgtable(&sgt);
371         }
372
373         for (i = 0; i < iovcnt; i++) {
374                 if (iovs[i].kiov_len == 0)
375                         continue;
376
377                 sg_init_table(sg, 1);
378                 sg_set_page(&sg[0], iovs[i].kiov_page, iovs[i].kiov_len,
379                             iovs[i].kiov_offset);
380                 rc = crypto_hash_update(&desc, sg, iovs[i].kiov_len);
381                 if (rc)
382                         return rc;
383         }
384
385         if (hdr) {
386                 rc = gss_setup_sgtable(&sgt, sg, hdr, sizeof(*hdr));
387                 if (rc != 0)
388                         return rc;
389
390                 rc = crypto_hash_update(&desc, sg, sizeof(*hdr));
391                 if (rc)
392                         return rc;
393
394                 gss_teardown_sgtable(&sgt);
395         }
396
397         rc = crypto_hash_final(&desc, cksum->data);
398         if (rc)
399                 return rc;
400
401         return gss_crypt_generic(kb->kb_tfm, 0, NULL, cksum->data,
402                                  cksum->data, cksum->len);
403 }
404
405 int gss_add_padding(rawobj_t *msg, int msg_buflen, int blocksize)
406 {
407         int padding;
408
409         padding = (blocksize - (msg->len & (blocksize - 1))) &
410                   (blocksize - 1);
411         if (!padding)
412                 return 0;
413
414         if (msg->len + padding > msg_buflen) {
415                 CERROR("bufsize %u too small: datalen %u, padding %u\n",
416                        msg_buflen, msg->len, padding);
417                 return -EINVAL;
418         }
419
420         memset(msg->data + msg->len, padding, padding);
421         msg->len += padding;
422         return 0;
423 }
424
425 int gss_crypt_rawobjs(struct crypto_blkcipher *tfm, __u8 *iv,
426                       int inobj_cnt, rawobj_t *inobjs, rawobj_t *outobj,
427                       int enc)
428 {
429         struct blkcipher_desc desc;
430         struct scatterlist src;
431         struct scatterlist dst;
432         struct sg_table sg_dst;
433         struct sg_table sg_src;
434         __u8 *buf;
435         __u32 datalen = 0;
436         int i, rc;
437         ENTRY;
438
439         buf = outobj->data;
440         desc.tfm  = tfm;
441         desc.info = iv;
442         desc.flags = 0;
443
444         for (i = 0; i < inobj_cnt; i++) {
445                 LASSERT(buf + inobjs[i].len <= outobj->data + outobj->len);
446
447                 rc = gss_setup_sgtable(&sg_src, &src, inobjs[i].data,
448                                    inobjs[i].len);
449                 if (rc != 0)
450                         RETURN(rc);
451
452                 rc = gss_setup_sgtable(&sg_dst, &dst, buf,
453                                        outobj->len - datalen);
454                 if (rc != 0) {
455                         gss_teardown_sgtable(&sg_src);
456                         RETURN(rc);
457                 }
458
459                 if (iv) {
460                         if (enc)
461                                 rc = crypto_blkcipher_encrypt_iv(&desc, &dst,
462                                                                  &src,
463                                                                  src.length);
464                         else
465                                 rc = crypto_blkcipher_decrypt_iv(&desc, &dst,
466                                                                  &src,
467                                                                  src.length);
468                 } else {
469                         if (enc)
470                                 rc = crypto_blkcipher_encrypt(&desc, &dst, &src,
471                                                               src.length);
472                         else
473                                 rc = crypto_blkcipher_decrypt(&desc, &dst, &src,
474                                                               src.length);
475                 }
476
477                 gss_teardown_sgtable(&sg_src);
478                 gss_teardown_sgtable(&sg_dst);
479
480                 if (rc) {
481                         CERROR("encrypt error %d\n", rc);
482                         RETURN(rc);
483                 }
484
485                 datalen += inobjs[i].len;
486                 buf += inobjs[i].len;
487         }
488
489         outobj->len = datalen;
490         RETURN(0);
491 }