xref: /openbmc/linux/crypto/algboss.c (revision 1aa4ecd9)
1da7f033dSHerbert Xu /*
2da7f033dSHerbert Xu  * Create default crypto algorithm instances.
3da7f033dSHerbert Xu  *
4da7f033dSHerbert Xu  * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
5da7f033dSHerbert Xu  *
6da7f033dSHerbert Xu  * This program is free software; you can redistribute it and/or modify it
7da7f033dSHerbert Xu  * under the terms of the GNU General Public License as published by the Free
8da7f033dSHerbert Xu  * Software Foundation; either version 2 of the License, or (at your option)
9da7f033dSHerbert Xu  * any later version.
10da7f033dSHerbert Xu  *
11da7f033dSHerbert Xu  */
12da7f033dSHerbert Xu 
13da7f033dSHerbert Xu #include <linux/crypto.h>
14da7f033dSHerbert Xu #include <linux/ctype.h>
15da7f033dSHerbert Xu #include <linux/err.h>
16da7f033dSHerbert Xu #include <linux/init.h>
17da7f033dSHerbert Xu #include <linux/kthread.h>
18da7f033dSHerbert Xu #include <linux/module.h>
19da7f033dSHerbert Xu #include <linux/notifier.h>
20da7f033dSHerbert Xu #include <linux/rtnetlink.h>
21da7f033dSHerbert Xu #include <linux/sched.h>
22da7f033dSHerbert Xu #include <linux/string.h>
23da7f033dSHerbert Xu 
24da7f033dSHerbert Xu #include "internal.h"
25da7f033dSHerbert Xu 
26da7f033dSHerbert Xu struct cryptomgr_param {
27da7f033dSHerbert Xu 	struct rtattr *tb[CRYPTO_MAX_ATTRS + 2];
28da7f033dSHerbert Xu 
29da7f033dSHerbert Xu 	struct {
30da7f033dSHerbert Xu 		struct rtattr attr;
31da7f033dSHerbert Xu 		struct crypto_attr_type data;
32da7f033dSHerbert Xu 	} type;
33da7f033dSHerbert Xu 
34da7f033dSHerbert Xu 	union {
35da7f033dSHerbert Xu 		struct rtattr attr;
36da7f033dSHerbert Xu 		struct {
37da7f033dSHerbert Xu 			struct rtattr attr;
38da7f033dSHerbert Xu 			struct crypto_attr_alg data;
39da7f033dSHerbert Xu 		} alg;
40da7f033dSHerbert Xu 		struct {
41da7f033dSHerbert Xu 			struct rtattr attr;
42da7f033dSHerbert Xu 			struct crypto_attr_u32 data;
43da7f033dSHerbert Xu 		} nu32;
44da7f033dSHerbert Xu 	} attrs[CRYPTO_MAX_ATTRS];
45da7f033dSHerbert Xu 
46da7f033dSHerbert Xu 	char larval[CRYPTO_MAX_ALG_NAME];
47da7f033dSHerbert Xu 	char template[CRYPTO_MAX_ALG_NAME];
4873d3864aSHerbert Xu 
4973d3864aSHerbert Xu 	u32 otype;
5073d3864aSHerbert Xu 	u32 omask;
5173d3864aSHerbert Xu };
5273d3864aSHerbert Xu 
5373d3864aSHerbert Xu struct crypto_test_param {
5473d3864aSHerbert Xu 	char driver[CRYPTO_MAX_ALG_NAME];
5573d3864aSHerbert Xu 	char alg[CRYPTO_MAX_ALG_NAME];
5673d3864aSHerbert Xu 	u32 type;
57da7f033dSHerbert Xu };
58da7f033dSHerbert Xu 
59da7f033dSHerbert Xu static int cryptomgr_probe(void *data)
60da7f033dSHerbert Xu {
61da7f033dSHerbert Xu 	struct cryptomgr_param *param = data;
62da7f033dSHerbert Xu 	struct crypto_template *tmpl;
63da7f033dSHerbert Xu 	struct crypto_instance *inst;
64da7f033dSHerbert Xu 	int err;
65da7f033dSHerbert Xu 
66da7f033dSHerbert Xu 	tmpl = crypto_lookup_template(param->template);
67da7f033dSHerbert Xu 	if (!tmpl)
68da7f033dSHerbert Xu 		goto err;
69da7f033dSHerbert Xu 
70da7f033dSHerbert Xu 	do {
71da7f033dSHerbert Xu 		inst = tmpl->alloc(param->tb);
72da7f033dSHerbert Xu 		if (IS_ERR(inst))
73da7f033dSHerbert Xu 			err = PTR_ERR(inst);
74da7f033dSHerbert Xu 		else if ((err = crypto_register_instance(tmpl, inst)))
75da7f033dSHerbert Xu 			tmpl->free(inst);
76da7f033dSHerbert Xu 	} while (err == -EAGAIN && !signal_pending(current));
77da7f033dSHerbert Xu 
78da7f033dSHerbert Xu 	crypto_tmpl_put(tmpl);
79da7f033dSHerbert Xu 
80da7f033dSHerbert Xu 	if (err)
81da7f033dSHerbert Xu 		goto err;
82da7f033dSHerbert Xu 
83da7f033dSHerbert Xu out:
84da7f033dSHerbert Xu 	kfree(param);
85da7f033dSHerbert Xu 	module_put_and_exit(0);
86da7f033dSHerbert Xu 
87da7f033dSHerbert Xu err:
8873d3864aSHerbert Xu 	crypto_larval_error(param->larval, param->otype, param->omask);
89da7f033dSHerbert Xu 	goto out;
90da7f033dSHerbert Xu }
91da7f033dSHerbert Xu 
92da7f033dSHerbert Xu static int cryptomgr_schedule_probe(struct crypto_larval *larval)
93da7f033dSHerbert Xu {
94da7f033dSHerbert Xu 	struct task_struct *thread;
95da7f033dSHerbert Xu 	struct cryptomgr_param *param;
96da7f033dSHerbert Xu 	const char *name = larval->alg.cra_name;
97da7f033dSHerbert Xu 	const char *p;
98da7f033dSHerbert Xu 	unsigned int len;
99da7f033dSHerbert Xu 	int i;
100da7f033dSHerbert Xu 
101da7f033dSHerbert Xu 	if (!try_module_get(THIS_MODULE))
102da7f033dSHerbert Xu 		goto err;
103da7f033dSHerbert Xu 
104da7f033dSHerbert Xu 	param = kzalloc(sizeof(*param), GFP_KERNEL);
105da7f033dSHerbert Xu 	if (!param)
106da7f033dSHerbert Xu 		goto err_put_module;
107da7f033dSHerbert Xu 
108da7f033dSHerbert Xu 	for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++)
109da7f033dSHerbert Xu 		;
110da7f033dSHerbert Xu 
111da7f033dSHerbert Xu 	len = p - name;
112da7f033dSHerbert Xu 	if (!len || *p != '(')
113da7f033dSHerbert Xu 		goto err_free_param;
114da7f033dSHerbert Xu 
115da7f033dSHerbert Xu 	memcpy(param->template, name, len);
116da7f033dSHerbert Xu 
117da7f033dSHerbert Xu 	i = 0;
118da7f033dSHerbert Xu 	for (;;) {
119da7f033dSHerbert Xu 		int notnum = 0;
120da7f033dSHerbert Xu 
121da7f033dSHerbert Xu 		name = ++p;
122da7f033dSHerbert Xu 		len = 0;
123da7f033dSHerbert Xu 
124da7f033dSHerbert Xu 		for (; isalnum(*p) || *p == '-' || *p == '_'; p++)
125da7f033dSHerbert Xu 			notnum |= !isdigit(*p);
126da7f033dSHerbert Xu 
127da7f033dSHerbert Xu 		if (*p == '(') {
128da7f033dSHerbert Xu 			int recursion = 0;
129da7f033dSHerbert Xu 
130da7f033dSHerbert Xu 			for (;;) {
131da7f033dSHerbert Xu 				if (!*++p)
132da7f033dSHerbert Xu 					goto err_free_param;
133da7f033dSHerbert Xu 				if (*p == '(')
134da7f033dSHerbert Xu 					recursion++;
135da7f033dSHerbert Xu 				else if (*p == ')' && !recursion--)
136da7f033dSHerbert Xu 					break;
137da7f033dSHerbert Xu 			}
138da7f033dSHerbert Xu 
139da7f033dSHerbert Xu 			notnum = 1;
140da7f033dSHerbert Xu 			p++;
141da7f033dSHerbert Xu 		}
142da7f033dSHerbert Xu 
143da7f033dSHerbert Xu 		len = p - name;
144da7f033dSHerbert Xu 		if (!len)
145da7f033dSHerbert Xu 			goto err_free_param;
146da7f033dSHerbert Xu 
147da7f033dSHerbert Xu 		if (notnum) {
148da7f033dSHerbert Xu 			param->attrs[i].alg.attr.rta_len =
149da7f033dSHerbert Xu 				sizeof(param->attrs[i].alg);
150da7f033dSHerbert Xu 			param->attrs[i].alg.attr.rta_type = CRYPTOA_ALG;
151da7f033dSHerbert Xu 			memcpy(param->attrs[i].alg.data.name, name, len);
152da7f033dSHerbert Xu 		} else {
153da7f033dSHerbert Xu 			param->attrs[i].nu32.attr.rta_len =
154da7f033dSHerbert Xu 				sizeof(param->attrs[i].nu32);
155da7f033dSHerbert Xu 			param->attrs[i].nu32.attr.rta_type = CRYPTOA_U32;
156da7f033dSHerbert Xu 			param->attrs[i].nu32.data.num =
157da7f033dSHerbert Xu 				simple_strtol(name, NULL, 0);
158da7f033dSHerbert Xu 		}
159da7f033dSHerbert Xu 
160da7f033dSHerbert Xu 		param->tb[i + 1] = &param->attrs[i].attr;
161da7f033dSHerbert Xu 		i++;
162da7f033dSHerbert Xu 
163da7f033dSHerbert Xu 		if (i >= CRYPTO_MAX_ATTRS)
164da7f033dSHerbert Xu 			goto err_free_param;
165da7f033dSHerbert Xu 
166da7f033dSHerbert Xu 		if (*p == ')')
167da7f033dSHerbert Xu 			break;
168da7f033dSHerbert Xu 
169da7f033dSHerbert Xu 		if (*p != ',')
170da7f033dSHerbert Xu 			goto err_free_param;
171da7f033dSHerbert Xu 	}
172da7f033dSHerbert Xu 
173da7f033dSHerbert Xu 	if (!i)
174da7f033dSHerbert Xu 		goto err_free_param;
175da7f033dSHerbert Xu 
176da7f033dSHerbert Xu 	param->tb[i + 1] = NULL;
177da7f033dSHerbert Xu 
178da7f033dSHerbert Xu 	param->type.attr.rta_len = sizeof(param->type);
179da7f033dSHerbert Xu 	param->type.attr.rta_type = CRYPTOA_TYPE;
18073d3864aSHerbert Xu 	param->type.data.type = larval->alg.cra_flags & ~CRYPTO_ALG_TESTED;
18173d3864aSHerbert Xu 	param->type.data.mask = larval->mask & ~CRYPTO_ALG_TESTED;
182da7f033dSHerbert Xu 	param->tb[0] = &param->type.attr;
183da7f033dSHerbert Xu 
18473d3864aSHerbert Xu 	param->otype = larval->alg.cra_flags;
18573d3864aSHerbert Xu 	param->omask = larval->mask;
18673d3864aSHerbert Xu 
187da7f033dSHerbert Xu 	memcpy(param->larval, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME);
188da7f033dSHerbert Xu 
18973d3864aSHerbert Xu 	thread = kthread_run(cryptomgr_probe, param, "cryptomgr_probe");
19073d3864aSHerbert Xu 	if (IS_ERR(thread))
19173d3864aSHerbert Xu 		goto err_free_param;
19273d3864aSHerbert Xu 
19373d3864aSHerbert Xu 	return NOTIFY_STOP;
19473d3864aSHerbert Xu 
19573d3864aSHerbert Xu err_free_param:
19673d3864aSHerbert Xu 	kfree(param);
19773d3864aSHerbert Xu err_put_module:
19873d3864aSHerbert Xu 	module_put(THIS_MODULE);
19973d3864aSHerbert Xu err:
20073d3864aSHerbert Xu 	return NOTIFY_OK;
20173d3864aSHerbert Xu }
20273d3864aSHerbert Xu 
20373d3864aSHerbert Xu static int cryptomgr_test(void *data)
20473d3864aSHerbert Xu {
20573d3864aSHerbert Xu 	struct crypto_test_param *param = data;
20673d3864aSHerbert Xu 	u32 type = param->type;
20773d3864aSHerbert Xu 	int err = 0;
20873d3864aSHerbert Xu 
20973d3864aSHerbert Xu 	if (!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) &
21073d3864aSHerbert Xu 	      CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV))
21173d3864aSHerbert Xu 		goto skiptest;
21273d3864aSHerbert Xu 
2131aa4ecd9SHerbert Xu 	err = alg_test(param->driver, param->alg, type, CRYPTO_ALG_TESTED);
21473d3864aSHerbert Xu 
21573d3864aSHerbert Xu skiptest:
21673d3864aSHerbert Xu 	crypto_alg_tested(param->driver, err);
21773d3864aSHerbert Xu 
21873d3864aSHerbert Xu 	kfree(param);
21973d3864aSHerbert Xu 	module_put_and_exit(0);
22073d3864aSHerbert Xu }
22173d3864aSHerbert Xu 
22273d3864aSHerbert Xu static int cryptomgr_schedule_test(struct crypto_alg *alg)
22373d3864aSHerbert Xu {
22473d3864aSHerbert Xu 	struct task_struct *thread;
22573d3864aSHerbert Xu 	struct crypto_test_param *param;
22673d3864aSHerbert Xu 
22773d3864aSHerbert Xu 	if (!try_module_get(THIS_MODULE))
22873d3864aSHerbert Xu 		goto err;
22973d3864aSHerbert Xu 
23073d3864aSHerbert Xu 	param = kzalloc(sizeof(*param), GFP_KERNEL);
23173d3864aSHerbert Xu 	if (!param)
23273d3864aSHerbert Xu 		goto err_put_module;
23373d3864aSHerbert Xu 
23473d3864aSHerbert Xu 	memcpy(param->driver, alg->cra_driver_name, sizeof(param->driver));
23573d3864aSHerbert Xu 	memcpy(param->alg, alg->cra_name, sizeof(param->alg));
23673d3864aSHerbert Xu 	param->type = alg->cra_flags;
23773d3864aSHerbert Xu 
23873d3864aSHerbert Xu 	thread = kthread_run(cryptomgr_test, param, "cryptomgr_test");
239da7f033dSHerbert Xu 	if (IS_ERR(thread))
240da7f033dSHerbert Xu 		goto err_free_param;
241da7f033dSHerbert Xu 
242da7f033dSHerbert Xu 	return NOTIFY_STOP;
243da7f033dSHerbert Xu 
244da7f033dSHerbert Xu err_free_param:
245da7f033dSHerbert Xu 	kfree(param);
246da7f033dSHerbert Xu err_put_module:
247da7f033dSHerbert Xu 	module_put(THIS_MODULE);
248da7f033dSHerbert Xu err:
249da7f033dSHerbert Xu 	return NOTIFY_OK;
250da7f033dSHerbert Xu }
251da7f033dSHerbert Xu 
252da7f033dSHerbert Xu static int cryptomgr_notify(struct notifier_block *this, unsigned long msg,
253da7f033dSHerbert Xu 			    void *data)
254da7f033dSHerbert Xu {
255da7f033dSHerbert Xu 	switch (msg) {
256da7f033dSHerbert Xu 	case CRYPTO_MSG_ALG_REQUEST:
257da7f033dSHerbert Xu 		return cryptomgr_schedule_probe(data);
25873d3864aSHerbert Xu 	case CRYPTO_MSG_ALG_REGISTER:
25973d3864aSHerbert Xu 		return cryptomgr_schedule_test(data);
260da7f033dSHerbert Xu 	}
261da7f033dSHerbert Xu 
262da7f033dSHerbert Xu 	return NOTIFY_DONE;
263da7f033dSHerbert Xu }
264da7f033dSHerbert Xu 
265da7f033dSHerbert Xu static struct notifier_block cryptomgr_notifier = {
266da7f033dSHerbert Xu 	.notifier_call = cryptomgr_notify,
267da7f033dSHerbert Xu };
268da7f033dSHerbert Xu 
269da7f033dSHerbert Xu static int __init cryptomgr_init(void)
270da7f033dSHerbert Xu {
271da7f033dSHerbert Xu 	int err;
272da7f033dSHerbert Xu 
273da7f033dSHerbert Xu 	err = testmgr_init();
274da7f033dSHerbert Xu 	if (err)
275da7f033dSHerbert Xu 		return err;
276da7f033dSHerbert Xu 
277da7f033dSHerbert Xu 	err = crypto_register_notifier(&cryptomgr_notifier);
278da7f033dSHerbert Xu 	if (err)
279da7f033dSHerbert Xu 		goto free_testmgr;
280da7f033dSHerbert Xu 
281da7f033dSHerbert Xu 	return 0;
282da7f033dSHerbert Xu 
283da7f033dSHerbert Xu free_testmgr:
284da7f033dSHerbert Xu 	testmgr_exit();
285da7f033dSHerbert Xu 	return err;
286da7f033dSHerbert Xu }
287da7f033dSHerbert Xu 
288da7f033dSHerbert Xu static void __exit cryptomgr_exit(void)
289da7f033dSHerbert Xu {
290da7f033dSHerbert Xu 	int err = crypto_unregister_notifier(&cryptomgr_notifier);
291da7f033dSHerbert Xu 	BUG_ON(err);
292da7f033dSHerbert Xu 
293da7f033dSHerbert Xu 	testmgr_exit();
294da7f033dSHerbert Xu }
295da7f033dSHerbert Xu 
296da7f033dSHerbert Xu subsys_initcall(cryptomgr_init);
297da7f033dSHerbert Xu module_exit(cryptomgr_exit);
298da7f033dSHerbert Xu 
299da7f033dSHerbert Xu MODULE_LICENSE("GPL");
300da7f033dSHerbert Xu MODULE_DESCRIPTION("Crypto Algorithm Manager");
301