xref: /openbmc/linux/crypto/api.c (revision d5cb9783536a41df9f9cba5b0a1d78047ed787f7)
1 /*
2  * Scatterlist Cryptographic API.
3  *
4  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
5  * Copyright (c) 2002 David S. Miller (davem@redhat.com)
6  *
7  * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no>
8  * and Nettle, by Niels M�ller.
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 2 of the License, or (at your option)
13  * any later version.
14  *
15  */
16 
17 #include <linux/compiler.h>
18 #include <linux/init.h>
19 #include <linux/crypto.h>
20 #include <linux/errno.h>
21 #include <linux/kmod.h>
22 #include <linux/rwsem.h>
23 #include <linux/slab.h>
24 #include "internal.h"
25 
26 LIST_HEAD(crypto_alg_list);
27 DECLARE_RWSEM(crypto_alg_sem);
28 
29 static inline int crypto_alg_get(struct crypto_alg *alg)
30 {
31 	return try_module_get(alg->cra_module);
32 }
33 
34 static inline void crypto_alg_put(struct crypto_alg *alg)
35 {
36 	module_put(alg->cra_module);
37 }
38 
39 static struct crypto_alg *crypto_alg_lookup(const char *name)
40 {
41 	struct crypto_alg *q, *alg = NULL;
42 
43 	if (!name)
44 		return NULL;
45 
46 	down_read(&crypto_alg_sem);
47 
48 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
49 		if (!(strcmp(q->cra_name, name))) {
50 			if (crypto_alg_get(q))
51 				alg = q;
52 			break;
53 		}
54 	}
55 
56 	up_read(&crypto_alg_sem);
57 	return alg;
58 }
59 
60 /* A far more intelligent version of this is planned.  For now, just
61  * try an exact match on the name of the algorithm. */
62 static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name)
63 {
64 	return try_then_request_module(crypto_alg_lookup(name), name);
65 }
66 
67 static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags)
68 {
69 	tfm->crt_flags = flags & CRYPTO_TFM_REQ_MASK;
70 	flags &= ~CRYPTO_TFM_REQ_MASK;
71 
72 	switch (crypto_tfm_alg_type(tfm)) {
73 	case CRYPTO_ALG_TYPE_CIPHER:
74 		return crypto_init_cipher_flags(tfm, flags);
75 
76 	case CRYPTO_ALG_TYPE_DIGEST:
77 		return crypto_init_digest_flags(tfm, flags);
78 
79 	case CRYPTO_ALG_TYPE_COMPRESS:
80 		return crypto_init_compress_flags(tfm, flags);
81 
82 	default:
83 		break;
84 	}
85 
86 	BUG();
87 	return -EINVAL;
88 }
89 
90 static int crypto_init_ops(struct crypto_tfm *tfm)
91 {
92 	switch (crypto_tfm_alg_type(tfm)) {
93 	case CRYPTO_ALG_TYPE_CIPHER:
94 		return crypto_init_cipher_ops(tfm);
95 
96 	case CRYPTO_ALG_TYPE_DIGEST:
97 		return crypto_init_digest_ops(tfm);
98 
99 	case CRYPTO_ALG_TYPE_COMPRESS:
100 		return crypto_init_compress_ops(tfm);
101 
102 	default:
103 		break;
104 	}
105 
106 	BUG();
107 	return -EINVAL;
108 }
109 
110 static void crypto_exit_ops(struct crypto_tfm *tfm)
111 {
112 	switch (crypto_tfm_alg_type(tfm)) {
113 	case CRYPTO_ALG_TYPE_CIPHER:
114 		crypto_exit_cipher_ops(tfm);
115 		break;
116 
117 	case CRYPTO_ALG_TYPE_DIGEST:
118 		crypto_exit_digest_ops(tfm);
119 		break;
120 
121 	case CRYPTO_ALG_TYPE_COMPRESS:
122 		crypto_exit_compress_ops(tfm);
123 		break;
124 
125 	default:
126 		BUG();
127 
128 	}
129 }
130 
131 static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags)
132 {
133 	unsigned int len;
134 
135 	switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
136 	default:
137 		BUG();
138 
139 	case CRYPTO_ALG_TYPE_CIPHER:
140 		len = crypto_cipher_ctxsize(alg, flags);
141 		break;
142 
143 	case CRYPTO_ALG_TYPE_DIGEST:
144 		len = crypto_digest_ctxsize(alg, flags);
145 		break;
146 
147 	case CRYPTO_ALG_TYPE_COMPRESS:
148 		len = crypto_compress_ctxsize(alg, flags);
149 		break;
150 	}
151 
152 	return len + alg->cra_alignmask;
153 }
154 
155 struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
156 {
157 	struct crypto_tfm *tfm = NULL;
158 	struct crypto_alg *alg;
159 	unsigned int tfm_size;
160 
161 	alg = crypto_alg_mod_lookup(name);
162 	if (alg == NULL)
163 		goto out;
164 
165 	tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags);
166 	tfm = kmalloc(tfm_size, GFP_KERNEL);
167 	if (tfm == NULL)
168 		goto out_put;
169 
170 	memset(tfm, 0, tfm_size);
171 
172 	tfm->__crt_alg = alg;
173 
174 	if (crypto_init_flags(tfm, flags))
175 		goto out_free_tfm;
176 
177 	if (crypto_init_ops(tfm)) {
178 		crypto_exit_ops(tfm);
179 		goto out_free_tfm;
180 	}
181 
182 	goto out;
183 
184 out_free_tfm:
185 	kfree(tfm);
186 	tfm = NULL;
187 out_put:
188 	crypto_alg_put(alg);
189 out:
190 	return tfm;
191 }
192 
193 void crypto_free_tfm(struct crypto_tfm *tfm)
194 {
195 	struct crypto_alg *alg;
196 	int size;
197 
198 	if (unlikely(!tfm))
199 		return;
200 
201 	alg = tfm->__crt_alg;
202 	size = sizeof(*tfm) + alg->cra_ctxsize;
203 
204 	crypto_exit_ops(tfm);
205 	crypto_alg_put(alg);
206 	memset(tfm, 0, size);
207 	kfree(tfm);
208 }
209 
210 int crypto_register_alg(struct crypto_alg *alg)
211 {
212 	int ret = 0;
213 	struct crypto_alg *q;
214 
215 	if (alg->cra_alignmask & (alg->cra_alignmask + 1))
216 		return -EINVAL;
217 
218 	if (alg->cra_alignmask & alg->cra_blocksize)
219 		return -EINVAL;
220 
221 	if (alg->cra_blocksize > PAGE_SIZE)
222 		return -EINVAL;
223 
224 	down_write(&crypto_alg_sem);
225 
226 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
227 		if (!(strcmp(q->cra_name, alg->cra_name))) {
228 			ret = -EEXIST;
229 			goto out;
230 		}
231 	}
232 
233 	list_add_tail(&alg->cra_list, &crypto_alg_list);
234 out:
235 	up_write(&crypto_alg_sem);
236 	return ret;
237 }
238 
239 int crypto_unregister_alg(struct crypto_alg *alg)
240 {
241 	int ret = -ENOENT;
242 	struct crypto_alg *q;
243 
244 	BUG_ON(!alg->cra_module);
245 
246 	down_write(&crypto_alg_sem);
247 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
248 		if (alg == q) {
249 			list_del(&alg->cra_list);
250 			ret = 0;
251 			goto out;
252 		}
253 	}
254 out:
255 	up_write(&crypto_alg_sem);
256 	return ret;
257 }
258 
259 int crypto_alg_available(const char *name, u32 flags)
260 {
261 	int ret = 0;
262 	struct crypto_alg *alg = crypto_alg_mod_lookup(name);
263 
264 	if (alg) {
265 		crypto_alg_put(alg);
266 		ret = 1;
267 	}
268 
269 	return ret;
270 }
271 
272 static int __init init_crypto(void)
273 {
274 	printk(KERN_INFO "Initializing Cryptographic API\n");
275 	crypto_init_proc();
276 	return 0;
277 }
278 
279 __initcall(init_crypto);
280 
281 EXPORT_SYMBOL_GPL(crypto_register_alg);
282 EXPORT_SYMBOL_GPL(crypto_unregister_alg);
283 EXPORT_SYMBOL_GPL(crypto_alloc_tfm);
284 EXPORT_SYMBOL_GPL(crypto_free_tfm);
285 EXPORT_SYMBOL_GPL(crypto_alg_available);
286