algapi.c 19.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
/*
 * Cryptographic API for algorithms (i.e., low-level API).
 *
 * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 */

Herbert Xu's avatar
Herbert Xu committed
13
#include <linux/err.h>
14
15
16
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel.h>
17
#include <linux/list.h>
18
#include <linux/module.h>
19
#include <linux/rtnetlink.h>
20
#include <linux/slab.h>
21
22
23
24
#include <linux/string.h>

#include "internal.h"

25
26
static LIST_HEAD(crypto_template_list);

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
static inline int crypto_set_driver_name(struct crypto_alg *alg)
{
	static const char suffix[] = "-generic";
	char *driver_name = alg->cra_driver_name;
	int len;

	if (*driver_name)
		return 0;

	len = strlcpy(driver_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
	if (len + sizeof(suffix) > CRYPTO_MAX_ALG_NAME)
		return -ENAMETOOLONG;

	memcpy(driver_name + len, suffix, sizeof(suffix));
	return 0;
}

44
45
46
47
48
49
50
51
52
53
static inline void crypto_check_module_sig(struct module *mod)
{
#ifdef CONFIG_CRYPTO_FIPS
	if (fips_enabled && mod && !mod->sig_ok)
		panic("Module %s signature verification failed in FIPS mode\n",
		      mod->name);
#endif
	return;
}

54
static int crypto_check_alg(struct crypto_alg *alg)
55
{
56
57
	crypto_check_module_sig(alg->cra_module);

58
59
60
61
62
63
64
65
66
	if (alg->cra_alignmask & (alg->cra_alignmask + 1))
		return -EINVAL;

	if (alg->cra_blocksize > PAGE_SIZE / 8)
		return -EINVAL;

	if (alg->cra_priority < 0)
		return -EINVAL;

67
68
	atomic_set(&alg->cra_refcnt, 1);

69
70
71
	return crypto_set_driver_name(alg);
}

Herbert Xu's avatar
Herbert Xu committed
72
73
74
75
76
77
78
79
80
static void crypto_destroy_instance(struct crypto_alg *alg)
{
	struct crypto_instance *inst = (void *)alg;
	struct crypto_template *tmpl = inst->tmpl;

	tmpl->free(inst);
	crypto_tmpl_put(tmpl);
}

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
static struct list_head *crypto_more_spawns(struct crypto_alg *alg,
					    struct list_head *stack,
					    struct list_head *top,
					    struct list_head *secondary_spawns)
{
	struct crypto_spawn *spawn, *n;

	if (list_empty(stack))
		return NULL;

	spawn = list_first_entry(stack, struct crypto_spawn, list);
	n = list_entry(spawn->list.next, struct crypto_spawn, list);

	if (spawn->alg && &n->list != stack && !n->alg)
		n->alg = (n->list.next == stack) ? alg :
			 &list_entry(n->list.next, struct crypto_spawn,
				     list)->inst->alg;

	list_move(&spawn->list, secondary_spawns);

	return &n->list == stack ? top : &n->inst->alg.cra_users;
}

104
105
static void crypto_remove_instance(struct crypto_instance *inst,
				   struct list_head *list)
Herbert Xu's avatar
Herbert Xu committed
106
{
107
	struct crypto_template *tmpl = inst->tmpl;
Herbert Xu's avatar
Herbert Xu committed
108

109
110
	if (crypto_is_dead(&inst->alg))
		return;
Herbert Xu's avatar
Herbert Xu committed
111

112
	inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
113
114
115
	if (hlist_unhashed(&inst->list))
		return;

116
117
118
119
120
121
122
123
	if (!tmpl || !crypto_tmpl_get(tmpl))
		return;

	crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
	list_move(&inst->alg.cra_list, list);
	hlist_del(&inst->list);
	inst->alg.cra_destroy = crypto_destroy_instance;

124
	BUG_ON(!list_empty(&inst->alg.cra_users));
125
126
}

127
128
void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
			  struct crypto_alg *nalg)
129
{
130
	u32 new_type = (nalg ?: alg)->cra_flags;
131
132
	struct crypto_spawn *spawn, *n;
	LIST_HEAD(secondary_spawns);
133
134
135
	struct list_head *spawns;
	LIST_HEAD(stack);
	LIST_HEAD(top);
Herbert Xu's avatar
Herbert Xu committed
136

137
	spawns = &alg->cra_users;
138
139
	list_for_each_entry_safe(spawn, n, spawns, list) {
		if ((spawn->alg->cra_flags ^ new_type) & spawn->mask)
Herbert Xu's avatar
Herbert Xu committed
140
141
			continue;

142
		list_move(&spawn->list, &top);
143
	}
Herbert Xu's avatar
Herbert Xu committed
144

145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
	spawns = &top;
	do {
		while (!list_empty(spawns)) {
			struct crypto_instance *inst;

			spawn = list_first_entry(spawns, struct crypto_spawn,
						 list);
			inst = spawn->inst;

			BUG_ON(&inst->alg == alg);

			list_move(&spawn->list, &stack);

			if (&inst->alg == nalg)
				break;

			spawn->alg = NULL;
			spawns = &inst->alg.cra_users;
		}
	} while ((spawns = crypto_more_spawns(alg, &stack, &top,
					      &secondary_spawns)));

	list_for_each_entry_safe(spawn, n, &secondary_spawns, list) {
		if (spawn->alg)
			list_move(&spawn->list, &spawn->alg->cra_users);
		else
171
			crypto_remove_instance(spawn->inst, list);
Herbert Xu's avatar
Herbert Xu committed
172
173
	}
}
174
EXPORT_SYMBOL_GPL(crypto_remove_spawns);
Herbert Xu's avatar
Herbert Xu committed
175

176
static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg)
177
178
{
	struct crypto_alg *q;
179
	struct crypto_larval *larval;
Herbert Xu's avatar
Herbert Xu committed
180
181
182
	int ret = -EAGAIN;

	if (crypto_is_dead(alg))
183
		goto err;
Herbert Xu's avatar
Herbert Xu committed
184
185
186

	INIT_LIST_HEAD(&alg->cra_users);

187
188
189
	/* No cheating! */
	alg->cra_flags &= ~CRYPTO_ALG_TESTED;

Herbert Xu's avatar
Herbert Xu committed
190
	ret = -EEXIST;
191

192
	list_for_each_entry(q, &crypto_alg_list, cra_list) {
193
		if (q == alg)
194
195
			goto err;

196
197
198
		if (crypto_is_moribund(q))
			continue;

199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
		if (crypto_is_larval(q)) {
			if (!strcmp(alg->cra_driver_name, q->cra_driver_name))
				goto err;
			continue;
		}

		if (!strcmp(q->cra_driver_name, alg->cra_name) ||
		    !strcmp(q->cra_name, alg->cra_driver_name))
			goto err;
	}

	larval = crypto_larval_alloc(alg->cra_name,
				     alg->cra_flags | CRYPTO_ALG_TESTED, 0);
	if (IS_ERR(larval))
		goto out;

	ret = -ENOENT;
	larval->adult = crypto_mod_get(alg);
	if (!larval->adult)
		goto free_larval;

	atomic_set(&larval->alg.cra_refcnt, 1);
	memcpy(larval->alg.cra_driver_name, alg->cra_driver_name,
	       CRYPTO_MAX_ALG_NAME);
	larval->alg.cra_priority = alg->cra_priority;

	list_add(&alg->cra_list, &crypto_alg_list);
	list_add(&larval->alg.cra_list, &crypto_alg_list);

228
out:
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
	return larval;

free_larval:
	kfree(larval);
err:
	larval = ERR_PTR(ret);
	goto out;
}

void crypto_alg_tested(const char *name, int err)
{
	struct crypto_larval *test;
	struct crypto_alg *alg;
	struct crypto_alg *q;
	LIST_HEAD(list);

	down_write(&crypto_alg_sem);
	list_for_each_entry(q, &crypto_alg_list, cra_list) {
247
		if (crypto_is_moribund(q) || !crypto_is_larval(q))
248
249
250
251
252
253
254
255
256
257
258
259
			continue;

		test = (struct crypto_larval *)q;

		if (!strcmp(q->cra_driver_name, name))
			goto found;
	}

	printk(KERN_ERR "alg: Unexpected test result for %s: %d\n", name, err);
	goto unlock;

found:
260
	q->cra_flags |= CRYPTO_ALG_DEAD;
261
262
263
264
265
266
267
268
269
	alg = test->adult;
	if (err || list_empty(&alg->cra_list))
		goto complete;

	alg->cra_flags |= CRYPTO_ALG_TESTED;

	list_for_each_entry(q, &crypto_alg_list, cra_list) {
		if (q == alg)
			continue;
Herbert Xu's avatar
Herbert Xu committed
270
271
272
273
274

		if (crypto_is_moribund(q))
			continue;

		if (crypto_is_larval(q)) {
275
276
			struct crypto_larval *larval = (void *)q;

277
278
279
280
281
			/*
			 * Check to see if either our generic name or
			 * specific name can satisfy the name requested
			 * by the larval entry q.
			 */
Herbert Xu's avatar
Herbert Xu committed
282
283
284
285
286
287
			if (strcmp(alg->cra_name, q->cra_name) &&
			    strcmp(alg->cra_driver_name, q->cra_name))
				continue;

			if (larval->adult)
				continue;
288
289
			if ((q->cra_flags ^ alg->cra_flags) & larval->mask)
				continue;
290
291
			if (!crypto_mod_get(alg))
				continue;
Herbert Xu's avatar
Herbert Xu committed
292

293
			larval->adult = alg;
Herbert Xu's avatar
Herbert Xu committed
294
			continue;
295
		}
Herbert Xu's avatar
Herbert Xu committed
296
297
298
299
300
301
302
303

		if (strcmp(alg->cra_name, q->cra_name))
			continue;

		if (strcmp(alg->cra_driver_name, q->cra_driver_name) &&
		    q->cra_priority > alg->cra_priority)
			continue;

304
		crypto_remove_spawns(q, &list, alg);
305
	}
306

307
308
complete:
	complete_all(&test->completion);
309

310
311
312
313
unlock:
	up_write(&crypto_alg_sem);

	crypto_remove_final(&list);
314
}
315
EXPORT_SYMBOL_GPL(crypto_alg_tested);
316

317
void crypto_remove_final(struct list_head *list)
Herbert Xu's avatar
Herbert Xu committed
318
319
320
321
322
323
324
325
326
{
	struct crypto_alg *alg;
	struct crypto_alg *n;

	list_for_each_entry_safe(alg, n, list, cra_list) {
		list_del_init(&alg->cra_list);
		crypto_alg_put(alg);
	}
}
327
EXPORT_SYMBOL_GPL(crypto_remove_final);
Herbert Xu's avatar
Herbert Xu committed
328

329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
static void crypto_wait_for_test(struct crypto_larval *larval)
{
	int err;

	err = crypto_probing_notify(CRYPTO_MSG_ALG_REGISTER, larval->adult);
	if (err != NOTIFY_STOP) {
		if (WARN_ON(err != NOTIFY_DONE))
			goto out;
		crypto_alg_tested(larval->alg.cra_driver_name, 0);
	}

	err = wait_for_completion_interruptible(&larval->completion);
	WARN_ON(err);

out:
	crypto_larval_kill(&larval->alg);
}

347
348
int crypto_register_alg(struct crypto_alg *alg)
{
349
	struct crypto_larval *larval;
350
351
352
353
354
355
356
	int err;

	err = crypto_check_alg(alg);
	if (err)
		return err;

	down_write(&crypto_alg_sem);
357
	larval = __crypto_register_alg(alg);
358
359
	up_write(&crypto_alg_sem);

360
361
362
363
364
	if (IS_ERR(larval))
		return PTR_ERR(larval);

	crypto_wait_for_test(larval);
	return 0;
365
}
366
367
EXPORT_SYMBOL_GPL(crypto_register_alg);

Herbert Xu's avatar
Herbert Xu committed
368
369
370
371
372
373
374
375
376
static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
{
	if (unlikely(list_empty(&alg->cra_list)))
		return -ENOENT;

	alg->cra_flags |= CRYPTO_ALG_DEAD;

	crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
	list_del_init(&alg->cra_list);
377
	crypto_remove_spawns(alg, list, NULL);
Herbert Xu's avatar
Herbert Xu committed
378
379
380
381

	return 0;
}

382
383
int crypto_unregister_alg(struct crypto_alg *alg)
{
Herbert Xu's avatar
Herbert Xu committed
384
385
	int ret;
	LIST_HEAD(list);
386

387
	down_write(&crypto_alg_sem);
Herbert Xu's avatar
Herbert Xu committed
388
	ret = crypto_remove_alg(alg, &list);
389
390
391
392
393
394
395
396
397
	up_write(&crypto_alg_sem);

	if (ret)
		return ret;

	BUG_ON(atomic_read(&alg->cra_refcnt) != 1);
	if (alg->cra_destroy)
		alg->cra_destroy(alg);

Herbert Xu's avatar
Herbert Xu committed
398
	crypto_remove_final(&list);
399
400
401
402
	return 0;
}
EXPORT_SYMBOL_GPL(crypto_unregister_alg);

403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
int crypto_register_algs(struct crypto_alg *algs, int count)
{
	int i, ret;

	for (i = 0; i < count; i++) {
		ret = crypto_register_alg(&algs[i]);
		if (ret)
			goto err;
	}

	return 0;

err:
	for (--i; i >= 0; --i)
		crypto_unregister_alg(&algs[i]);

	return ret;
}
EXPORT_SYMBOL_GPL(crypto_register_algs);

int crypto_unregister_algs(struct crypto_alg *algs, int count)
{
	int i, ret;

	for (i = 0; i < count; i++) {
		ret = crypto_unregister_alg(&algs[i]);
		if (ret)
			pr_err("Failed to unregister %s %s: %d\n",
			       algs[i].cra_driver_name, algs[i].cra_name, ret);
	}

	return 0;
}
EXPORT_SYMBOL_GPL(crypto_unregister_algs);

438
439
440
441
442
443
444
int crypto_register_template(struct crypto_template *tmpl)
{
	struct crypto_template *q;
	int err = -EEXIST;

	down_write(&crypto_alg_sem);

445
446
	crypto_check_module_sig(tmpl->module);

447
448
449
450
451
452
	list_for_each_entry(q, &crypto_template_list, list) {
		if (q == tmpl)
			goto out;
	}

	list_add(&tmpl->list, &crypto_template_list);
453
	crypto_notify(CRYPTO_MSG_TMPL_REGISTER, tmpl);
454
455
456
457
458
459
460
461
462
463
	err = 0;
out:
	up_write(&crypto_alg_sem);
	return err;
}
EXPORT_SYMBOL_GPL(crypto_register_template);

void crypto_unregister_template(struct crypto_template *tmpl)
{
	struct crypto_instance *inst;
464
	struct hlist_node *n;
465
	struct hlist_head *list;
Herbert Xu's avatar
Herbert Xu committed
466
	LIST_HEAD(users);
467
468
469
470
471
472
473

	down_write(&crypto_alg_sem);

	BUG_ON(list_empty(&tmpl->list));
	list_del_init(&tmpl->list);

	list = &tmpl->instances;
474
	hlist_for_each_entry(inst, list, list) {
Herbert Xu's avatar
Herbert Xu committed
475
		int err = crypto_remove_alg(&inst->alg, &users);
476

Herbert Xu's avatar
Herbert Xu committed
477
		BUG_ON(err);
478
479
	}

480
481
	crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl);

482
483
	up_write(&crypto_alg_sem);

484
	hlist_for_each_entry_safe(inst, n, list, list) {
485
486
487
		BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1);
		tmpl->free(inst);
	}
Herbert Xu's avatar
Herbert Xu committed
488
	crypto_remove_final(&users);
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
}
EXPORT_SYMBOL_GPL(crypto_unregister_template);

static struct crypto_template *__crypto_lookup_template(const char *name)
{
	struct crypto_template *q, *tmpl = NULL;

	down_read(&crypto_alg_sem);
	list_for_each_entry(q, &crypto_template_list, list) {
		if (strcmp(q->name, name))
			continue;
		if (unlikely(!crypto_tmpl_get(q)))
			continue;

		tmpl = q;
		break;
	}
	up_read(&crypto_alg_sem);

	return tmpl;
}

struct crypto_template *crypto_lookup_template(const char *name)
{
513
514
	return try_then_request_module(__crypto_lookup_template(name),
				       "crypto-%s", name);
515
516
517
518
519
520
}
EXPORT_SYMBOL_GPL(crypto_lookup_template);

int crypto_register_instance(struct crypto_template *tmpl,
			     struct crypto_instance *inst)
{
521
522
	struct crypto_larval *larval;
	int err;
523
524
525
526
527
528

	err = crypto_check_alg(&inst->alg);
	if (err)
		goto err;

	inst->alg.cra_module = tmpl->module;
529
	inst->alg.cra_flags |= CRYPTO_ALG_INSTANCE;
530
531
532

	down_write(&crypto_alg_sem);

533
534
	larval = __crypto_register_alg(&inst->alg);
	if (IS_ERR(larval))
535
536
537
538
539
540
541
542
		goto unlock;

	hlist_add_head(&inst->list, &tmpl->instances);
	inst->tmpl = tmpl;

unlock:
	up_write(&crypto_alg_sem);

543
544
545
546
547
548
	err = PTR_ERR(larval);
	if (IS_ERR(larval))
		goto err;

	crypto_wait_for_test(larval);
	err = 0;
Herbert Xu's avatar
Herbert Xu committed
549

550
551
552
553
err:
	return err;
}
EXPORT_SYMBOL_GPL(crypto_register_instance);
554

555
int crypto_unregister_instance(struct crypto_instance *inst)
556
{
557
	LIST_HEAD(list);
558
559
560

	down_write(&crypto_alg_sem);

561
	crypto_remove_spawns(&inst->alg, &list, NULL);
562
	crypto_remove_instance(inst, &list);
563
564
565

	up_write(&crypto_alg_sem);

566
	crypto_remove_final(&list);
567
568
569
570

	return 0;
}
EXPORT_SYMBOL_GPL(crypto_unregister_instance);
571

Herbert Xu's avatar
Herbert Xu committed
572
int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
573
		      struct crypto_instance *inst, u32 mask)
Herbert Xu's avatar
Herbert Xu committed
574
575
576
577
{
	int err = -EAGAIN;

	spawn->inst = inst;
578
	spawn->mask = mask;
Herbert Xu's avatar
Herbert Xu committed
579
580
581
582
583
584
585
586
587
588
589
590
591

	down_write(&crypto_alg_sem);
	if (!crypto_is_moribund(alg)) {
		list_add(&spawn->list, &alg->cra_users);
		spawn->alg = alg;
		err = 0;
	}
	up_write(&crypto_alg_sem);

	return err;
}
EXPORT_SYMBOL_GPL(crypto_init_spawn);

592
593
594
595
596
597
int crypto_init_spawn2(struct crypto_spawn *spawn, struct crypto_alg *alg,
		       struct crypto_instance *inst,
		       const struct crypto_type *frontend)
{
	int err = -EINVAL;

598
	if ((alg->cra_flags ^ frontend->type) & frontend->maskset)
599
600
601
602
603
604
605
606
607
608
		goto out;

	spawn->frontend = frontend;
	err = crypto_init_spawn(spawn, alg, inst, frontend->maskset);

out:
	return err;
}
EXPORT_SYMBOL_GPL(crypto_init_spawn2);

Herbert Xu's avatar
Herbert Xu committed
609
610
void crypto_drop_spawn(struct crypto_spawn *spawn)
{
611
612
613
	if (!spawn->alg)
		return;

Herbert Xu's avatar
Herbert Xu committed
614
615
616
617
618
619
	down_write(&crypto_alg_sem);
	list_del(&spawn->list);
	up_write(&crypto_alg_sem);
}
EXPORT_SYMBOL_GPL(crypto_drop_spawn);

620
static struct crypto_alg *crypto_spawn_alg(struct crypto_spawn *spawn)
Herbert Xu's avatar
Herbert Xu committed
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
{
	struct crypto_alg *alg;
	struct crypto_alg *alg2;

	down_read(&crypto_alg_sem);
	alg = spawn->alg;
	alg2 = alg;
	if (alg2)
		alg2 = crypto_mod_get(alg2);
	up_read(&crypto_alg_sem);

	if (!alg2) {
		if (alg)
			crypto_shoot_alg(alg);
		return ERR_PTR(-EAGAIN);
	}

638
639
640
641
642
643
644
645
646
647
648
649
650
	return alg;
}

struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
				    u32 mask)
{
	struct crypto_alg *alg;
	struct crypto_tfm *tfm;

	alg = crypto_spawn_alg(spawn);
	if (IS_ERR(alg))
		return ERR_CAST(alg);

651
652
653
654
	tfm = ERR_PTR(-EINVAL);
	if (unlikely((alg->cra_flags ^ type) & mask))
		goto out_put_alg;

655
	tfm = __crypto_alloc_tfm(alg, type, mask);
Herbert Xu's avatar
Herbert Xu committed
656
	if (IS_ERR(tfm))
657
658
659
		goto out_put_alg;

	return tfm;
Herbert Xu's avatar
Herbert Xu committed
660

661
662
out_put_alg:
	crypto_mod_put(alg);
Herbert Xu's avatar
Herbert Xu committed
663
664
665
666
	return tfm;
}
EXPORT_SYMBOL_GPL(crypto_spawn_tfm);

667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
void *crypto_spawn_tfm2(struct crypto_spawn *spawn)
{
	struct crypto_alg *alg;
	struct crypto_tfm *tfm;

	alg = crypto_spawn_alg(spawn);
	if (IS_ERR(alg))
		return ERR_CAST(alg);

	tfm = crypto_create_tfm(alg, spawn->frontend);
	if (IS_ERR(tfm))
		goto out_put_alg;

	return tfm;

out_put_alg:
	crypto_mod_put(alg);
	return tfm;
}
EXPORT_SYMBOL_GPL(crypto_spawn_tfm2);

688
689
690
691
692
693
694
695
696
697
698
699
int crypto_register_notifier(struct notifier_block *nb)
{
	return blocking_notifier_chain_register(&crypto_chain, nb);
}
EXPORT_SYMBOL_GPL(crypto_register_notifier);

int crypto_unregister_notifier(struct notifier_block *nb)
{
	return blocking_notifier_chain_unregister(&crypto_chain, nb);
}
EXPORT_SYMBOL_GPL(crypto_unregister_notifier);

700
struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb)
701
{
702
	struct rtattr *rta = tb[0];
703
704
705
706
707
708
	struct crypto_attr_type *algt;

	if (!rta)
		return ERR_PTR(-ENOENT);
	if (RTA_PAYLOAD(rta) < sizeof(*algt))
		return ERR_PTR(-EINVAL);
709
710
	if (rta->rta_type != CRYPTOA_TYPE)
		return ERR_PTR(-EINVAL);
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732

	algt = RTA_DATA(rta);

	return algt;
}
EXPORT_SYMBOL_GPL(crypto_get_attr_type);

int crypto_check_attr_type(struct rtattr **tb, u32 type)
{
	struct crypto_attr_type *algt;

	algt = crypto_get_attr_type(tb);
	if (IS_ERR(algt))
		return PTR_ERR(algt);

	if ((algt->type ^ type) & algt->mask)
		return -EINVAL;

	return 0;
}
EXPORT_SYMBOL_GPL(crypto_check_attr_type);

733
const char *crypto_attr_alg_name(struct rtattr *rta)
734
{
735
736
	struct crypto_attr_alg *alga;

737
738
739
	if (!rta)
		return ERR_PTR(-ENOENT);
	if (RTA_PAYLOAD(rta) < sizeof(*alga))
740
		return ERR_PTR(-EINVAL);
741
742
	if (rta->rta_type != CRYPTOA_ALG)
		return ERR_PTR(-EINVAL);
743
744
745
746

	alga = RTA_DATA(rta);
	alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0;

747
748
749
750
	return alga->name;
}
EXPORT_SYMBOL_GPL(crypto_attr_alg_name);

751
752
753
struct crypto_alg *crypto_attr_alg2(struct rtattr *rta,
				    const struct crypto_type *frontend,
				    u32 type, u32 mask)
754
755
756
757
758
{
	const char *name;

	name = crypto_attr_alg_name(rta);
	if (IS_ERR(name))
Julia Lawall's avatar
Julia Lawall committed
759
		return ERR_CAST(name);
760

761
	return crypto_find_alg(name, frontend, type, mask);
762
}
763
EXPORT_SYMBOL_GPL(crypto_attr_alg2);
Herbert Xu's avatar
Herbert Xu committed
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781

int crypto_attr_u32(struct rtattr *rta, u32 *num)
{
	struct crypto_attr_u32 *nu32;

	if (!rta)
		return -ENOENT;
	if (RTA_PAYLOAD(rta) < sizeof(*nu32))
		return -EINVAL;
	if (rta->rta_type != CRYPTOA_U32)
		return -EINVAL;

	nu32 = RTA_DATA(rta);
	*num = nu32->num;

	return 0;
}
EXPORT_SYMBOL_GPL(crypto_attr_u32);
782

783
784
void *crypto_alloc_instance2(const char *name, struct crypto_alg *alg,
			     unsigned int head)
785
786
{
	struct crypto_instance *inst;
787
	char *p;
788
789
	int err;

790
791
792
	p = kzalloc(head + sizeof(*inst) + sizeof(struct crypto_spawn),
		    GFP_KERNEL);
	if (!p)
793
794
		return ERR_PTR(-ENOMEM);

795
796
	inst = (void *)(p + head);

797
798
799
800
801
802
803
804
805
	err = -ENAMETOOLONG;
	if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", name,
		     alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
		goto err_free_inst;

	if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
		     name, alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
		goto err_free_inst;

806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
	return p;

err_free_inst:
	kfree(p);
	return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(crypto_alloc_instance2);

struct crypto_instance *crypto_alloc_instance(const char *name,
					      struct crypto_alg *alg)
{
	struct crypto_instance *inst;
	struct crypto_spawn *spawn;
	int err;

	inst = crypto_alloc_instance2(name, alg, 0);
	if (IS_ERR(inst))
		goto out;

825
	spawn = crypto_instance_ctx(inst);
826
827
	err = crypto_init_spawn(spawn, alg, inst,
				CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
828
829
830
831
832
833
834
835

	if (err)
		goto err_free_inst;

	return inst;

err_free_inst:
	kfree(inst);
836
837
838
839
	inst = ERR_PTR(err);

out:
	return inst;
840
841
842
}
EXPORT_SYMBOL_GPL(crypto_alloc_instance);

843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen)
{
	INIT_LIST_HEAD(&queue->list);
	queue->backlog = &queue->list;
	queue->qlen = 0;
	queue->max_qlen = max_qlen;
}
EXPORT_SYMBOL_GPL(crypto_init_queue);

int crypto_enqueue_request(struct crypto_queue *queue,
			   struct crypto_async_request *request)
{
	int err = -EINPROGRESS;

	if (unlikely(queue->qlen >= queue->max_qlen)) {
		err = -EBUSY;
		if (!(request->flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
			goto out;
		if (queue->backlog == &queue->list)
			queue->backlog = &request->list;
	}

	queue->qlen++;
	list_add_tail(&request->list, &queue->list);

out:
	return err;
}
EXPORT_SYMBOL_GPL(crypto_enqueue_request);

873
void *__crypto_dequeue_request(struct crypto_queue *queue, unsigned int offset)
874
875
876
877
878
879
880
881
882
883
884
885
886
887
{
	struct list_head *request;

	if (unlikely(!queue->qlen))
		return NULL;

	queue->qlen--;

	if (queue->backlog != &queue->list)
		queue->backlog = queue->backlog->next;

	request = queue->list.next;
	list_del(request);

888
889
890
891
892
893
894
895
	return (char *)list_entry(request, struct crypto_async_request, list) -
	       offset;
}
EXPORT_SYMBOL_GPL(__crypto_dequeue_request);

struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue)
{
	return __crypto_dequeue_request(queue, 0);
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
}
EXPORT_SYMBOL_GPL(crypto_dequeue_request);

int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm)
{
	struct crypto_async_request *req;

	list_for_each_entry(req, &queue->list, list) {
		if (req->tfm == tfm)
			return 1;
	}

	return 0;
}
EXPORT_SYMBOL_GPL(crypto_tfm_in_queue);

912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
static inline void crypto_inc_byte(u8 *a, unsigned int size)
{
	u8 *b = (a + size);
	u8 c;

	for (; size; size--) {
		c = *--b + 1;
		*b = c;
		if (c)
			break;
	}
}

void crypto_inc(u8 *a, unsigned int size)
{
	__be32 *b = (__be32 *)(a + size);
	u32 c;

	for (; size >= 4; size -= 4) {
		c = be32_to_cpu(*--b) + 1;
		*b = cpu_to_be32(c);
		if (c)
			return;
	}

	crypto_inc_byte(a, size);
}
EXPORT_SYMBOL_GPL(crypto_inc);

static inline void crypto_xor_byte(u8 *a, const u8 *b, unsigned int size)
{
	for (; size; size--)
		*a++ ^= *b++;
}

void crypto_xor(u8 *dst, const u8 *src, unsigned int size)
{
	u32 *a = (u32 *)dst;
	u32 *b = (u32 *)src;

	for (; size >= 4; size -= 4)
		*a++ ^= *b++;

	crypto_xor_byte((u8 *)a, (u8 *)b, size);
}
EXPORT_SYMBOL_GPL(crypto_xor);

959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
static int __init crypto_algapi_init(void)
{
	crypto_init_proc();
	return 0;
}

static void __exit crypto_algapi_exit(void)
{
	crypto_exit_proc();
}

module_init(crypto_algapi_init);
module_exit(crypto_algapi_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cryptographic algorithms API");