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