xref: /openbmc/linux/net/sunrpc/auth_gss/gss_krb5_crypto.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
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 			kmap(sg->page); /* XXX kmap_atomic? */
189 			crypto_digest_update(tfm, sg, 1);
190 			kunmap(sg->page);
191 			len -= thislen;
192 			i++;
193 			offset = 0;
194 			thislen = PAGE_CACHE_SIZE;
195 		} while(len != 0);
196 	}
197 	if (body->tail[0].iov_len) {
198 		buf_to_sg(sg, body->tail[0].iov_base, body->tail[0].iov_len);
199 		crypto_digest_update(tfm, sg, 1);
200 	}
201 	crypto_digest_final(tfm, cksum->data);
202 	code = 0;
203 out:
204 	if (tfm)
205 		crypto_free_tfm(tfm);
206 	return code;
207 }
208 
209 EXPORT_SYMBOL(make_checksum);
210