]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - crypto/algapi.c
[CRYPTO] cipher: Removed special IV checks for ECB
[mirror_ubuntu-zesty-kernel.git] / crypto / algapi.c
CommitLineData
cce9e06d
HX
1/*
2 * Cryptographic API for algorithms (i.e., low-level API).
3 *
4 * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 */
12
6bfd4809 13#include <linux/err.h>
cce9e06d
HX
14#include <linux/errno.h>
15#include <linux/init.h>
16#include <linux/kernel.h>
4cc7720c 17#include <linux/list.h>
cce9e06d
HX
18#include <linux/module.h>
19#include <linux/string.h>
20
21#include "internal.h"
22
4cc7720c
HX
23static LIST_HEAD(crypto_template_list);
24
492e2b63 25void crypto_larval_error(const char *name, u32 type, u32 mask)
2825982d
HX
26{
27 struct crypto_alg *alg;
28
29 down_read(&crypto_alg_sem);
492e2b63 30 alg = __crypto_alg_lookup(name, type, mask);
2825982d
HX
31 up_read(&crypto_alg_sem);
32
33 if (alg) {
34 if (crypto_is_larval(alg)) {
35 struct crypto_larval *larval = (void *)alg;
36 complete(&larval->completion);
37 }
38 crypto_mod_put(alg);
39 }
40}
41EXPORT_SYMBOL_GPL(crypto_larval_error);
42
cce9e06d
HX
43static inline int crypto_set_driver_name(struct crypto_alg *alg)
44{
45 static const char suffix[] = "-generic";
46 char *driver_name = alg->cra_driver_name;
47 int len;
48
49 if (*driver_name)
50 return 0;
51
52 len = strlcpy(driver_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
53 if (len + sizeof(suffix) > CRYPTO_MAX_ALG_NAME)
54 return -ENAMETOOLONG;
55
56 memcpy(driver_name + len, suffix, sizeof(suffix));
57 return 0;
58}
59
4cc7720c 60static int crypto_check_alg(struct crypto_alg *alg)
cce9e06d 61{
cce9e06d
HX
62 if (alg->cra_alignmask & (alg->cra_alignmask + 1))
63 return -EINVAL;
64
65 if (alg->cra_alignmask & alg->cra_blocksize)
66 return -EINVAL;
67
68 if (alg->cra_blocksize > PAGE_SIZE / 8)
69 return -EINVAL;
70
71 if (alg->cra_priority < 0)
72 return -EINVAL;
cce9e06d 73
4cc7720c
HX
74 return crypto_set_driver_name(alg);
75}
76
6bfd4809
HX
77static void crypto_destroy_instance(struct crypto_alg *alg)
78{
79 struct crypto_instance *inst = (void *)alg;
80 struct crypto_template *tmpl = inst->tmpl;
81
82 tmpl->free(inst);
83 crypto_tmpl_put(tmpl);
84}
85
86static void crypto_remove_spawns(struct list_head *spawns,
87 struct list_head *list)
88{
89 struct crypto_spawn *spawn, *n;
90
91 list_for_each_entry_safe(spawn, n, spawns, list) {
92 struct crypto_instance *inst = spawn->inst;
93 struct crypto_template *tmpl = inst->tmpl;
94
95 list_del_init(&spawn->list);
96 spawn->alg = NULL;
97
98 if (crypto_is_dead(&inst->alg))
99 continue;
100
101 inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
102 if (!tmpl || !crypto_tmpl_get(tmpl))
103 continue;
104
105 crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
106 list_move(&inst->alg.cra_list, list);
107 hlist_del(&inst->list);
108 inst->alg.cra_destroy = crypto_destroy_instance;
109
110 if (!list_empty(&inst->alg.cra_users)) {
111 if (&n->list == spawns)
112 n = list_entry(inst->alg.cra_users.next,
113 typeof(*n), list);
114 __list_splice(&inst->alg.cra_users, spawns->prev);
115 }
116 }
117}
118
119static int __crypto_register_alg(struct crypto_alg *alg,
120 struct list_head *list)
4cc7720c
HX
121{
122 struct crypto_alg *q;
6bfd4809
HX
123 int ret = -EAGAIN;
124
125 if (crypto_is_dead(alg))
126 goto out;
127
128 INIT_LIST_HEAD(&alg->cra_users);
129
130 ret = -EEXIST;
4cc7720c 131
2825982d 132 atomic_set(&alg->cra_refcnt, 1);
cce9e06d 133 list_for_each_entry(q, &crypto_alg_list, cra_list) {
4cc7720c 134 if (q == alg)
cce9e06d 135 goto out;
6bfd4809
HX
136
137 if (crypto_is_moribund(q))
138 continue;
139
140 if (crypto_is_larval(q)) {
2825982d
HX
141 struct crypto_larval *larval = (void *)q;
142
6bfd4809
HX
143 if (strcmp(alg->cra_name, q->cra_name) &&
144 strcmp(alg->cra_driver_name, q->cra_name))
145 continue;
146
147 if (larval->adult)
148 continue;
492e2b63
HX
149 if ((q->cra_flags ^ alg->cra_flags) & larval->mask)
150 continue;
2825982d
HX
151 if (!crypto_mod_get(alg))
152 continue;
6bfd4809 153
2825982d
HX
154 larval->adult = alg;
155 complete(&larval->completion);
6bfd4809 156 continue;
2825982d 157 }
6bfd4809
HX
158
159 if (strcmp(alg->cra_name, q->cra_name))
160 continue;
161
162 if (strcmp(alg->cra_driver_name, q->cra_driver_name) &&
163 q->cra_priority > alg->cra_priority)
164 continue;
165
166 crypto_remove_spawns(&q->cra_users, list);
cce9e06d
HX
167 }
168
169 list_add(&alg->cra_list, &crypto_alg_list);
2825982d
HX
170
171 crypto_notify(CRYPTO_MSG_ALG_REGISTER, alg);
4cc7720c 172 ret = 0;
2825982d 173
cce9e06d 174out:
cce9e06d
HX
175 return ret;
176}
4cc7720c 177
6bfd4809
HX
178static void crypto_remove_final(struct list_head *list)
179{
180 struct crypto_alg *alg;
181 struct crypto_alg *n;
182
183 list_for_each_entry_safe(alg, n, list, cra_list) {
184 list_del_init(&alg->cra_list);
185 crypto_alg_put(alg);
186 }
187}
188
4cc7720c
HX
189int crypto_register_alg(struct crypto_alg *alg)
190{
6bfd4809 191 LIST_HEAD(list);
4cc7720c
HX
192 int err;
193
194 err = crypto_check_alg(alg);
195 if (err)
196 return err;
197
198 down_write(&crypto_alg_sem);
6bfd4809 199 err = __crypto_register_alg(alg, &list);
4cc7720c
HX
200 up_write(&crypto_alg_sem);
201
6bfd4809 202 crypto_remove_final(&list);
4cc7720c
HX
203 return err;
204}
cce9e06d
HX
205EXPORT_SYMBOL_GPL(crypto_register_alg);
206
6bfd4809
HX
207static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
208{
209 if (unlikely(list_empty(&alg->cra_list)))
210 return -ENOENT;
211
212 alg->cra_flags |= CRYPTO_ALG_DEAD;
213
214 crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
215 list_del_init(&alg->cra_list);
216 crypto_remove_spawns(&alg->cra_users, list);
217
218 return 0;
219}
220
cce9e06d
HX
221int crypto_unregister_alg(struct crypto_alg *alg)
222{
6bfd4809
HX
223 int ret;
224 LIST_HEAD(list);
cce9e06d
HX
225
226 down_write(&crypto_alg_sem);
6bfd4809 227 ret = crypto_remove_alg(alg, &list);
cce9e06d
HX
228 up_write(&crypto_alg_sem);
229
230 if (ret)
231 return ret;
232
233 BUG_ON(atomic_read(&alg->cra_refcnt) != 1);
234 if (alg->cra_destroy)
235 alg->cra_destroy(alg);
236
6bfd4809 237 crypto_remove_final(&list);
cce9e06d
HX
238 return 0;
239}
240EXPORT_SYMBOL_GPL(crypto_unregister_alg);
241
4cc7720c
HX
242int crypto_register_template(struct crypto_template *tmpl)
243{
244 struct crypto_template *q;
245 int err = -EEXIST;
246
247 down_write(&crypto_alg_sem);
248
249 list_for_each_entry(q, &crypto_template_list, list) {
250 if (q == tmpl)
251 goto out;
252 }
253
254 list_add(&tmpl->list, &crypto_template_list);
2825982d 255 crypto_notify(CRYPTO_MSG_TMPL_REGISTER, tmpl);
4cc7720c
HX
256 err = 0;
257out:
258 up_write(&crypto_alg_sem);
259 return err;
260}
261EXPORT_SYMBOL_GPL(crypto_register_template);
262
263void crypto_unregister_template(struct crypto_template *tmpl)
264{
265 struct crypto_instance *inst;
266 struct hlist_node *p, *n;
267 struct hlist_head *list;
6bfd4809 268 LIST_HEAD(users);
4cc7720c
HX
269
270 down_write(&crypto_alg_sem);
271
272 BUG_ON(list_empty(&tmpl->list));
273 list_del_init(&tmpl->list);
274
275 list = &tmpl->instances;
276 hlist_for_each_entry(inst, p, list, list) {
6bfd4809
HX
277 int err = crypto_remove_alg(&inst->alg, &users);
278 BUG_ON(err);
4cc7720c
HX
279 }
280
2825982d
HX
281 crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl);
282
4cc7720c
HX
283 up_write(&crypto_alg_sem);
284
285 hlist_for_each_entry_safe(inst, p, n, list, list) {
286 BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1);
287 tmpl->free(inst);
288 }
6bfd4809 289 crypto_remove_final(&users);
4cc7720c
HX
290}
291EXPORT_SYMBOL_GPL(crypto_unregister_template);
292
293static struct crypto_template *__crypto_lookup_template(const char *name)
294{
295 struct crypto_template *q, *tmpl = NULL;
296
297 down_read(&crypto_alg_sem);
298 list_for_each_entry(q, &crypto_template_list, list) {
299 if (strcmp(q->name, name))
300 continue;
301 if (unlikely(!crypto_tmpl_get(q)))
302 continue;
303
304 tmpl = q;
305 break;
306 }
307 up_read(&crypto_alg_sem);
308
309 return tmpl;
310}
311
312struct crypto_template *crypto_lookup_template(const char *name)
313{
314 return try_then_request_module(__crypto_lookup_template(name), name);
315}
316EXPORT_SYMBOL_GPL(crypto_lookup_template);
317
318int crypto_register_instance(struct crypto_template *tmpl,
319 struct crypto_instance *inst)
320{
6bfd4809 321 LIST_HEAD(list);
4cc7720c
HX
322 int err = -EINVAL;
323
324 if (inst->alg.cra_destroy)
325 goto err;
326
327 err = crypto_check_alg(&inst->alg);
328 if (err)
329 goto err;
330
331 inst->alg.cra_module = tmpl->module;
332
333 down_write(&crypto_alg_sem);
334
6bfd4809 335 err = __crypto_register_alg(&inst->alg, &list);
4cc7720c
HX
336 if (err)
337 goto unlock;
338
339 hlist_add_head(&inst->list, &tmpl->instances);
340 inst->tmpl = tmpl;
341
342unlock:
343 up_write(&crypto_alg_sem);
344
6bfd4809
HX
345 crypto_remove_final(&list);
346
4cc7720c
HX
347err:
348 return err;
349}
350EXPORT_SYMBOL_GPL(crypto_register_instance);
351
6bfd4809
HX
352int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
353 struct crypto_instance *inst)
354{
355 int err = -EAGAIN;
356
357 spawn->inst = inst;
358
359 down_write(&crypto_alg_sem);
360 if (!crypto_is_moribund(alg)) {
361 list_add(&spawn->list, &alg->cra_users);
362 spawn->alg = alg;
363 err = 0;
364 }
365 up_write(&crypto_alg_sem);
366
367 return err;
368}
369EXPORT_SYMBOL_GPL(crypto_init_spawn);
370
371void crypto_drop_spawn(struct crypto_spawn *spawn)
372{
373 down_write(&crypto_alg_sem);
374 list_del(&spawn->list);
375 up_write(&crypto_alg_sem);
376}
377EXPORT_SYMBOL_GPL(crypto_drop_spawn);
378
379struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn)
380{
381 struct crypto_alg *alg;
382 struct crypto_alg *alg2;
383 struct crypto_tfm *tfm;
384
385 down_read(&crypto_alg_sem);
386 alg = spawn->alg;
387 alg2 = alg;
388 if (alg2)
389 alg2 = crypto_mod_get(alg2);
390 up_read(&crypto_alg_sem);
391
392 if (!alg2) {
393 if (alg)
394 crypto_shoot_alg(alg);
395 return ERR_PTR(-EAGAIN);
396 }
397
398 tfm = __crypto_alloc_tfm(alg, 0);
399 if (IS_ERR(tfm))
400 crypto_mod_put(alg);
401
402 return tfm;
403}
404EXPORT_SYMBOL_GPL(crypto_spawn_tfm);
405
2825982d
HX
406int crypto_register_notifier(struct notifier_block *nb)
407{
408 return blocking_notifier_chain_register(&crypto_chain, nb);
409}
410EXPORT_SYMBOL_GPL(crypto_register_notifier);
411
412int crypto_unregister_notifier(struct notifier_block *nb)
413{
414 return blocking_notifier_chain_unregister(&crypto_chain, nb);
415}
416EXPORT_SYMBOL_GPL(crypto_unregister_notifier);
417
cce9e06d
HX
418static int __init crypto_algapi_init(void)
419{
420 crypto_init_proc();
421 return 0;
422}
423
424static void __exit crypto_algapi_exit(void)
425{
426 crypto_exit_proc();
427}
428
429module_init(crypto_algapi_init);
430module_exit(crypto_algapi_exit);
431
432MODULE_LICENSE("GPL");
433MODULE_DESCRIPTION("Cryptographic algorithms API");