Commit 5cb1454b862ab3040b78364d58330262fea1ddba

Authored by Herbert Xu
Committed by David S. Miller
1 parent 06ace7a9ba

[CRYPTO] Allow multiple implementations of the same algorithm

This is the first step on the road towards asynchronous support in
the Crypto API.  It adds support for having multiple crypto_alg objects
for the same algorithm registered in the system.

For example, each device driver would register a crypto_alg object
for each algorithm that it supports.  While at the same time the
user may load software implementations of those same algorithms.

Users of the Crypto API may then select a specific implementation
by name, or choose any implementation for a given algorithm with
the highest priority.

The priority field is a 32-bit signed integer.  In future it will be
possible to modify it from user-space.

This also provides a solution to the problem of selecting amongst
various AES implementations, that is, aes vs. aes-i586 vs. aes-padlock.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Showing 4 changed files with 60 additions and 9 deletions Side-by-side Diff

... ... @@ -3,6 +3,7 @@
3 3 *
4 4 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
5 5 * Copyright (c) 2002 David S. Miller (davem@redhat.com)
  6 + * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
6 7 *
7 8 * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no>
8 9 * and Nettle, by Niels Möller.
9 10  
... ... @@ -18,9 +19,11 @@
18 19 #include <linux/init.h>
19 20 #include <linux/crypto.h>
20 21 #include <linux/errno.h>
  22 +#include <linux/kernel.h>
21 23 #include <linux/kmod.h>
22 24 #include <linux/rwsem.h>
23 25 #include <linux/slab.h>
  26 +#include <linux/string.h>
24 27 #include "internal.h"
25 28  
26 29 LIST_HEAD(crypto_alg_list);
... ... @@ -39,6 +42,7 @@
39 42 static struct crypto_alg *crypto_alg_lookup(const char *name)
40 43 {
41 44 struct crypto_alg *q, *alg = NULL;
  45 + int best = -1;
42 46  
43 47 if (!name)
44 48 return NULL;
45 49  
... ... @@ -46,11 +50,23 @@
46 50 down_read(&crypto_alg_sem);
47 51  
48 52 list_for_each_entry(q, &crypto_alg_list, cra_list) {
49   - if (!(strcmp(q->cra_name, name))) {
50   - if (crypto_alg_get(q))
51   - alg = q;
  53 + int exact, fuzzy;
  54 +
  55 + exact = !strcmp(q->cra_driver_name, name);
  56 + fuzzy = !strcmp(q->cra_name, name);
  57 + if (!exact && !(fuzzy && q->cra_priority > best))
  58 + continue;
  59 +
  60 + if (unlikely(!crypto_alg_get(q)))
  61 + continue;
  62 +
  63 + best = q->cra_priority;
  64 + if (alg)
  65 + crypto_alg_put(alg);
  66 + alg = q;
  67 +
  68 + if (exact)
52 69 break;
53   - }
54 70 }
55 71  
56 72 up_read(&crypto_alg_sem);
57 73  
... ... @@ -207,9 +223,26 @@
207 223 kfree(tfm);
208 224 }
209 225  
  226 +static inline int crypto_set_driver_name(struct crypto_alg *alg)
  227 +{
  228 + static const char suffix[] = "-generic";
  229 + char *driver_name = (char *)alg->cra_driver_name;
  230 + int len;
  231 +
  232 + if (*driver_name)
  233 + return 0;
  234 +
  235 + len = strlcpy(driver_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
  236 + if (len + sizeof(suffix) > CRYPTO_MAX_ALG_NAME)
  237 + return -ENAMETOOLONG;
  238 +
  239 + memcpy(driver_name + len, suffix, sizeof(suffix));
  240 + return 0;
  241 +}
  242 +
210 243 int crypto_register_alg(struct crypto_alg *alg)
211 244 {
212   - int ret = 0;
  245 + int ret;
213 246 struct crypto_alg *q;
214 247  
215 248 if (alg->cra_alignmask & (alg->cra_alignmask + 1))
216 249  
217 250  
... ... @@ -220,11 +253,18 @@
220 253  
221 254 if (alg->cra_blocksize > PAGE_SIZE)
222 255 return -EINVAL;
  256 +
  257 + if (alg->cra_priority < 0)
  258 + return -EINVAL;
223 259  
  260 + ret = crypto_set_driver_name(alg);
  261 + if (unlikely(ret))
  262 + return ret;
  263 +
224 264 down_write(&crypto_alg_sem);
225 265  
226 266 list_for_each_entry(q, &crypto_alg_list, cra_list) {
227   - if (!(strcmp(q->cra_name, alg->cra_name))) {
  267 + if (!strcmp(q->cra_driver_name, alg->cra_driver_name)) {
228 268 ret = -EEXIST;
229 269 goto out;
230 270 }
... ... @@ -2,6 +2,7 @@
2 2 * Cryptographic API.
3 3 *
4 4 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  5 + * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
5 6 *
6 7 * This program is free software; you can redistribute it and/or modify it
7 8 * under the terms of the GNU General Public License as published by the Free
8 9  
9 10  
... ... @@ -16,9 +17,14 @@
16 17 #include <linux/highmem.h>
17 18 #include <linux/interrupt.h>
18 19 #include <linux/init.h>
  20 +#include <linux/list.h>
19 21 #include <linux/kernel.h>
  22 +#include <linux/rwsem.h>
20 23 #include <linux/slab.h>
21 24 #include <asm/kmap_types.h>
  25 +
  26 +extern struct list_head crypto_alg_list;
  27 +extern struct rw_semaphore crypto_alg_sem;
22 28  
23 29 extern enum km_type crypto_km_types[];
24 30  
... ... @@ -4,6 +4,7 @@
4 4 * Procfs information.
5 5 *
6 6 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  7 + * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
7 8 *
8 9 * This program is free software; you can redistribute it and/or modify it
9 10 * under the terms of the GNU General Public License as published by the Free
... ... @@ -18,9 +19,6 @@
18 19 #include <linux/seq_file.h>
19 20 #include "internal.h"
20 21  
21   -extern struct list_head crypto_alg_list;
22   -extern struct rw_semaphore crypto_alg_sem;
23   -
24 22 static void *c_start(struct seq_file *m, loff_t *pos)
25 23 {
26 24 struct list_head *v;
27 25  
... ... @@ -53,7 +51,9 @@
53 51 struct crypto_alg *alg = (struct crypto_alg *)p;
54 52  
55 53 seq_printf(m, "name : %s\n", alg->cra_name);
  54 + seq_printf(m, "driver : %s\n", alg->cra_driver_name);
56 55 seq_printf(m, "module : %s\n", module_name(alg->cra_module));
  56 + seq_printf(m, "priority : %d\n", alg->cra_priority);
57 57  
58 58 switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
59 59 case CRYPTO_ALG_TYPE_CIPHER:
include/linux/crypto.h
... ... @@ -3,6 +3,7 @@
3 3 *
4 4 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
5 5 * Copyright (c) 2002 David S. Miller (davem@redhat.com)
  6 + * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
6 7 *
7 8 * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no>
8 9 * and Nettle, by Niels Möller.
9 10  
... ... @@ -126,7 +127,11 @@
126 127 unsigned int cra_blocksize;
127 128 unsigned int cra_ctxsize;
128 129 unsigned int cra_alignmask;
  130 +
  131 + int cra_priority;
  132 +
129 133 const char cra_name[CRYPTO_MAX_ALG_NAME];
  134 + const char cra_driver_name[CRYPTO_MAX_ALG_NAME];
130 135  
131 136 union {
132 137 struct cipher_alg cipher;