api.c 13.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5
/*
 * Scatterlist Cryptographic API.
 *
 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
 * Copyright (c) 2002 David S. Miller (davem@redhat.com)
6
 * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
L
Linus Torvalds 已提交
7 8
 *
 * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no>
9
 * and Nettle, by Niels Möller.
L
Linus Torvalds 已提交
10 11 12 13 14 15 16
 *
 * 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.
 *
 */
17

H
Herbert Xu 已提交
18
#include <linux/err.h>
L
Linus Torvalds 已提交
19
#include <linux/errno.h>
20
#include <linux/kernel.h>
21
#include <linux/kmod.h>
H
Herbert Xu 已提交
22
#include <linux/module.h>
23
#include <linux/param.h>
H
Herbert Xu 已提交
24
#include <linux/sched.h>
L
Linus Torvalds 已提交
25
#include <linux/slab.h>
26
#include <linux/string.h>
L
Linus Torvalds 已提交
27 28 29
#include "internal.h"

LIST_HEAD(crypto_alg_list);
30
EXPORT_SYMBOL_GPL(crypto_alg_list);
L
Linus Torvalds 已提交
31
DECLARE_RWSEM(crypto_alg_sem);
32
EXPORT_SYMBOL_GPL(crypto_alg_sem);
L
Linus Torvalds 已提交
33

34 35 36
BLOCKING_NOTIFIER_HEAD(crypto_chain);
EXPORT_SYMBOL_GPL(crypto_chain);

37
static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg)
L
Linus Torvalds 已提交
38
{
39 40 41 42
	atomic_inc(&alg->cra_refcnt);
	return alg;
}

43
struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
44 45
{
	return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL;
L
Linus Torvalds 已提交
46
}
47
EXPORT_SYMBOL_GPL(crypto_mod_get);
L
Linus Torvalds 已提交
48

49
void crypto_mod_put(struct crypto_alg *alg)
L
Linus Torvalds 已提交
50
{
51 52
	struct module *module = alg->cra_module;

53
	crypto_alg_put(alg);
54
	module_put(module);
L
Linus Torvalds 已提交
55
}
56
EXPORT_SYMBOL_GPL(crypto_mod_put);
L
Linus Torvalds 已提交
57

58 59 60 61 62
static inline int crypto_is_test_larval(struct crypto_larval *larval)
{
	return larval->alg.cra_driver_name[0];
}

63 64
static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type,
					      u32 mask)
L
Linus Torvalds 已提交
65 66
{
	struct crypto_alg *q, *alg = NULL;
67
	int best = -2;
L
Linus Torvalds 已提交
68 69

	list_for_each_entry(q, &crypto_alg_list, cra_list) {
70 71
		int exact, fuzzy;

H
Herbert Xu 已提交
72 73 74
		if (crypto_is_moribund(q))
			continue;

75 76 77 78
		if ((q->cra_flags ^ type) & mask)
			continue;

		if (crypto_is_larval(q) &&
79
		    !crypto_is_test_larval((struct crypto_larval *)q) &&
80 81 82
		    ((struct crypto_larval *)q)->mask != mask)
			continue;

83 84 85 86 87
		exact = !strcmp(q->cra_driver_name, name);
		fuzzy = !strcmp(q->cra_name, name);
		if (!exact && !(fuzzy && q->cra_priority > best))
			continue;

88
		if (unlikely(!crypto_mod_get(q)))
89 90 91 92
			continue;

		best = q->cra_priority;
		if (alg)
93
			crypto_mod_put(alg);
94 95 96
		alg = q;

		if (exact)
L
Linus Torvalds 已提交
97 98
			break;
	}
99 100 101 102 103 104 105 106 107 108 109 110 111 112

	return alg;
}

static void crypto_larval_destroy(struct crypto_alg *alg)
{
	struct crypto_larval *larval = (void *)alg;

	BUG_ON(!crypto_is_larval(alg));
	if (larval->adult)
		crypto_mod_put(larval->adult);
	kfree(larval);
}

113
struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask)
114 115 116 117 118
{
	struct crypto_larval *larval;

	larval = kzalloc(sizeof(*larval), GFP_KERNEL);
	if (!larval)
H
Herbert Xu 已提交
119
		return ERR_PTR(-ENOMEM);
120

121 122
	larval->mask = mask;
	larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type;
123 124 125 126 127 128
	larval->alg.cra_priority = -1;
	larval->alg.cra_destroy = crypto_larval_destroy;

	strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME);
	init_completion(&larval->completion);

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
	return larval;
}
EXPORT_SYMBOL_GPL(crypto_larval_alloc);

static struct crypto_alg *crypto_larval_add(const char *name, u32 type,
					    u32 mask)
{
	struct crypto_alg *alg;
	struct crypto_larval *larval;

	larval = crypto_larval_alloc(name, type, mask);
	if (IS_ERR(larval))
		return ERR_CAST(larval);

	atomic_set(&larval->alg.cra_refcnt, 2);

145
	down_write(&crypto_alg_sem);
146
	alg = __crypto_alg_lookup(name, type, mask);
147 148 149 150 151 152 153 154 155 156 157 158
	if (!alg) {
		alg = &larval->alg;
		list_add(&alg->cra_list, &crypto_alg_list);
	}
	up_write(&crypto_alg_sem);

	if (alg != &larval->alg)
		kfree(larval);

	return alg;
}

159
void crypto_larval_kill(struct crypto_alg *alg)
160 161 162 163 164 165
{
	struct crypto_larval *larval = (void *)alg;

	down_write(&crypto_alg_sem);
	list_del(&alg->cra_list);
	up_write(&crypto_alg_sem);
166
	complete_all(&larval->completion);
167 168
	crypto_alg_put(alg);
}
169
EXPORT_SYMBOL_GPL(crypto_larval_kill);
170 171 172 173

static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
{
	struct crypto_larval *larval = (void *)alg;
174 175 176 177
	long timeout;

	timeout = wait_for_completion_interruptible_timeout(
		&larval->completion, 60 * HZ);
178 179

	alg = larval->adult;
180 181 182 183 184
	if (timeout < 0)
		alg = ERR_PTR(-EINTR);
	else if (!timeout)
		alg = ERR_PTR(-ETIMEDOUT);
	else if (!alg)
H
Herbert Xu 已提交
185
		alg = ERR_PTR(-ENOENT);
186 187 188 189 190
	else if (crypto_is_test_larval(larval) &&
		 !(alg->cra_flags & CRYPTO_ALG_TESTED))
		alg = ERR_PTR(-EAGAIN);
	else if (!crypto_mod_get(alg))
		alg = ERR_PTR(-EAGAIN);
191 192 193 194 195
	crypto_mod_put(&larval->alg);

	return alg;
}

196
struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, u32 mask)
197 198 199 200
{
	struct crypto_alg *alg;

	down_read(&crypto_alg_sem);
201
	alg = __crypto_alg_lookup(name, type, mask);
L
Linus Torvalds 已提交
202
	up_read(&crypto_alg_sem);
203

L
Linus Torvalds 已提交
204 205
	return alg;
}
206
EXPORT_SYMBOL_GPL(crypto_alg_lookup);
L
Linus Torvalds 已提交
207

208
struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask)
209
{
210 211
	struct crypto_alg *alg;

H
Herbert Xu 已提交
212 213 214 215
	if (!name)
		return ERR_PTR(-ENOENT);

	mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD);
216 217 218 219
	type &= mask;

	alg = try_then_request_module(crypto_alg_lookup(name, type, mask),
				      name);
220 221 222
	if (alg)
		return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg;

223
	return crypto_larval_add(name, type, mask);
224 225 226
}
EXPORT_SYMBOL_GPL(crypto_larval_lookup);

227 228 229 230 231 232 233 234 235 236 237 238 239 240
int crypto_probing_notify(unsigned long val, void *v)
{
	int ok;

	ok = blocking_notifier_call_chain(&crypto_chain, val, v);
	if (ok == NOTIFY_DONE) {
		request_module("cryptomgr");
		ok = blocking_notifier_call_chain(&crypto_chain, val, v);
	}

	return ok;
}
EXPORT_SYMBOL_GPL(crypto_probing_notify);

241 242 243 244 245 246
struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
{
	struct crypto_alg *alg;
	struct crypto_alg *larval;
	int ok;

247
	if (!((type | mask) & CRYPTO_ALG_TESTED)) {
248 249 250 251
		type |= CRYPTO_ALG_TESTED;
		mask |= CRYPTO_ALG_TESTED;
	}

252
	larval = crypto_larval_lookup(name, type, mask);
H
Herbert Xu 已提交
253
	if (IS_ERR(larval) || !crypto_is_larval(larval))
254 255
		return larval;

256
	ok = crypto_probing_notify(CRYPTO_MSG_ALG_REQUEST, larval);
H
Herbert Xu 已提交
257 258

	if (ok == NOTIFY_STOP)
259 260 261
		alg = crypto_larval_wait(larval);
	else {
		crypto_mod_put(larval);
H
Herbert Xu 已提交
262
		alg = ERR_PTR(-ENOENT);
263 264 265
	}
	crypto_larval_kill(larval);
	return alg;
266
}
267
EXPORT_SYMBOL_GPL(crypto_alg_mod_lookup);
268

269
static int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
L
Linus Torvalds 已提交
270
{
271
	const struct crypto_type *type_obj = tfm->__crt_alg->cra_type;
272

273 274
	if (type_obj)
		return type_obj->init(tfm, type, mask);
275

L
Linus Torvalds 已提交
276 277 278 279 280
	switch (crypto_tfm_alg_type(tfm)) {
	case CRYPTO_ALG_TYPE_CIPHER:
		return crypto_init_cipher_ops(tfm);
		
	case CRYPTO_ALG_TYPE_DIGEST:
281 282 283 284 285 286
		if ((mask & CRYPTO_ALG_TYPE_HASH_MASK) !=
		    CRYPTO_ALG_TYPE_HASH_MASK)
			return crypto_init_digest_ops_async(tfm);
		else
			return crypto_init_digest_ops(tfm);

L
Linus Torvalds 已提交
287 288 289 290 291 292 293 294 295 296 297 298 299
	case CRYPTO_ALG_TYPE_COMPRESS:
		return crypto_init_compress_ops(tfm);
	
	default:
		break;
	}
	
	BUG();
	return -EINVAL;
}

static void crypto_exit_ops(struct crypto_tfm *tfm)
{
300 301 302
	const struct crypto_type *type = tfm->__crt_alg->cra_type;

	if (type) {
303 304
		if (tfm->exit)
			tfm->exit(tfm);
305 306 307
		return;
	}

L
Linus Torvalds 已提交
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
	switch (crypto_tfm_alg_type(tfm)) {
	case CRYPTO_ALG_TYPE_CIPHER:
		crypto_exit_cipher_ops(tfm);
		break;
		
	case CRYPTO_ALG_TYPE_DIGEST:
		crypto_exit_digest_ops(tfm);
		break;
		
	case CRYPTO_ALG_TYPE_COMPRESS:
		crypto_exit_compress_ops(tfm);
		break;
	
	default:
		BUG();
		
	}
}

327
static unsigned int crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask)
328
{
329
	const struct crypto_type *type_obj = alg->cra_type;
330 331
	unsigned int len;

332
	len = alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1);
333 334
	if (type_obj)
		return len + type_obj->ctxsize(alg, type, mask);
335

336 337 338 339 340
	switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
	default:
		BUG();

	case CRYPTO_ALG_TYPE_CIPHER:
341
		len += crypto_cipher_ctxsize(alg);
342 343 344
		break;
		
	case CRYPTO_ALG_TYPE_DIGEST:
345
		len += crypto_digest_ctxsize(alg);
346 347 348
		break;
		
	case CRYPTO_ALG_TYPE_COMPRESS:
349
		len += crypto_compress_ctxsize(alg);
350 351 352
		break;
	}

353
	return len;
354 355
}

H
Herbert Xu 已提交
356 357 358 359 360 361 362 363
void crypto_shoot_alg(struct crypto_alg *alg)
{
	down_write(&crypto_alg_sem);
	alg->cra_flags |= CRYPTO_ALG_DYING;
	up_write(&crypto_alg_sem);
}
EXPORT_SYMBOL_GPL(crypto_shoot_alg);

364 365
struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
				      u32 mask)
L
Linus Torvalds 已提交
366 367
{
	struct crypto_tfm *tfm = NULL;
368
	unsigned int tfm_size;
H
Herbert Xu 已提交
369
	int err = -ENOMEM;
370

371
	tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, type, mask);
372
	tfm = kzalloc(tfm_size, GFP_KERNEL);
L
Linus Torvalds 已提交
373
	if (tfm == NULL)
374
		goto out_err;
L
Linus Torvalds 已提交
375 376

	tfm->__crt_alg = alg;
H
Herbert Xu 已提交
377

378
	err = crypto_init_ops(tfm, type, mask);
H
Herbert Xu 已提交
379
	if (err)
L
Linus Torvalds 已提交
380
		goto out_free_tfm;
381

382
	if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm)))
383
		goto cra_init_failed;
L
Linus Torvalds 已提交
384 385 386

	goto out;

387 388
cra_init_failed:
	crypto_exit_ops(tfm);
L
Linus Torvalds 已提交
389
out_free_tfm:
390 391
	if (err == -EAGAIN)
		crypto_shoot_alg(alg);
L
Linus Torvalds 已提交
392
	kfree(tfm);
393
out_err:
H
Herbert Xu 已提交
394
	tfm = ERR_PTR(err);
L
Linus Torvalds 已提交
395 396 397
out:
	return tfm;
}
H
Herbert Xu 已提交
398 399
EXPORT_SYMBOL_GPL(__crypto_alloc_tfm);

400 401 402 403 404 405
/*
 *	crypto_alloc_base - Locate algorithm and allocate transform
 *	@alg_name: Name of algorithm
 *	@type: Type of algorithm
 *	@mask: Mask for type comparison
 *
406 407 408
 *	This function should not be used by new algorithm types.
 *	Plesae use crypto_alloc_tfm instead.
 *
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
 *	crypto_alloc_base() will first attempt to locate an already loaded
 *	algorithm.  If that fails and the kernel supports dynamically loadable
 *	modules, it will then attempt to load a module of the same name or
 *	alias.  If that fails it will send a query to any loaded crypto manager
 *	to construct an algorithm on the fly.  A refcount is grabbed on the
 *	algorithm which is then associated with the new transform.
 *
 *	The returned transform is of a non-determinate type.  Most people
 *	should use one of the more specific allocation functions such as
 *	crypto_alloc_blkcipher.
 *
 *	In case of error the return value is an error pointer.
 */
struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask)
{
	struct crypto_tfm *tfm;
	int err;

	for (;;) {
		struct crypto_alg *alg;

		alg = crypto_alg_mod_lookup(alg_name, type, mask);
431 432
		if (IS_ERR(alg)) {
			err = PTR_ERR(alg);
433
			goto err;
434
		}
435

436
		tfm = __crypto_alloc_tfm(alg, type, mask);
437
		if (!IS_ERR(tfm))
438
			return tfm;
439 440 441 442 443 444 445 446 447 448 449

		crypto_mod_put(alg);
		err = PTR_ERR(tfm);

err:
		if (err != -EAGAIN)
			break;
		if (signal_pending(current)) {
			err = -EINTR;
			break;
		}
450
	}
451

452
	return ERR_PTR(err);
453 454
}
EXPORT_SYMBOL_GPL(crypto_alloc_base);
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559

struct crypto_tfm *crypto_create_tfm(struct crypto_alg *alg,
				     const struct crypto_type *frontend)
{
	char *mem;
	struct crypto_tfm *tfm = NULL;
	unsigned int tfmsize;
	unsigned int total;
	int err = -ENOMEM;

	tfmsize = frontend->tfmsize;
	total = tfmsize + sizeof(*tfm) + frontend->extsize(alg, frontend);

	mem = kzalloc(total, GFP_KERNEL);
	if (mem == NULL)
		goto out_err;

	tfm = (struct crypto_tfm *)(mem + tfmsize);
	tfm->__crt_alg = alg;

	err = frontend->init_tfm(tfm, frontend);
	if (err)
		goto out_free_tfm;

	if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm)))
		goto cra_init_failed;

	goto out;

cra_init_failed:
	crypto_exit_ops(tfm);
out_free_tfm:
	if (err == -EAGAIN)
		crypto_shoot_alg(alg);
	kfree(mem);
out_err:
	tfm = ERR_PTR(err);
out:
	return tfm;
}
EXPORT_SYMBOL_GPL(crypto_create_tfm);

/*
 *	crypto_alloc_tfm - Locate algorithm and allocate transform
 *	@alg_name: Name of algorithm
 *	@frontend: Frontend algorithm type
 *	@type: Type of algorithm
 *	@mask: Mask for type comparison
 *
 *	crypto_alloc_tfm() will first attempt to locate an already loaded
 *	algorithm.  If that fails and the kernel supports dynamically loadable
 *	modules, it will then attempt to load a module of the same name or
 *	alias.  If that fails it will send a query to any loaded crypto manager
 *	to construct an algorithm on the fly.  A refcount is grabbed on the
 *	algorithm which is then associated with the new transform.
 *
 *	The returned transform is of a non-determinate type.  Most people
 *	should use one of the more specific allocation functions such as
 *	crypto_alloc_blkcipher.
 *
 *	In case of error the return value is an error pointer.
 */
struct crypto_tfm *crypto_alloc_tfm(const char *alg_name,
				    const struct crypto_type *frontend,
				    u32 type, u32 mask)
{
	struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask);
	struct crypto_tfm *tfm;
	int err;

	type &= frontend->maskclear;
	mask &= frontend->maskclear;
	type |= frontend->type;
	mask |= frontend->maskset;

	lookup = frontend->lookup ?: crypto_alg_mod_lookup;

	for (;;) {
		struct crypto_alg *alg;

		alg = lookup(alg_name, type, mask);
		if (IS_ERR(alg)) {
			err = PTR_ERR(alg);
			goto err;
		}

		tfm = crypto_create_tfm(alg, frontend);
		if (!IS_ERR(tfm))
			return tfm;

		crypto_mod_put(alg);
		err = PTR_ERR(tfm);

err:
		if (err != -EAGAIN)
			break;
		if (signal_pending(current)) {
			err = -EINTR;
			break;
		}
	}

	return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(crypto_alloc_tfm);
H
Herbert Xu 已提交
560

561
/*
H
Herbert Xu 已提交
562 563
 *	crypto_destroy_tfm - Free crypto transform
 *	@mem: Start of tfm slab
564 565
 *	@tfm: Transform to free
 *
H
Herbert Xu 已提交
566
 *	This function frees up the transform and any associated resources,
567 568
 *	then drops the refcount on the associated algorithm.
 */
H
Herbert Xu 已提交
569
void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm)
L
Linus Torvalds 已提交
570
{
571 572 573
	struct crypto_alg *alg;
	int size;

H
Herbert Xu 已提交
574
	if (unlikely(!mem))
575 576 577
		return;

	alg = tfm->__crt_alg;
H
Herbert Xu 已提交
578
	size = ksize(mem);
L
Linus Torvalds 已提交
579

580
	if (!tfm->exit && alg->cra_exit)
581
		alg->cra_exit(tfm);
L
Linus Torvalds 已提交
582
	crypto_exit_ops(tfm);
583
	crypto_mod_put(alg);
H
Herbert Xu 已提交
584 585
	memset(mem, 0, size);
	kfree(mem);
L
Linus Torvalds 已提交
586
}
H
Herbert Xu 已提交
587
EXPORT_SYMBOL_GPL(crypto_destroy_tfm);
588 589 590 591 592 593 594 595 596 597 598 599 600 601

int crypto_has_alg(const char *name, u32 type, u32 mask)
{
	int ret = 0;
	struct crypto_alg *alg = crypto_alg_mod_lookup(name, type, mask);
	
	if (!IS_ERR(alg)) {
		crypto_mod_put(alg);
		ret = 1;
	}
	
	return ret;
}
EXPORT_SYMBOL_GPL(crypto_has_alg);
602 603 604

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