Blame view

crypto/api.c 13.5 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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)
5cb1454b8   Herbert Xu   [CRYPTO] Allow mu...
6
   * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
   *
   * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no>
991d17403   John Anthony Kazos Jr   crypto: convert "...
9
   * and Nettle, by Niels Möller.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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.
   *
   */
a61cc4481   Jesper Juhl   [CRYPTO] Add null...
17

6bfd48096   Herbert Xu   [CRYPTO] api: Add...
18
  #include <linux/err.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  #include <linux/errno.h>
5cb1454b8   Herbert Xu   [CRYPTO] Allow mu...
20
  #include <linux/kernel.h>
176c3652c   Adrian Bunk   [CRYPTO] Make cry...
21
  #include <linux/kmod.h>
2b8c19dbd   Herbert Xu   [CRYPTO] api: Add...
22
  #include <linux/module.h>
2825982d9   Herbert Xu   [CRYPTO] api: Add...
23
  #include <linux/param.h>
6bfd48096   Herbert Xu   [CRYPTO] api: Add...
24
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include <linux/slab.h>
5cb1454b8   Herbert Xu   [CRYPTO] Allow mu...
26
  #include <linux/string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
  #include "internal.h"
  
  LIST_HEAD(crypto_alg_list);
cce9e06d1   Herbert Xu   [CRYPTO] api: Spl...
30
  EXPORT_SYMBOL_GPL(crypto_alg_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  DECLARE_RWSEM(crypto_alg_sem);
cce9e06d1   Herbert Xu   [CRYPTO] api: Spl...
32
  EXPORT_SYMBOL_GPL(crypto_alg_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33

2825982d9   Herbert Xu   [CRYPTO] api: Add...
34
35
  BLOCKING_NOTIFIER_HEAD(crypto_chain);
  EXPORT_SYMBOL_GPL(crypto_chain);
6521f3027   Herbert Xu   [CRYPTO] api: Add...
36
  static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  {
6521f3027   Herbert Xu   [CRYPTO] api: Add...
38
39
40
  	atomic_inc(&alg->cra_refcnt);
  	return alg;
  }
2825982d9   Herbert Xu   [CRYPTO] api: Add...
41
  struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
6521f3027   Herbert Xu   [CRYPTO] api: Add...
42
43
  {
  	return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  }
2825982d9   Herbert Xu   [CRYPTO] api: Add...
45
  EXPORT_SYMBOL_GPL(crypto_mod_get);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46

2825982d9   Herbert Xu   [CRYPTO] api: Add...
47
  void crypto_mod_put(struct crypto_alg *alg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  {
da7cd59ab   Herbert Xu   [CRYPTO] api: Rea...
49
  	struct module *module = alg->cra_module;
6521f3027   Herbert Xu   [CRYPTO] api: Add...
50
  	crypto_alg_put(alg);
da7cd59ab   Herbert Xu   [CRYPTO] api: Rea...
51
  	module_put(module);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  }
2825982d9   Herbert Xu   [CRYPTO] api: Add...
53
  EXPORT_SYMBOL_GPL(crypto_mod_put);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

73d3864a4   Herbert Xu   crypto: api - Use...
55
56
57
58
  static inline int crypto_is_test_larval(struct crypto_larval *larval)
  {
  	return larval->alg.cra_driver_name[0];
  }
c51b6c810   Herbert Xu   crypto: api - Exp...
59
60
  static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type,
  					      u32 mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
  {
  	struct crypto_alg *q, *alg = NULL;
2825982d9   Herbert Xu   [CRYPTO] api: Add...
63
  	int best = -2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  	list_for_each_entry(q, &crypto_alg_list, cra_list) {
5cb1454b8   Herbert Xu   [CRYPTO] Allow mu...
66
  		int exact, fuzzy;
6bfd48096   Herbert Xu   [CRYPTO] api: Add...
67
68
  		if (crypto_is_moribund(q))
  			continue;
492e2b63e   Herbert Xu   [CRYPTO] api: All...
69
70
71
72
  		if ((q->cra_flags ^ type) & mask)
  			continue;
  
  		if (crypto_is_larval(q) &&
73d3864a4   Herbert Xu   crypto: api - Use...
73
  		    !crypto_is_test_larval((struct crypto_larval *)q) &&
492e2b63e   Herbert Xu   [CRYPTO] api: All...
74
75
  		    ((struct crypto_larval *)q)->mask != mask)
  			continue;
5cb1454b8   Herbert Xu   [CRYPTO] Allow mu...
76
77
78
79
  		exact = !strcmp(q->cra_driver_name, name);
  		fuzzy = !strcmp(q->cra_name, name);
  		if (!exact && !(fuzzy && q->cra_priority > best))
  			continue;
72fa49191   Herbert Xu   [CRYPTO] api: Ren...
80
  		if (unlikely(!crypto_mod_get(q)))
5cb1454b8   Herbert Xu   [CRYPTO] Allow mu...
81
82
83
84
  			continue;
  
  		best = q->cra_priority;
  		if (alg)
72fa49191   Herbert Xu   [CRYPTO] api: Ren...
85
  			crypto_mod_put(alg);
5cb1454b8   Herbert Xu   [CRYPTO] Allow mu...
86
87
88
  		alg = q;
  
  		if (exact)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  	}
2825982d9   Herbert Xu   [CRYPTO] api: Add...
91
92
93
  
  	return alg;
  }
2825982d9   Herbert Xu   [CRYPTO] api: Add...
94
95
96
97
98
99
100
101
102
103
  
  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);
  }
73d3864a4   Herbert Xu   crypto: api - Use...
104
  struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask)
2825982d9   Herbert Xu   [CRYPTO] api: Add...
105
  {
2825982d9   Herbert Xu   [CRYPTO] api: Add...
106
107
108
109
  	struct crypto_larval *larval;
  
  	larval = kzalloc(sizeof(*larval), GFP_KERNEL);
  	if (!larval)
6bfd48096   Herbert Xu   [CRYPTO] api: Add...
110
  		return ERR_PTR(-ENOMEM);
2825982d9   Herbert Xu   [CRYPTO] api: Add...
111

492e2b63e   Herbert Xu   [CRYPTO] api: All...
112
113
  	larval->mask = mask;
  	larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type;
2825982d9   Herbert Xu   [CRYPTO] api: Add...
114
115
  	larval->alg.cra_priority = -1;
  	larval->alg.cra_destroy = crypto_larval_destroy;
2825982d9   Herbert Xu   [CRYPTO] api: Add...
116
117
  	strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME);
  	init_completion(&larval->completion);
73d3864a4   Herbert Xu   crypto: api - Use...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  	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);
2825982d9   Herbert Xu   [CRYPTO] api: Add...
133
  	down_write(&crypto_alg_sem);
492e2b63e   Herbert Xu   [CRYPTO] api: All...
134
  	alg = __crypto_alg_lookup(name, type, mask);
2825982d9   Herbert Xu   [CRYPTO] api: Add...
135
136
137
138
139
140
141
142
143
144
145
  	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;
  }
b9c55aa47   Herbert Xu   [CRYPTO] skcipher...
146
  void crypto_larval_kill(struct crypto_alg *alg)
2825982d9   Herbert Xu   [CRYPTO] api: Add...
147
148
149
150
151
152
  {
  	struct crypto_larval *larval = (void *)alg;
  
  	down_write(&crypto_alg_sem);
  	list_del(&alg->cra_list);
  	up_write(&crypto_alg_sem);
fe3c5206a   Herbert Xu   [CRYPTO] api: Wak...
153
  	complete_all(&larval->completion);
2825982d9   Herbert Xu   [CRYPTO] api: Add...
154
155
  	crypto_alg_put(alg);
  }
b9c55aa47   Herbert Xu   [CRYPTO] skcipher...
156
  EXPORT_SYMBOL_GPL(crypto_larval_kill);
2825982d9   Herbert Xu   [CRYPTO] api: Add...
157
158
159
160
  
  static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
  {
  	struct crypto_larval *larval = (void *)alg;
73d3864a4   Herbert Xu   crypto: api - Use...
161
162
163
164
  	long timeout;
  
  	timeout = wait_for_completion_interruptible_timeout(
  		&larval->completion, 60 * HZ);
2825982d9   Herbert Xu   [CRYPTO] api: Add...
165

2825982d9   Herbert Xu   [CRYPTO] api: Add...
166
  	alg = larval->adult;
73d3864a4   Herbert Xu   crypto: api - Use...
167
168
169
170
171
  	if (timeout < 0)
  		alg = ERR_PTR(-EINTR);
  	else if (!timeout)
  		alg = ERR_PTR(-ETIMEDOUT);
  	else if (!alg)
6bfd48096   Herbert Xu   [CRYPTO] api: Add...
172
  		alg = ERR_PTR(-ENOENT);
73d3864a4   Herbert Xu   crypto: api - Use...
173
174
175
176
177
  	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);
2825982d9   Herbert Xu   [CRYPTO] api: Add...
178
179
180
181
  	crypto_mod_put(&larval->alg);
  
  	return alg;
  }
c51b6c810   Herbert Xu   crypto: api - Exp...
182
  struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, u32 mask)
2825982d9   Herbert Xu   [CRYPTO] api: Add...
183
184
  {
  	struct crypto_alg *alg;
2825982d9   Herbert Xu   [CRYPTO] api: Add...
185
  	down_read(&crypto_alg_sem);
492e2b63e   Herbert Xu   [CRYPTO] api: All...
186
  	alg = __crypto_alg_lookup(name, type, mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  	up_read(&crypto_alg_sem);
2825982d9   Herbert Xu   [CRYPTO] api: Add...
188

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
  	return alg;
  }
c51b6c810   Herbert Xu   crypto: api - Exp...
191
  EXPORT_SYMBOL_GPL(crypto_alg_lookup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192

b9c55aa47   Herbert Xu   [CRYPTO] skcipher...
193
  struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask)
176c3652c   Adrian Bunk   [CRYPTO] Make cry...
194
  {
2825982d9   Herbert Xu   [CRYPTO] api: Add...
195
  	struct crypto_alg *alg;
2825982d9   Herbert Xu   [CRYPTO] api: Add...
196

6bfd48096   Herbert Xu   [CRYPTO] api: Add...
197
198
199
200
  	if (!name)
  		return ERR_PTR(-ENOENT);
  
  	mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD);
492e2b63e   Herbert Xu   [CRYPTO] api: All...
201
  	type &= mask;
a760a6656   Herbert Xu   crypto: api - Fix...
202
203
  	alg = crypto_alg_lookup(name, type, mask);
  	if (!alg) {
aa07a6990   Alex Riesen   crypto: api - Use...
204
  		request_module("%s", name);
a760a6656   Herbert Xu   crypto: api - Fix...
205

37fc334cc   Herbert Xu   crypto: api - Fix...
206
  		if (!((type ^ CRYPTO_ALG_NEED_FALLBACK) & mask &
aa07a6990   Alex Riesen   crypto: api - Use...
207
208
  		      CRYPTO_ALG_NEED_FALLBACK))
  			request_module("%s-all", name);
a760a6656   Herbert Xu   crypto: api - Fix...
209
210
211
  
  		alg = crypto_alg_lookup(name, type, mask);
  	}
2825982d9   Herbert Xu   [CRYPTO] api: Add...
212
213
  	if (alg)
  		return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg;
73d3864a4   Herbert Xu   crypto: api - Use...
214
  	return crypto_larval_add(name, type, mask);
b9c55aa47   Herbert Xu   [CRYPTO] skcipher...
215
216
  }
  EXPORT_SYMBOL_GPL(crypto_larval_lookup);
73d3864a4   Herbert Xu   crypto: api - Use...
217
218
219
220
221
222
223
224
225
226
227
228
229
  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);
b9c55aa47   Herbert Xu   [CRYPTO] skcipher...
230
231
232
233
234
  struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
  {
  	struct crypto_alg *alg;
  	struct crypto_alg *larval;
  	int ok;
ff753308d   Herbert Xu   crypto: api - cry...
235
  	if (!((type | mask) & CRYPTO_ALG_TESTED)) {
73d3864a4   Herbert Xu   crypto: api - Use...
236
237
238
  		type |= CRYPTO_ALG_TESTED;
  		mask |= CRYPTO_ALG_TESTED;
  	}
b9c55aa47   Herbert Xu   [CRYPTO] skcipher...
239
  	larval = crypto_larval_lookup(name, type, mask);
6bfd48096   Herbert Xu   [CRYPTO] api: Add...
240
  	if (IS_ERR(larval) || !crypto_is_larval(larval))
2825982d9   Herbert Xu   [CRYPTO] api: Add...
241
  		return larval;
73d3864a4   Herbert Xu   crypto: api - Use...
242
  	ok = crypto_probing_notify(CRYPTO_MSG_ALG_REQUEST, larval);
2b8c19dbd   Herbert Xu   [CRYPTO] api: Add...
243
244
  
  	if (ok == NOTIFY_STOP)
2825982d9   Herbert Xu   [CRYPTO] api: Add...
245
246
247
  		alg = crypto_larval_wait(larval);
  	else {
  		crypto_mod_put(larval);
6bfd48096   Herbert Xu   [CRYPTO] api: Add...
248
  		alg = ERR_PTR(-ENOENT);
2825982d9   Herbert Xu   [CRYPTO] api: Add...
249
250
251
  	}
  	crypto_larval_kill(larval);
  	return alg;
176c3652c   Adrian Bunk   [CRYPTO] Make cry...
252
  }
492e2b63e   Herbert Xu   [CRYPTO] api: All...
253
  EXPORT_SYMBOL_GPL(crypto_alg_mod_lookup);
176c3652c   Adrian Bunk   [CRYPTO] Make cry...
254

27d2a3300   Herbert Xu   [CRYPTO] api: All...
255
  static int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
  {
27d2a3300   Herbert Xu   [CRYPTO] api: All...
257
  	const struct crypto_type *type_obj = tfm->__crt_alg->cra_type;
e853c3cfa   Herbert Xu   [CRYPTO] api: Add...
258

27d2a3300   Herbert Xu   [CRYPTO] api: All...
259
260
  	if (type_obj)
  		return type_obj->init(tfm, type, mask);
e853c3cfa   Herbert Xu   [CRYPTO] api: Add...
261

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
265
266
  	switch (crypto_tfm_alg_type(tfm)) {
  	case CRYPTO_ALG_TYPE_CIPHER:
  		return crypto_init_cipher_ops(tfm);
  		
  	case CRYPTO_ALG_TYPE_DIGEST:
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
267
268
269
270
271
  		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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
275
276
277
278
279
280
281
282
283
284
  	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)
  {
e853c3cfa   Herbert Xu   [CRYPTO] api: Add...
285
286
287
  	const struct crypto_type *type = tfm->__crt_alg->cra_type;
  
  	if (type) {
4a7794860   Herbert Xu   crypto: api - Mov...
288
289
  		if (tfm->exit)
  			tfm->exit(tfm);
e853c3cfa   Herbert Xu   [CRYPTO] api: Add...
290
291
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
  	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();
  		
  	}
  }
27d2a3300   Herbert Xu   [CRYPTO] api: All...
310
  static unsigned int crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask)
fbdae9f3e   Herbert Xu   [CRYPTO] Ensure c...
311
  {
27d2a3300   Herbert Xu   [CRYPTO] api: All...
312
  	const struct crypto_type *type_obj = alg->cra_type;
fbdae9f3e   Herbert Xu   [CRYPTO] Ensure c...
313
  	unsigned int len;
e853c3cfa   Herbert Xu   [CRYPTO] api: Add...
314
  	len = alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1);
27d2a3300   Herbert Xu   [CRYPTO] api: All...
315
316
  	if (type_obj)
  		return len + type_obj->ctxsize(alg, type, mask);
e853c3cfa   Herbert Xu   [CRYPTO] api: Add...
317

fbdae9f3e   Herbert Xu   [CRYPTO] Ensure c...
318
319
320
321
322
  	switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
  	default:
  		BUG();
  
  	case CRYPTO_ALG_TYPE_CIPHER:
f1ddcaf33   Herbert Xu   [CRYPTO] api: Rem...
323
  		len += crypto_cipher_ctxsize(alg);
fbdae9f3e   Herbert Xu   [CRYPTO] Ensure c...
324
325
326
  		break;
  		
  	case CRYPTO_ALG_TYPE_DIGEST:
f1ddcaf33   Herbert Xu   [CRYPTO] api: Rem...
327
  		len += crypto_digest_ctxsize(alg);
fbdae9f3e   Herbert Xu   [CRYPTO] Ensure c...
328
329
330
  		break;
  		
  	case CRYPTO_ALG_TYPE_COMPRESS:
f1ddcaf33   Herbert Xu   [CRYPTO] api: Rem...
331
  		len += crypto_compress_ctxsize(alg);
fbdae9f3e   Herbert Xu   [CRYPTO] Ensure c...
332
333
  		break;
  	}
e853c3cfa   Herbert Xu   [CRYPTO] api: Add...
334
  	return len;
fbdae9f3e   Herbert Xu   [CRYPTO] Ensure c...
335
  }
6bfd48096   Herbert Xu   [CRYPTO] api: Add...
336
337
338
339
340
341
342
  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);
27d2a3300   Herbert Xu   [CRYPTO] api: All...
343
344
  struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
  				      u32 mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
346
  {
  	struct crypto_tfm *tfm = NULL;
fbdae9f3e   Herbert Xu   [CRYPTO] Ensure c...
347
  	unsigned int tfm_size;
6bfd48096   Herbert Xu   [CRYPTO] api: Add...
348
  	int err = -ENOMEM;
fbdae9f3e   Herbert Xu   [CRYPTO] Ensure c...
349

27d2a3300   Herbert Xu   [CRYPTO] api: All...
350
  	tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, type, mask);
bbeb563f7   Eric Sesterhenn   [CRYPTO] all: Use...
351
  	tfm = kzalloc(tfm_size, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
  	if (tfm == NULL)
9765d262b   Akinobu Mita   [CRYPTO] api: fix...
353
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
  	tfm->__crt_alg = alg;
6bfd48096   Herbert Xu   [CRYPTO] api: Add...
356

27d2a3300   Herbert Xu   [CRYPTO] api: All...
357
  	err = crypto_init_ops(tfm, type, mask);
6bfd48096   Herbert Xu   [CRYPTO] api: Add...
358
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
  		goto out_free_tfm;
c7fc05992   Herbert Xu   [CRYPTO] api: Add...
360

4a7794860   Herbert Xu   crypto: api - Mov...
361
  	if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm)))
c7fc05992   Herbert Xu   [CRYPTO] api: Add...
362
  		goto cra_init_failed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
  
  	goto out;
c7fc05992   Herbert Xu   [CRYPTO] api: Add...
365
366
  cra_init_failed:
  	crypto_exit_ops(tfm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
  out_free_tfm:
4a7794860   Herbert Xu   crypto: api - Mov...
368
369
  	if (err == -EAGAIN)
  		crypto_shoot_alg(alg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  	kfree(tfm);
9765d262b   Akinobu Mita   [CRYPTO] api: fix...
371
  out_err:
6bfd48096   Herbert Xu   [CRYPTO] api: Add...
372
  	tfm = ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
  out:
  	return tfm;
  }
6bfd48096   Herbert Xu   [CRYPTO] api: Add...
376
  EXPORT_SYMBOL_GPL(__crypto_alloc_tfm);
6d7d684d6   Herbert Xu   [CRYPTO] api: Add...
377
378
379
380
381
382
  /*
   *	crypto_alloc_base - Locate algorithm and allocate transform
   *	@alg_name: Name of algorithm
   *	@type: Type of algorithm
   *	@mask: Mask for type comparison
   *
7b0bac64c   Herbert Xu   crypto: api - Reb...
383
384
385
   *	This function should not be used by new algorithm types.
   *	Plesae use crypto_alloc_tfm instead.
   *
6d7d684d6   Herbert Xu   [CRYPTO] api: Add...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
   *	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);
9765d262b   Akinobu Mita   [CRYPTO] api: fix...
408
409
  		if (IS_ERR(alg)) {
  			err = PTR_ERR(alg);
6d7d684d6   Herbert Xu   [CRYPTO] api: Add...
410
  			goto err;
9765d262b   Akinobu Mita   [CRYPTO] api: fix...
411
  		}
6d7d684d6   Herbert Xu   [CRYPTO] api: Add...
412

27d2a3300   Herbert Xu   [CRYPTO] api: All...
413
  		tfm = __crypto_alloc_tfm(alg, type, mask);
6d7d684d6   Herbert Xu   [CRYPTO] api: Add...
414
  		if (!IS_ERR(tfm))
9765d262b   Akinobu Mita   [CRYPTO] api: fix...
415
  			return tfm;
6d7d684d6   Herbert Xu   [CRYPTO] api: Add...
416
417
418
419
420
421
422
423
424
425
426
  
  		crypto_mod_put(alg);
  		err = PTR_ERR(tfm);
  
  err:
  		if (err != -EAGAIN)
  			break;
  		if (signal_pending(current)) {
  			err = -EINTR;
  			break;
  		}
9765d262b   Akinobu Mita   [CRYPTO] api: fix...
427
  	}
6d7d684d6   Herbert Xu   [CRYPTO] api: Add...
428

9765d262b   Akinobu Mita   [CRYPTO] api: fix...
429
  	return ERR_PTR(err);
6d7d684d6   Herbert Xu   [CRYPTO] api: Add...
430
431
  }
  EXPORT_SYMBOL_GPL(crypto_alloc_base);
7b0bac64c   Herbert Xu   crypto: api - Reb...
432

3f683d617   Herbert Xu   crypto: api - Fix...
433
434
  void *crypto_create_tfm(struct crypto_alg *alg,
  			const struct crypto_type *frontend)
7b0bac64c   Herbert Xu   crypto: api - Reb...
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
  {
  	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:
3f683d617   Herbert Xu   crypto: api - Fix...
468
  	mem = ERR_PTR(err);
7b0bac64c   Herbert Xu   crypto: api - Reb...
469
  out:
3f683d617   Herbert Xu   crypto: api - Fix...
470
  	return mem;
7b0bac64c   Herbert Xu   crypto: api - Reb...
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
  }
  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.
   */
3f683d617   Herbert Xu   crypto: api - Fix...
494
495
  void *crypto_alloc_tfm(const char *alg_name,
  		       const struct crypto_type *frontend, u32 type, u32 mask)
7b0bac64c   Herbert Xu   crypto: api - Reb...
496
497
  {
  	struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask);
3f683d617   Herbert Xu   crypto: api - Fix...
498
  	void *tfm;
7b0bac64c   Herbert Xu   crypto: api - Reb...
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
  	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);
7b2cd92ad   Herbert Xu   crypto: api - Fix...
536

6d7d684d6   Herbert Xu   [CRYPTO] api: Add...
537
  /*
7b2cd92ad   Herbert Xu   crypto: api - Fix...
538
539
   *	crypto_destroy_tfm - Free crypto transform
   *	@mem: Start of tfm slab
6d7d684d6   Herbert Xu   [CRYPTO] api: Add...
540
541
   *	@tfm: Transform to free
   *
7b2cd92ad   Herbert Xu   crypto: api - Fix...
542
   *	This function frees up the transform and any associated resources,
6d7d684d6   Herbert Xu   [CRYPTO] api: Add...
543
544
   *	then drops the refcount on the associated algorithm.
   */
7b2cd92ad   Herbert Xu   crypto: api - Fix...
545
  void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
  {
a61cc4481   Jesper Juhl   [CRYPTO] Add null...
547
  	struct crypto_alg *alg;
a61cc4481   Jesper Juhl   [CRYPTO] Add null...
548

7b2cd92ad   Herbert Xu   crypto: api - Fix...
549
  	if (unlikely(!mem))
a61cc4481   Jesper Juhl   [CRYPTO] Add null...
550
551
552
  		return;
  
  	alg = tfm->__crt_alg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553

4a7794860   Herbert Xu   crypto: api - Mov...
554
  	if (!tfm->exit && alg->cra_exit)
c7fc05992   Herbert Xu   [CRYPTO] api: Add...
555
  		alg->cra_exit(tfm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
  	crypto_exit_ops(tfm);
72fa49191   Herbert Xu   [CRYPTO] api: Ren...
557
  	crypto_mod_put(alg);
811d8f062   Johannes Weiner   crypto: api - Use...
558
  	kzfree(mem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
  }
7b2cd92ad   Herbert Xu   crypto: api - Fix...
560
  EXPORT_SYMBOL_GPL(crypto_destroy_tfm);
fce32d70b   Herbert Xu   [CRYPTO] api: Add...
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  
  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);
c3715cb90   Sebastian Siewior   [CRYPTO] api: Mak...
575
576
577
  
  MODULE_DESCRIPTION("Cryptographic core API");
  MODULE_LICENSE("GPL");