Merge head 'upstream-fixes' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[linux-2.6] / net / sunrpc / auth_gss / gss_krb5_crypto.c
1 /*
2  *  linux/net/sunrpc/gss_krb5_crypto.c
3  *
4  *  Copyright (c) 2000 The Regents of the University of Michigan.
5  *  All rights reserved.
6  *
7  *  Andy Adamson   <andros@umich.edu>
8  *  Bruce Fields   <bfields@umich.edu>
9  */
10
11 /*
12  * Copyright (C) 1998 by the FundsXpress, INC.
13  *
14  * All rights reserved.
15  *
16  * Export of this software from the United States of America may require
17  * a specific license from the United States Government.  It is the
18  * responsibility of any person or organization contemplating export to
19  * obtain such a license before exporting.
20  *
21  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
22  * distribute this software and its documentation for any purpose and
23  * without fee is hereby granted, provided that the above copyright
24  * notice appear in all copies and that both that copyright notice and
25  * this permission notice appear in supporting documentation, and that
26  * the name of FundsXpress. not be used in advertising or publicity pertaining
27  * to distribution of the software without specific, written prior
28  * permission.  FundsXpress makes no representations about the suitability of
29  * this software for any purpose.  It is provided "as is" without express
30  * or implied warranty.
31  *
32  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
33  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
34  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
35  */
36
37 #include <linux/types.h>
38 #include <linux/mm.h>
39 #include <linux/slab.h>
40 #include <asm/scatterlist.h>
41 #include <linux/crypto.h>
42 #include <linux/highmem.h>
43 #include <linux/pagemap.h>
44 #include <linux/sunrpc/gss_krb5.h>
45
46 #ifdef RPC_DEBUG
47 # define RPCDBG_FACILITY        RPCDBG_AUTH
48 #endif
49
50 u32
51 krb5_encrypt(
52         struct crypto_tfm *tfm,
53         void * iv,
54         void * in,
55         void * out,
56         int length)
57 {
58         u32 ret = -EINVAL;
59         struct scatterlist sg[1];
60         u8 local_iv[16] = {0};
61
62         dprintk("RPC:      krb5_encrypt: input data:\n");
63         print_hexl((u32 *)in, length, 0);
64
65         if (length % crypto_tfm_alg_blocksize(tfm) != 0)
66                 goto out;
67
68         if (crypto_tfm_alg_ivsize(tfm) > 16) {
69                 dprintk("RPC:      gss_k5encrypt: tfm iv size to large %d\n",
70                          crypto_tfm_alg_ivsize(tfm));
71                 goto out;
72         }
73
74         if (iv)
75                 memcpy(local_iv, iv, crypto_tfm_alg_ivsize(tfm));
76
77         memcpy(out, in, length);
78         sg[0].page = virt_to_page(out);
79         sg[0].offset = offset_in_page(out);
80         sg[0].length = length;
81
82         ret = crypto_cipher_encrypt_iv(tfm, sg, sg, length, local_iv);
83
84         dprintk("RPC:      krb5_encrypt: output data:\n");
85         print_hexl((u32 *)out, length, 0);
86 out:
87         dprintk("RPC:      krb5_encrypt returns %d\n",ret);
88         return(ret);
89 }
90
91 EXPORT_SYMBOL(krb5_encrypt);
92
93 u32
94 krb5_decrypt(
95      struct crypto_tfm *tfm,
96      void * iv,
97      void * in,
98      void * out,
99      int length)
100 {
101         u32 ret = -EINVAL;
102         struct scatterlist sg[1];
103         u8 local_iv[16] = {0};
104
105         dprintk("RPC:      krb5_decrypt: input data:\n");
106         print_hexl((u32 *)in, length, 0);
107
108         if (length % crypto_tfm_alg_blocksize(tfm) != 0)
109                 goto out;
110
111         if (crypto_tfm_alg_ivsize(tfm) > 16) {
112                 dprintk("RPC:      gss_k5decrypt: tfm iv size to large %d\n",
113                         crypto_tfm_alg_ivsize(tfm));
114                 goto out;
115         }
116         if (iv)
117                 memcpy(local_iv,iv, crypto_tfm_alg_ivsize(tfm));
118
119         memcpy(out, in, length);
120         sg[0].page = virt_to_page(out);
121         sg[0].offset = offset_in_page(out);
122         sg[0].length = length;
123
124         ret = crypto_cipher_decrypt_iv(tfm, sg, sg, length, local_iv);
125
126         dprintk("RPC:      krb5_decrypt: output_data:\n");
127         print_hexl((u32 *)out, length, 0);
128 out:
129         dprintk("RPC:      gss_k5decrypt returns %d\n",ret);
130         return(ret);
131 }
132
133 EXPORT_SYMBOL(krb5_decrypt);
134
135 static void
136 buf_to_sg(struct scatterlist *sg, char *ptr, int len) {
137         sg->page = virt_to_page(ptr);
138         sg->offset = offset_in_page(ptr);
139         sg->length = len;
140 }
141
142 /* checksum the plaintext data and hdrlen bytes of the token header */
143 s32
144 make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
145                    struct xdr_netobj *cksum)
146 {
147         char                            *cksumname;
148         struct crypto_tfm               *tfm = NULL; /* XXX add to ctx? */
149         struct scatterlist              sg[1];
150         u32                             code = GSS_S_FAILURE;
151         int                             len, thislen, offset;
152         int                             i;
153
154         switch (cksumtype) {
155                 case CKSUMTYPE_RSA_MD5:
156                         cksumname = "md5";
157                         break;
158                 default:
159                         dprintk("RPC:      krb5_make_checksum:"
160                                 " unsupported checksum %d", cksumtype);
161                         goto out;
162         }
163         if (!(tfm = crypto_alloc_tfm(cksumname, 0)))
164                 goto out;
165         cksum->len = crypto_tfm_alg_digestsize(tfm);
166         if ((cksum->data = kmalloc(cksum->len, GFP_KERNEL)) == NULL)
167                 goto out;
168
169         crypto_digest_init(tfm);
170         buf_to_sg(sg, header, hdrlen);
171         crypto_digest_update(tfm, sg, 1);
172         if (body->head[0].iov_len) {
173                 buf_to_sg(sg, body->head[0].iov_base, body->head[0].iov_len);
174                 crypto_digest_update(tfm, sg, 1);
175         }
176
177         len = body->page_len;
178         if (len != 0) {
179                 offset = body->page_base & (PAGE_CACHE_SIZE - 1);
180                 i = body->page_base >> PAGE_CACHE_SHIFT;
181                 thislen = PAGE_CACHE_SIZE - offset;
182                 do {
183                         if (thislen > len)
184                                 thislen = len;
185                         sg->page = body->pages[i];
186                         sg->offset = offset;
187                         sg->length = thislen;
188                         crypto_digest_update(tfm, sg, 1);
189                         len -= thislen;
190                         i++;
191                         offset = 0;
192                         thislen = PAGE_CACHE_SIZE;
193                 } while(len != 0);
194         }
195         if (body->tail[0].iov_len) {
196                 buf_to_sg(sg, body->tail[0].iov_base, body->tail[0].iov_len);
197                 crypto_digest_update(tfm, sg, 1);
198         }
199         crypto_digest_final(tfm, cksum->data);
200         code = 0;
201 out:
202         if (tfm)
203                 crypto_free_tfm(tfm);
204         return code;
205 }
206
207 EXPORT_SYMBOL(make_checksum);