crypto_user.c 13.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Crypto user configuration API.
 *
 * Copyright (C) 2011 secunet Security Networks AG
 * Copyright (C) 2011 Steffen Klassert <steffen.klassert@secunet.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <linux/module.h>
#include <linux/crypto.h>
#include <linux/cryptouser.h>
24
#include <linux/sched.h>
25 26 27
#include <net/netlink.h>
#include <linux/security.h>
#include <net/net_namespace.h>
28
#include <crypto/internal/skcipher.h>
29
#include <crypto/internal/rng.h>
T
Tadeusz Struk 已提交
30
#include <crypto/akcipher.h>
31
#include <crypto/kpp.h>
32

33 34
#include "internal.h"

35 36
#define null_terminated(x)	(strnlen(x, sizeof(x)) < sizeof(x))

37
static DEFINE_MUTEX(crypto_cfg_mutex);
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55

/* The crypto netlink socket */
static struct sock *crypto_nlsk;

struct crypto_dump_info {
	struct sk_buff *in_skb;
	struct sk_buff *out_skb;
	u32 nlmsg_seq;
	u16 nlmsg_flags;
};

static struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact)
{
	struct crypto_alg *q, *alg = NULL;

	down_read(&crypto_alg_sem);

	list_for_each_entry(q, &crypto_alg_list, cra_list) {
56
		int match = 0;
57 58 59 60 61 62 63 64 65 66

		if ((q->cra_flags ^ p->cru_type) & p->cru_mask)
			continue;

		if (strlen(p->cru_driver_name))
			match = !strcmp(q->cra_driver_name,
					p->cru_driver_name);
		else if (!exact)
			match = !strcmp(q->cra_name, p->cru_name);

67 68 69 70 71 72 73 74
		if (!match)
			continue;

		if (unlikely(!crypto_mod_get(q)))
			continue;

		alg = q;
		break;
75 76 77 78 79 80 81
	}

	up_read(&crypto_alg_sem);

	return alg;
}

82 83 84 85
static int crypto_report_cipher(struct sk_buff *skb, struct crypto_alg *alg)
{
	struct crypto_report_cipher rcipher;

86
	strlcpy(rcipher.type, "cipher", sizeof(rcipher.type));
87 88 89 90 91

	rcipher.blocksize = alg->cra_blocksize;
	rcipher.min_keysize = alg->cra_cipher.cia_min_keysize;
	rcipher.max_keysize = alg->cra_cipher.cia_max_keysize;

D
David S. Miller 已提交
92 93 94
	if (nla_put(skb, CRYPTOCFGA_REPORT_CIPHER,
		    sizeof(struct crypto_report_cipher), &rcipher))
		goto nla_put_failure;
95 96 97 98 99 100
	return 0;

nla_put_failure:
	return -EMSGSIZE;
}

101 102 103 104
static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg)
{
	struct crypto_report_comp rcomp;

105
	strlcpy(rcomp.type, "compression", sizeof(rcomp.type));
D
David S. Miller 已提交
106 107 108
	if (nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS,
		    sizeof(struct crypto_report_comp), &rcomp))
		goto nla_put_failure;
109 110 111 112 113 114
	return 0;

nla_put_failure:
	return -EMSGSIZE;
}

115 116 117 118
static int crypto_report_acomp(struct sk_buff *skb, struct crypto_alg *alg)
{
	struct crypto_report_acomp racomp;

119
	strlcpy(racomp.type, "acomp", sizeof(racomp.type));
120 121 122 123 124 125 126 127 128 129

	if (nla_put(skb, CRYPTOCFGA_REPORT_ACOMP,
		    sizeof(struct crypto_report_acomp), &racomp))
		goto nla_put_failure;
	return 0;

nla_put_failure:
	return -EMSGSIZE;
}

T
Tadeusz Struk 已提交
130 131 132 133
static int crypto_report_akcipher(struct sk_buff *skb, struct crypto_alg *alg)
{
	struct crypto_report_akcipher rakcipher;

134
	strlcpy(rakcipher.type, "akcipher", sizeof(rakcipher.type));
T
Tadeusz Struk 已提交
135 136 137 138 139 140 141 142 143 144

	if (nla_put(skb, CRYPTOCFGA_REPORT_AKCIPHER,
		    sizeof(struct crypto_report_akcipher), &rakcipher))
		goto nla_put_failure;
	return 0;

nla_put_failure:
	return -EMSGSIZE;
}

145 146 147 148
static int crypto_report_kpp(struct sk_buff *skb, struct crypto_alg *alg)
{
	struct crypto_report_kpp rkpp;

149
	strlcpy(rkpp.type, "kpp", sizeof(rkpp.type));
150 151 152 153 154 155 156 157 158 159

	if (nla_put(skb, CRYPTOCFGA_REPORT_KPP,
		    sizeof(struct crypto_report_kpp), &rkpp))
		goto nla_put_failure;
	return 0;

nla_put_failure:
	return -EMSGSIZE;
}

160 161 162
static int crypto_report_one(struct crypto_alg *alg,
			     struct crypto_user_alg *ualg, struct sk_buff *skb)
{
163 164
	strlcpy(ualg->cru_name, alg->cra_name, sizeof(ualg->cru_name));
	strlcpy(ualg->cru_driver_name, alg->cra_driver_name,
165
		sizeof(ualg->cru_driver_name));
166
	strlcpy(ualg->cru_module_name, module_name(alg->cra_module),
167 168 169 170
		sizeof(ualg->cru_module_name));

	ualg->cru_type = 0;
	ualg->cru_mask = 0;
171 172 173
	ualg->cru_flags = alg->cra_flags;
	ualg->cru_refcnt = atomic_read(&alg->cra_refcnt);

D
David S. Miller 已提交
174 175
	if (nla_put_u32(skb, CRYPTOCFGA_PRIORITY_VAL, alg->cra_priority))
		goto nla_put_failure;
176 177 178
	if (alg->cra_flags & CRYPTO_ALG_LARVAL) {
		struct crypto_report_larval rl;

179
		strlcpy(rl.type, "larval", sizeof(rl.type));
D
David S. Miller 已提交
180 181 182
		if (nla_put(skb, CRYPTOCFGA_REPORT_LARVAL,
			    sizeof(struct crypto_report_larval), &rl))
			goto nla_put_failure;
183 184 185
		goto out;
	}

186 187 188
	if (alg->cra_type && alg->cra_type->report) {
		if (alg->cra_type->report(skb, alg))
			goto nla_put_failure;
189 190 191 192 193 194 195 196 197

		goto out;
	}

	switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) {
	case CRYPTO_ALG_TYPE_CIPHER:
		if (crypto_report_cipher(skb, alg))
			goto nla_put_failure;

198 199 200 201 202
		break;
	case CRYPTO_ALG_TYPE_COMPRESS:
		if (crypto_report_comp(skb, alg))
			goto nla_put_failure;

203
		break;
204 205 206
	case CRYPTO_ALG_TYPE_ACOMPRESS:
		if (crypto_report_acomp(skb, alg))
			goto nla_put_failure;
T
Tadeusz Struk 已提交
207

208
		break;
T
Tadeusz Struk 已提交
209 210 211 212 213
	case CRYPTO_ALG_TYPE_AKCIPHER:
		if (crypto_report_akcipher(skb, alg))
			goto nla_put_failure;

		break;
214 215 216 217
	case CRYPTO_ALG_TYPE_KPP:
		if (crypto_report_kpp(skb, alg))
			goto nla_put_failure;
		break;
218 219
	}

220
out:
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
	return 0;

nla_put_failure:
	return -EMSGSIZE;
}

static int crypto_report_alg(struct crypto_alg *alg,
			     struct crypto_dump_info *info)
{
	struct sk_buff *in_skb = info->in_skb;
	struct sk_buff *skb = info->out_skb;
	struct nlmsghdr *nlh;
	struct crypto_user_alg *ualg;
	int err = 0;

236
	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, info->nlmsg_seq,
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
			CRYPTO_MSG_GETALG, sizeof(*ualg), info->nlmsg_flags);
	if (!nlh) {
		err = -EMSGSIZE;
		goto out;
	}

	ualg = nlmsg_data(nlh);

	err = crypto_report_one(alg, ualg, skb);
	if (err) {
		nlmsg_cancel(skb, nlh);
		goto out;
	}

	nlmsg_end(skb, nlh);

out:
	return err;
}

static int crypto_report(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
			 struct nlattr **attrs)
{
	struct crypto_user_alg *p = nlmsg_data(in_nlh);
	struct crypto_alg *alg;
	struct sk_buff *skb;
	struct crypto_dump_info info;
	int err;

266 267 268
	if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
		return -EINVAL;

269
	alg = crypto_alg_match(p, 0);
270 271 272
	if (!alg)
		return -ENOENT;

273
	err = -ENOMEM;
274 275
	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
	if (!skb)
276
		goto drop_alg;
277 278 279 280 281 282 283

	info.in_skb = in_skb;
	info.out_skb = skb;
	info.nlmsg_seq = in_nlh->nlmsg_seq;
	info.nlmsg_flags = 0;

	err = crypto_report_alg(alg, &info);
284 285 286 287

drop_alg:
	crypto_mod_put(alg);

288 289 290
	if (err)
		return err;

291
	return nlmsg_unicast(crypto_nlsk, skb, NETLINK_CB(in_skb).portid);
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
}

static int crypto_dump_report(struct sk_buff *skb, struct netlink_callback *cb)
{
	struct crypto_alg *alg;
	struct crypto_dump_info info;
	int err;

	if (cb->args[0])
		goto out;

	cb->args[0] = 1;

	info.in_skb = cb->skb;
	info.out_skb = skb;
	info.nlmsg_seq = cb->nlh->nlmsg_seq;
	info.nlmsg_flags = NLM_F_MULTI;

	list_for_each_entry(alg, &crypto_alg_list, cra_list) {
		err = crypto_report_alg(alg, &info);
		if (err)
			goto out_err;
	}

out:
	return skb->len;
out_err:
	return err;
}

static int crypto_dump_report_done(struct netlink_callback *cb)
{
	return 0;
}

static int crypto_update_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
			     struct nlattr **attrs)
{
	struct crypto_alg *alg;
	struct crypto_user_alg *p = nlmsg_data(nlh);
	struct nlattr *priority = attrs[CRYPTOCFGA_PRIORITY_VAL];
	LIST_HEAD(list);

335
	if (!netlink_capable(skb, CAP_NET_ADMIN))
336 337
		return -EPERM;

338 339 340
	if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
		return -EINVAL;

341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
	if (priority && !strlen(p->cru_driver_name))
		return -EINVAL;

	alg = crypto_alg_match(p, 1);
	if (!alg)
		return -ENOENT;

	down_write(&crypto_alg_sem);

	crypto_remove_spawns(alg, &list, NULL);

	if (priority)
		alg->cra_priority = nla_get_u32(priority);

	up_write(&crypto_alg_sem);

357
	crypto_mod_put(alg);
358 359 360 361 362 363 364 365 366 367
	crypto_remove_final(&list);

	return 0;
}

static int crypto_del_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
			  struct nlattr **attrs)
{
	struct crypto_alg *alg;
	struct crypto_user_alg *p = nlmsg_data(nlh);
368
	int err;
369

370
	if (!netlink_capable(skb, CAP_NET_ADMIN))
371 372
		return -EPERM;

373 374 375
	if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
		return -EINVAL;

376 377 378 379 380 381 382 383 384
	alg = crypto_alg_match(p, 1);
	if (!alg)
		return -ENOENT;

	/* We can not unregister core algorithms such as aes-generic.
	 * We would loose the reference in the crypto_alg_list to this algorithm
	 * if we try to unregister. Unregistering such an algorithm without
	 * removing the module is not possible, so we restrict to crypto
	 * instances that are build from templates. */
385
	err = -EINVAL;
386
	if (!(alg->cra_flags & CRYPTO_ALG_INSTANCE))
387
		goto drop_alg;
388

389 390 391
	err = -EBUSY;
	if (atomic_read(&alg->cra_refcnt) > 2)
		goto drop_alg;
392

393 394 395 396 397
	err = crypto_unregister_instance((struct crypto_instance *)alg);

drop_alg:
	crypto_mod_put(alg);
	return err;
398 399 400 401 402
}

static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
			  struct nlattr **attrs)
{
403
	int exact = 0;
404 405 406 407 408
	const char *name;
	struct crypto_alg *alg;
	struct crypto_user_alg *p = nlmsg_data(nlh);
	struct nlattr *priority = attrs[CRYPTOCFGA_PRIORITY_VAL];

409
	if (!netlink_capable(skb, CAP_NET_ADMIN))
410 411
		return -EPERM;

412 413 414
	if (!null_terminated(p->cru_name) || !null_terminated(p->cru_driver_name))
		return -EINVAL;

415 416 417 418 419 420 421
	if (strlen(p->cru_driver_name))
		exact = 1;

	if (priority && !exact)
		return -EINVAL;

	alg = crypto_alg_match(p, exact);
422 423
	if (alg) {
		crypto_mod_put(alg);
424
		return -EEXIST;
425
	}
426 427 428 429 430 431

	if (strlen(p->cru_driver_name))
		name = p->cru_driver_name;
	else
		name = p->cru_name;

432
	alg = crypto_alg_mod_lookup(name, p->cru_type, p->cru_mask);
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
	if (IS_ERR(alg))
		return PTR_ERR(alg);

	down_write(&crypto_alg_sem);

	if (priority)
		alg->cra_priority = nla_get_u32(priority);

	up_write(&crypto_alg_sem);

	crypto_mod_put(alg);

	return 0;
}

448 449 450 451 452 453 454 455
static int crypto_del_rng(struct sk_buff *skb, struct nlmsghdr *nlh,
			  struct nlattr **attrs)
{
	if (!netlink_capable(skb, CAP_NET_ADMIN))
		return -EPERM;
	return crypto_del_default_rng();
}

456 457 458 459 460 461
#define MSGSIZE(type) sizeof(struct type)

static const int crypto_msg_min[CRYPTO_NR_MSGTYPES] = {
	[CRYPTO_MSG_NEWALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
	[CRYPTO_MSG_DELALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
	[CRYPTO_MSG_UPDATEALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
462
	[CRYPTO_MSG_GETALG	- CRYPTO_MSG_BASE] = MSGSIZE(crypto_user_alg),
463
	[CRYPTO_MSG_DELRNG	- CRYPTO_MSG_BASE] = 0,
464 465 466 467 468 469 470 471
};

static const struct nla_policy crypto_policy[CRYPTOCFGA_MAX+1] = {
	[CRYPTOCFGA_PRIORITY_VAL]   = { .type = NLA_U32},
};

#undef MSGSIZE

472
static const struct crypto_link {
473 474 475 476 477 478 479 480 481 482
	int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
	int (*dump)(struct sk_buff *, struct netlink_callback *);
	int (*done)(struct netlink_callback *);
} crypto_dispatch[CRYPTO_NR_MSGTYPES] = {
	[CRYPTO_MSG_NEWALG	- CRYPTO_MSG_BASE] = { .doit = crypto_add_alg},
	[CRYPTO_MSG_DELALG	- CRYPTO_MSG_BASE] = { .doit = crypto_del_alg},
	[CRYPTO_MSG_UPDATEALG	- CRYPTO_MSG_BASE] = { .doit = crypto_update_alg},
	[CRYPTO_MSG_GETALG	- CRYPTO_MSG_BASE] = { .doit = crypto_report,
						       .dump = crypto_dump_report,
						       .done = crypto_dump_report_done},
483
	[CRYPTO_MSG_DELRNG	- CRYPTO_MSG_BASE] = { .doit = crypto_del_rng },
484 485 486 487 488
};

static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
	struct nlattr *attrs[CRYPTOCFGA_MAX+1];
489
	const struct crypto_link *link;
490 491 492 493 494 495 496 497 498 499 500
	int type, err;

	type = nlh->nlmsg_type;
	if (type > CRYPTO_MSG_MAX)
		return -EINVAL;

	type -= CRYPTO_MSG_BASE;
	link = &crypto_dispatch[type];

	if ((type == (CRYPTO_MSG_GETALG - CRYPTO_MSG_BASE) &&
	    (nlh->nlmsg_flags & NLM_F_DUMP))) {
501 502 503
		struct crypto_alg *alg;
		u16 dump_alloc = 0;

504 505
		if (link->dump == NULL)
			return -EINVAL;
506

507
		down_read(&crypto_alg_sem);
508 509 510
		list_for_each_entry(alg, &crypto_alg_list, cra_list)
			dump_alloc += CRYPTO_REPORT_MAXSIZE;

511 512 513 514
		{
			struct netlink_dump_control c = {
				.dump = link->dump,
				.done = link->done,
515
				.min_dump_alloc = dump_alloc,
516
			};
517
			err = netlink_dump_start(crypto_nlsk, skb, nlh, &c);
518
		}
519 520 521
		up_read(&crypto_alg_sem);

		return err;
522 523
	}

524 525 526 527
	err = nlmsg_parse(nlh, crypto_msg_min[type], attrs, CRYPTOCFGA_MAX,
			  crypto_policy);
	if (err < 0)
		return err;
528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543

	if (link->doit == NULL)
		return -EINVAL;

	return link->doit(skb, nlh, attrs);
}

static void crypto_netlink_rcv(struct sk_buff *skb)
{
	mutex_lock(&crypto_cfg_mutex);
	netlink_rcv_skb(skb, &crypto_user_rcv_msg);
	mutex_unlock(&crypto_cfg_mutex);
}

static int __init crypto_user_init(void)
{
544 545 546 547
	struct netlink_kernel_cfg cfg = {
		.input	= crypto_netlink_rcv,
	};

548
	crypto_nlsk = netlink_kernel_create(&init_net, NETLINK_CRYPTO, &cfg);
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
	if (!crypto_nlsk)
		return -ENOMEM;

	return 0;
}

static void __exit crypto_user_exit(void)
{
	netlink_kernel_release(crypto_nlsk);
}

module_init(crypto_user_init);
module_exit(crypto_user_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>");
MODULE_DESCRIPTION("Crypto userspace configuration API");
S
Stephan Mueller 已提交
565
MODULE_ALIAS("net-pf-16-proto-21");