From 72fa491912689ca69dd15f4266945d2c2f2819f8 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 28 May 2006 09:05:24 +1000 Subject: [CRYPTO] api: Rename crypto_alg_get to crypto_mod_get The functions crypto_alg_get and crypto_alg_put operates on the crypto modules rather than the algorithms. Therefore it makes sense to call them crypto_mod_get and crypto_alg_put respectively. This is needed because we need to have real algorithm reference counters for parameterised algorithms as they can be unregistered from below by when their parameter algorithms are themselves unregistered. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- crypto/api.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'crypto/api.c') diff --git a/crypto/api.c b/crypto/api.c index c11ec1fd4f18..8c2743a05f90 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -29,12 +29,12 @@ LIST_HEAD(crypto_alg_list); DECLARE_RWSEM(crypto_alg_sem); -static inline int crypto_alg_get(struct crypto_alg *alg) +static inline int crypto_mod_get(struct crypto_alg *alg) { return try_module_get(alg->cra_module); } -static inline void crypto_alg_put(struct crypto_alg *alg) +static inline void crypto_mod_put(struct crypto_alg *alg) { module_put(alg->cra_module); } @@ -57,12 +57,12 @@ static struct crypto_alg *crypto_alg_lookup(const char *name) if (!exact && !(fuzzy && q->cra_priority > best)) continue; - if (unlikely(!crypto_alg_get(q))) + if (unlikely(!crypto_mod_get(q))) continue; best = q->cra_priority; if (alg) - crypto_alg_put(alg); + crypto_mod_put(alg); alg = q; if (exact) @@ -202,7 +202,7 @@ out_free_tfm: kfree(tfm); tfm = NULL; out_put: - crypto_alg_put(alg); + crypto_mod_put(alg); out: return tfm; } @@ -221,7 +221,7 @@ void crypto_free_tfm(struct crypto_tfm *tfm) if (alg->cra_exit) alg->cra_exit(tfm); crypto_exit_ops(tfm); - crypto_alg_put(alg); + crypto_mod_put(alg); memset(tfm, 0, size); kfree(tfm); } @@ -305,7 +305,7 @@ int crypto_alg_available(const char *name, u32 flags) struct crypto_alg *alg = crypto_alg_mod_lookup(name); if (alg) { - crypto_alg_put(alg); + crypto_mod_put(alg); ret = 1; } -- cgit v1.2.1 From 6521f30273fbec65146a0f16de74b7b402b0f7b0 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 6 Aug 2006 20:28:44 +1000 Subject: [CRYPTO] api: Add crypto_alg reference counting Up until now we've relied on module reference counting to ensure that the crypto_alg structures don't disappear from under us. This was good enough as long as each crypto_alg came from exactly one module. However, with parameterised crypto algorithms a crypto_alg object may need two or more modules to operate. This means that we need to count the references to the crypto_alg object directly. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- crypto/api.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'crypto/api.c') diff --git a/crypto/api.c b/crypto/api.c index 8c2743a05f90..5994a58ef954 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -29,13 +29,26 @@ LIST_HEAD(crypto_alg_list); DECLARE_RWSEM(crypto_alg_sem); -static inline int crypto_mod_get(struct crypto_alg *alg) +static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg) { - return try_module_get(alg->cra_module); + atomic_inc(&alg->cra_refcnt); + return alg; +} + +static inline void crypto_alg_put(struct crypto_alg *alg) +{ + if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy) + alg->cra_destroy(alg); +} + +static struct crypto_alg *crypto_mod_get(struct crypto_alg *alg) +{ + return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL; } -static inline void crypto_mod_put(struct crypto_alg *alg) +static void crypto_mod_put(struct crypto_alg *alg) { + crypto_alg_put(alg); module_put(alg->cra_module); } @@ -274,6 +287,7 @@ int crypto_register_alg(struct crypto_alg *alg) } list_add(&alg->cra_list, &crypto_alg_list); + atomic_set(&alg->cra_refcnt, 1); out: up_write(&crypto_alg_sem); return ret; @@ -284,8 +298,6 @@ int crypto_unregister_alg(struct crypto_alg *alg) int ret = -ENOENT; struct crypto_alg *q; - BUG_ON(!alg->cra_module); - down_write(&crypto_alg_sem); list_for_each_entry(q, &crypto_alg_list, cra_list) { if (alg == q) { @@ -296,7 +308,15 @@ int crypto_unregister_alg(struct crypto_alg *alg) } out: up_write(&crypto_alg_sem); - return ret; + + if (ret) + return ret; + + BUG_ON(atomic_read(&alg->cra_refcnt) != 1); + if (alg->cra_destroy) + alg->cra_destroy(alg); + + return 0; } int crypto_alg_available(const char *name, u32 flags) -- cgit v1.2.1 From cce9e06d100df19a327b19f23adad76e7bf63edd Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 21 Aug 2006 21:08:13 +1000 Subject: [CRYPTO] api: Split out low-level API The crypto API is made up of the part facing users such as IPsec and the low-level part which is used by cryptographic entities such as algorithms. This patch splits out the latter so that the two APIs are more clearly delineated. As a bonus the low-level API can now be modularised if all algorithms are built as modules. Signed-off-by: Herbert Xu --- crypto/api.c | 97 ++---------------------------------------------------------- 1 file changed, 2 insertions(+), 95 deletions(-) (limited to 'crypto/api.c') diff --git a/crypto/api.c b/crypto/api.c index 5994a58ef954..c922090b4842 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -15,19 +15,17 @@ * */ -#include -#include -#include #include #include #include -#include #include #include #include "internal.h" LIST_HEAD(crypto_alg_list); +EXPORT_SYMBOL_GPL(crypto_alg_list); DECLARE_RWSEM(crypto_alg_sem); +EXPORT_SYMBOL_GPL(crypto_alg_sem); static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg) { @@ -239,86 +237,6 @@ void crypto_free_tfm(struct crypto_tfm *tfm) kfree(tfm); } -static inline int crypto_set_driver_name(struct crypto_alg *alg) -{ - static const char suffix[] = "-generic"; - char *driver_name = alg->cra_driver_name; - int len; - - if (*driver_name) - return 0; - - len = strlcpy(driver_name, alg->cra_name, CRYPTO_MAX_ALG_NAME); - if (len + sizeof(suffix) > CRYPTO_MAX_ALG_NAME) - return -ENAMETOOLONG; - - memcpy(driver_name + len, suffix, sizeof(suffix)); - return 0; -} - -int crypto_register_alg(struct crypto_alg *alg) -{ - int ret; - struct crypto_alg *q; - - if (alg->cra_alignmask & (alg->cra_alignmask + 1)) - return -EINVAL; - - if (alg->cra_alignmask & alg->cra_blocksize) - return -EINVAL; - - if (alg->cra_blocksize > PAGE_SIZE / 8) - return -EINVAL; - - if (alg->cra_priority < 0) - return -EINVAL; - - ret = crypto_set_driver_name(alg); - if (unlikely(ret)) - return ret; - - down_write(&crypto_alg_sem); - - list_for_each_entry(q, &crypto_alg_list, cra_list) { - if (q == alg) { - ret = -EEXIST; - goto out; - } - } - - list_add(&alg->cra_list, &crypto_alg_list); - atomic_set(&alg->cra_refcnt, 1); -out: - up_write(&crypto_alg_sem); - return ret; -} - -int crypto_unregister_alg(struct crypto_alg *alg) -{ - int ret = -ENOENT; - struct crypto_alg *q; - - down_write(&crypto_alg_sem); - list_for_each_entry(q, &crypto_alg_list, cra_list) { - if (alg == q) { - list_del(&alg->cra_list); - ret = 0; - goto out; - } - } -out: - up_write(&crypto_alg_sem); - - if (ret) - return ret; - - BUG_ON(atomic_read(&alg->cra_refcnt) != 1); - if (alg->cra_destroy) - alg->cra_destroy(alg); - - return 0; -} - int crypto_alg_available(const char *name, u32 flags) { int ret = 0; @@ -332,17 +250,6 @@ int crypto_alg_available(const char *name, u32 flags) return ret; } -static int __init init_crypto(void) -{ - printk(KERN_INFO "Initializing Cryptographic API\n"); - crypto_init_proc(); - return 0; -} - -__initcall(init_crypto); - -EXPORT_SYMBOL_GPL(crypto_register_alg); -EXPORT_SYMBOL_GPL(crypto_unregister_alg); EXPORT_SYMBOL_GPL(crypto_alloc_tfm); EXPORT_SYMBOL_GPL(crypto_free_tfm); EXPORT_SYMBOL_GPL(crypto_alg_available); -- cgit v1.2.1 From 2825982d9d66ebba4b532a07391dfbb357f71c5f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 6 Aug 2006 21:23:26 +1000 Subject: [CRYPTO] api: Added event notification This patch adds a notifier chain for algorithm/template registration events. This will be used to register compound algorithms such as cbc(aes). In future this will also be passed onto user-space through netlink. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- crypto/api.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 110 insertions(+), 12 deletions(-) (limited to 'crypto/api.c') diff --git a/crypto/api.c b/crypto/api.c index c922090b4842..5a0d6a17cfd7 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include "internal.h" @@ -27,6 +28,9 @@ EXPORT_SYMBOL_GPL(crypto_alg_list); DECLARE_RWSEM(crypto_alg_sem); EXPORT_SYMBOL_GPL(crypto_alg_sem); +BLOCKING_NOTIFIER_HEAD(crypto_chain); +EXPORT_SYMBOL_GPL(crypto_chain); + static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg) { atomic_inc(&alg->cra_refcnt); @@ -39,27 +43,24 @@ static inline void crypto_alg_put(struct crypto_alg *alg) alg->cra_destroy(alg); } -static struct crypto_alg *crypto_mod_get(struct crypto_alg *alg) +struct crypto_alg *crypto_mod_get(struct crypto_alg *alg) { return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL; } +EXPORT_SYMBOL_GPL(crypto_mod_get); -static void crypto_mod_put(struct crypto_alg *alg) +void crypto_mod_put(struct crypto_alg *alg) { crypto_alg_put(alg); module_put(alg->cra_module); } +EXPORT_SYMBOL_GPL(crypto_mod_put); -static struct crypto_alg *crypto_alg_lookup(const char *name) +struct crypto_alg *__crypto_alg_lookup(const char *name) { struct crypto_alg *q, *alg = NULL; - int best = -1; + int best = -2; - if (!name) - return NULL; - - down_read(&crypto_alg_sem); - list_for_each_entry(q, &crypto_alg_list, cra_list) { int exact, fuzzy; @@ -79,16 +80,113 @@ static struct crypto_alg *crypto_alg_lookup(const char *name) if (exact) break; } - + + return alg; +} +EXPORT_SYMBOL_GPL(__crypto_alg_lookup); + +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); +} + +static struct crypto_alg *crypto_larval_alloc(const char *name) +{ + struct crypto_alg *alg; + struct crypto_larval *larval; + + larval = kzalloc(sizeof(*larval), GFP_KERNEL); + if (!larval) + return NULL; + + larval->alg.cra_flags = CRYPTO_ALG_LARVAL; + larval->alg.cra_priority = -1; + larval->alg.cra_destroy = crypto_larval_destroy; + + atomic_set(&larval->alg.cra_refcnt, 2); + strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME); + init_completion(&larval->completion); + + down_write(&crypto_alg_sem); + alg = __crypto_alg_lookup(name); + 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; +} + +static void crypto_larval_kill(struct crypto_alg *alg) +{ + struct crypto_larval *larval = (void *)alg; + + down_write(&crypto_alg_sem); + list_del(&alg->cra_list); + up_write(&crypto_alg_sem); + complete(&larval->completion); + crypto_alg_put(alg); +} + +static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) +{ + struct crypto_larval *larval = (void *)alg; + + wait_for_completion_interruptible_timeout(&larval->completion, 60 * HZ); + alg = larval->adult; + if (alg && !crypto_mod_get(alg)) + alg = NULL; + crypto_mod_put(&larval->alg); + + return alg; +} + +static struct crypto_alg *crypto_alg_lookup(const char *name) +{ + struct crypto_alg *alg; + + if (!name) + return NULL; + + down_read(&crypto_alg_sem); + alg = __crypto_alg_lookup(name); up_read(&crypto_alg_sem); + return alg; } /* A far more intelligent version of this is planned. For now, just * try an exact match on the name of the algorithm. */ -static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name) +static struct crypto_alg *crypto_alg_mod_lookup(const char *name) { - return try_then_request_module(crypto_alg_lookup(name), name); + struct crypto_alg *alg; + struct crypto_alg *larval; + + alg = try_then_request_module(crypto_alg_lookup(name), name); + if (alg) + return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg; + + larval = crypto_larval_alloc(name); + if (!larval || !crypto_is_larval(larval)) + return larval; + + if (crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval) == NOTIFY_STOP) + alg = crypto_larval_wait(larval); + else { + crypto_mod_put(larval); + alg = NULL; + } + crypto_larval_kill(larval); + return alg; } static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) -- cgit v1.2.1 From 2b8c19dbdc692e81243a328725a02efb77b144a5 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 21 Sep 2006 11:31:44 +1000 Subject: [CRYPTO] api: Add cryptomgr The cryptomgr module is a simple manager of crypto algorithm instances. It ensures that parameterised algorithms of the type tmpl(alg) (e.g., cbc(aes)) are always created. This is meant to satisfy the needs for most users. For more complex cases such as deeper combinations or multiple parameters, a netlink module will be created which allows arbitrary expressions to be parsed in user-space. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- crypto/api.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'crypto/api.c') diff --git a/crypto/api.c b/crypto/api.c index 5a0d6a17cfd7..67cd6f87b74a 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -170,6 +171,7 @@ static struct crypto_alg *crypto_alg_mod_lookup(const char *name) { struct crypto_alg *alg; struct crypto_alg *larval; + int ok; alg = try_then_request_module(crypto_alg_lookup(name), name); if (alg) @@ -179,7 +181,13 @@ static struct crypto_alg *crypto_alg_mod_lookup(const char *name) if (!larval || !crypto_is_larval(larval)) return larval; - if (crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval) == NOTIFY_STOP) + ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval); + if (ok == NOTIFY_DONE) { + request_module("cryptomgr"); + ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval); + } + + if (ok == NOTIFY_STOP) alg = crypto_larval_wait(larval); else { crypto_mod_put(larval); -- cgit v1.2.1 From 492e2b63eb10c28f4f0b694264d74a8755cd1be0 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 21 Sep 2006 11:35:17 +1000 Subject: [CRYPTO] api: Allow algorithm lookup by type This patch also adds the infrastructure to pick an algorithm based on their type. For example, this allows you to select the encryption algorithm "aes", instead of any algorithm registered under the name "aes". For now this is only accessible internally. Eventually it will be made available through crypto_alloc_tfm. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- crypto/api.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'crypto/api.c') diff --git a/crypto/api.c b/crypto/api.c index 67cd6f87b74a..ddf6a767acdd 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -57,7 +57,7 @@ void crypto_mod_put(struct crypto_alg *alg) } EXPORT_SYMBOL_GPL(crypto_mod_put); -struct crypto_alg *__crypto_alg_lookup(const char *name) +struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask) { struct crypto_alg *q, *alg = NULL; int best = -2; @@ -65,6 +65,13 @@ struct crypto_alg *__crypto_alg_lookup(const char *name) list_for_each_entry(q, &crypto_alg_list, cra_list) { int exact, fuzzy; + if ((q->cra_flags ^ type) & mask) + continue; + + if (crypto_is_larval(q) && + ((struct crypto_larval *)q)->mask != mask) + continue; + exact = !strcmp(q->cra_driver_name, name); fuzzy = !strcmp(q->cra_name, name); if (!exact && !(fuzzy && q->cra_priority > best)) @@ -96,7 +103,8 @@ static void crypto_larval_destroy(struct crypto_alg *alg) kfree(larval); } -static struct crypto_alg *crypto_larval_alloc(const char *name) +static struct crypto_alg *crypto_larval_alloc(const char *name, u32 type, + u32 mask) { struct crypto_alg *alg; struct crypto_larval *larval; @@ -105,7 +113,8 @@ static struct crypto_alg *crypto_larval_alloc(const char *name) if (!larval) return NULL; - larval->alg.cra_flags = CRYPTO_ALG_LARVAL; + larval->mask = mask; + larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type; larval->alg.cra_priority = -1; larval->alg.cra_destroy = crypto_larval_destroy; @@ -114,7 +123,7 @@ static struct crypto_alg *crypto_larval_alloc(const char *name) init_completion(&larval->completion); down_write(&crypto_alg_sem); - alg = __crypto_alg_lookup(name); + alg = __crypto_alg_lookup(name, type, mask); if (!alg) { alg = &larval->alg; list_add(&alg->cra_list, &crypto_alg_list); @@ -151,7 +160,8 @@ static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) return alg; } -static struct crypto_alg *crypto_alg_lookup(const char *name) +static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, + u32 mask) { struct crypto_alg *alg; @@ -159,25 +169,27 @@ static struct crypto_alg *crypto_alg_lookup(const char *name) return NULL; down_read(&crypto_alg_sem); - alg = __crypto_alg_lookup(name); + alg = __crypto_alg_lookup(name, type, mask); up_read(&crypto_alg_sem); return alg; } -/* A far more intelligent version of this is planned. For now, just - * try an exact match on the name of the algorithm. */ -static struct crypto_alg *crypto_alg_mod_lookup(const char *name) +struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) { struct crypto_alg *alg; struct crypto_alg *larval; int ok; - alg = try_then_request_module(crypto_alg_lookup(name), name); + mask &= ~CRYPTO_ALG_LARVAL; + type &= mask; + + alg = try_then_request_module(crypto_alg_lookup(name, type, mask), + name); if (alg) return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg; - larval = crypto_larval_alloc(name); + larval = crypto_larval_alloc(name, type, mask); if (!larval || !crypto_is_larval(larval)) return larval; @@ -196,6 +208,7 @@ static struct crypto_alg *crypto_alg_mod_lookup(const char *name) crypto_larval_kill(larval); return alg; } +EXPORT_SYMBOL_GPL(crypto_alg_mod_lookup); static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) { @@ -291,7 +304,7 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) struct crypto_alg *alg; unsigned int tfm_size; - alg = crypto_alg_mod_lookup(name); + alg = crypto_alg_mod_lookup(name, 0, 0); if (alg == NULL) goto out; @@ -346,7 +359,7 @@ void crypto_free_tfm(struct crypto_tfm *tfm) int crypto_alg_available(const char *name, u32 flags) { int ret = 0; - struct crypto_alg *alg = crypto_alg_mod_lookup(name); + struct crypto_alg *alg = crypto_alg_mod_lookup(name, 0, 0); if (alg) { crypto_mod_put(alg); -- cgit v1.2.1 From 6bfd48096ff8ecabf955958b51ddfa7988eb0a14 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 21 Sep 2006 11:39:29 +1000 Subject: [CRYPTO] api: Added spawns Spawns lock a specific crypto algorithm in place. They can then be used with crypto_spawn_tfm to allocate a tfm for that algorithm. When the base algorithm of a spawn is deregistered, all its spawns will be automatically removed. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- crypto/api.c | 95 +++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 30 deletions(-) (limited to 'crypto/api.c') diff --git a/crypto/api.c b/crypto/api.c index ddf6a767acdd..7e5522cf856e 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -15,11 +15,13 @@ * */ +#include #include #include #include #include #include +#include #include #include #include "internal.h" @@ -38,12 +40,6 @@ static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg) return alg; } -static inline void crypto_alg_put(struct crypto_alg *alg) -{ - if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy) - alg->cra_destroy(alg); -} - struct crypto_alg *crypto_mod_get(struct crypto_alg *alg) { return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL; @@ -65,6 +61,9 @@ struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask) list_for_each_entry(q, &crypto_alg_list, cra_list) { int exact, fuzzy; + if (crypto_is_moribund(q)) + continue; + if ((q->cra_flags ^ type) & mask) continue; @@ -111,7 +110,7 @@ static struct crypto_alg *crypto_larval_alloc(const char *name, u32 type, larval = kzalloc(sizeof(*larval), GFP_KERNEL); if (!larval) - return NULL; + return ERR_PTR(-ENOMEM); larval->mask = mask; larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type; @@ -153,8 +152,11 @@ static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) wait_for_completion_interruptible_timeout(&larval->completion, 60 * HZ); alg = larval->adult; - if (alg && !crypto_mod_get(alg)) - alg = NULL; + if (alg) { + if (!crypto_mod_get(alg)) + alg = ERR_PTR(-EAGAIN); + } else + alg = ERR_PTR(-ENOENT); crypto_mod_put(&larval->alg); return alg; @@ -165,9 +167,6 @@ static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, { struct crypto_alg *alg; - if (!name) - return NULL; - down_read(&crypto_alg_sem); alg = __crypto_alg_lookup(name, type, mask); up_read(&crypto_alg_sem); @@ -181,7 +180,10 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) struct crypto_alg *larval; int ok; - mask &= ~CRYPTO_ALG_LARVAL; + if (!name) + return ERR_PTR(-ENOENT); + + mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD); type &= mask; alg = try_then_request_module(crypto_alg_lookup(name, type, mask), @@ -190,7 +192,7 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg; larval = crypto_larval_alloc(name, type, mask); - if (!larval || !crypto_is_larval(larval)) + if (IS_ERR(larval) || !crypto_is_larval(larval)) return larval; ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval); @@ -203,7 +205,7 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) alg = crypto_larval_wait(larval); else { crypto_mod_put(larval); - alg = NULL; + alg = ERR_PTR(-ENOENT); } crypto_larval_kill(larval); return alg; @@ -298,31 +300,40 @@ static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags) return len + (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1)); } -struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) +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); + +struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags) { struct crypto_tfm *tfm = NULL; - struct crypto_alg *alg; unsigned int tfm_size; - - alg = crypto_alg_mod_lookup(name, 0, 0); - if (alg == NULL) - goto out; + int err = -ENOMEM; tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags); tfm = kzalloc(tfm_size, GFP_KERNEL); if (tfm == NULL) - goto out_put; + goto out; tfm->__crt_alg = alg; - - if (crypto_init_flags(tfm, flags)) + + err = crypto_init_flags(tfm, flags); + if (err) goto out_free_tfm; - if (crypto_init_ops(tfm)) + err = crypto_init_ops(tfm); + if (err) goto out_free_tfm; - if (alg->cra_init && alg->cra_init(tfm)) + if (alg->cra_init && (err = alg->cra_init(tfm))) { + if (err == -EAGAIN) + crypto_shoot_alg(alg); goto cra_init_failed; + } goto out; @@ -330,12 +341,36 @@ cra_init_failed: crypto_exit_ops(tfm); out_free_tfm: kfree(tfm); - tfm = NULL; -out_put: - crypto_mod_put(alg); + tfm = ERR_PTR(err); out: return tfm; } +EXPORT_SYMBOL_GPL(__crypto_alloc_tfm); + +struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) +{ + struct crypto_tfm *tfm = NULL; + int err; + + do { + struct crypto_alg *alg; + + alg = crypto_alg_mod_lookup(name, 0, 0); + err = PTR_ERR(alg); + if (IS_ERR(alg)) + continue; + + tfm = __crypto_alloc_tfm(alg, flags); + err = 0; + if (IS_ERR(tfm)) { + crypto_mod_put(alg); + err = PTR_ERR(tfm); + tfm = NULL; + } + } while (err == -EAGAIN && !signal_pending(current)); + + return tfm; +} void crypto_free_tfm(struct crypto_tfm *tfm) { @@ -361,7 +396,7 @@ int crypto_alg_available(const char *name, u32 flags) int ret = 0; struct crypto_alg *alg = crypto_alg_mod_lookup(name, 0, 0); - if (alg) { + if (!IS_ERR(alg)) { crypto_mod_put(alg); ret = 1; } -- cgit v1.2.1 From f3f632d61ae9af85d436706ee8e33af1a7fb9c28 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 6 Aug 2006 23:12:59 +1000 Subject: [CRYPTO] api: Added asynchronous flag This patch adds the asynchronous flag and changes all existing users to only look up algorithms that are synchronous. Signed-off-by: Herbert Xu --- crypto/api.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'crypto/api.c') diff --git a/crypto/api.c b/crypto/api.c index 7e5522cf856e..1e4692a13474 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -355,7 +355,7 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) do { struct crypto_alg *alg; - alg = crypto_alg_mod_lookup(name, 0, 0); + alg = crypto_alg_mod_lookup(name, 0, CRYPTO_ALG_ASYNC); err = PTR_ERR(alg); if (IS_ERR(alg)) continue; @@ -394,7 +394,8 @@ void crypto_free_tfm(struct crypto_tfm *tfm) int crypto_alg_available(const char *name, u32 flags) { int ret = 0; - struct crypto_alg *alg = crypto_alg_mod_lookup(name, 0, 0); + struct crypto_alg *alg = crypto_alg_mod_lookup(name, 0, + CRYPTO_ALG_ASYNC); if (!IS_ERR(alg)) { crypto_mod_put(alg); -- cgit v1.2.1 From 6d7d684d635ac5a345f075015f2c84169c111c6a Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 30 Jul 2006 11:53:01 +1000 Subject: [CRYPTO] api: Added crypto_alloc_base Up until now all crypto transforms have been of the same type, struct crypto_tfm, regardless of whether they are ciphers, digests, or other types. As a result of that, we check the types at run-time before each crypto operation. This is rather cumbersome. We could instead use different C types for each crypto type to ensure that the correct types are used at compile time. That is, we would have crypto_cipher/crypto_digest instead of just crypto_tfm. The appropriate type would then be required for the actual operations such as crypto_digest_digest. Now that we have the type/mask fields when looking up algorithms, it is easy to request for an algorithm of the precise type that the user wants. However, crypto_alloc_tfm currently does not expose these new attributes. This patch introduces the function crypto_alloc_base which will carry these new parameters. It will be renamed to crypto_alloc_tfm once all existing users have been converted. Signed-off-by: Herbert Xu --- crypto/api.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'crypto/api.c') diff --git a/crypto/api.c b/crypto/api.c index 1e4692a13474..bc4b7901acdf 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -372,6 +372,66 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) return tfm; } +/* + * crypto_alloc_base - Locate algorithm and allocate transform + * @alg_name: Name of algorithm + * @type: Type of algorithm + * @mask: Mask for type comparison + * + * 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); + err = PTR_ERR(alg); + tfm = ERR_PTR(err); + if (IS_ERR(alg)) + goto err; + + tfm = __crypto_alloc_tfm(alg, 0); + if (!IS_ERR(tfm)) + break; + + crypto_mod_put(alg); + err = PTR_ERR(tfm); + +err: + if (err != -EAGAIN) + break; + if (signal_pending(current)) { + err = -EINTR; + break; + } + }; + + return tfm; +} +EXPORT_SYMBOL_GPL(crypto_alloc_base); + +/* + * crypto_free_tfm - Free crypto transform + * @tfm: Transform to free + * + * crypto_free_tfm() frees up the transform and any associated resources, + * then drops the refcount on the associated algorithm. + */ void crypto_free_tfm(struct crypto_tfm *tfm) { struct crypto_alg *alg; -- cgit v1.2.1 From e853c3cfa8cc24869ecd2526e589bcb176bc12e9 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 22 Aug 2006 00:06:54 +1000 Subject: [CRYPTO] api: Added crypto_type support This patch adds the crypto_type structure which will be used for all new crypto algorithm types, beginning with block ciphers. The primary purpose of this abstraction is to allow different crypto_type objects for crypto algorithms of the same type, in particular, there will be a different crypto_type objects for asynchronous algorithms. Signed-off-by: Herbert Xu --- crypto/api.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'crypto/api.c') diff --git a/crypto/api.c b/crypto/api.c index bc4b7901acdf..edaa843d8e83 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -226,17 +226,18 @@ static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) case CRYPTO_ALG_TYPE_COMPRESS: return crypto_init_compress_flags(tfm, flags); - - default: - break; } - BUG(); - return -EINVAL; + return 0; } static int crypto_init_ops(struct crypto_tfm *tfm) { + const struct crypto_type *type = tfm->__crt_alg->cra_type; + + if (type) + return type->init(tfm); + switch (crypto_tfm_alg_type(tfm)) { case CRYPTO_ALG_TYPE_CIPHER: return crypto_init_cipher_ops(tfm); @@ -257,6 +258,14 @@ static int crypto_init_ops(struct crypto_tfm *tfm) static void crypto_exit_ops(struct crypto_tfm *tfm) { + const struct crypto_type *type = tfm->__crt_alg->cra_type; + + if (type) { + if (type->exit) + type->exit(tfm); + return; + } + switch (crypto_tfm_alg_type(tfm)) { case CRYPTO_ALG_TYPE_CIPHER: crypto_exit_cipher_ops(tfm); @@ -278,26 +287,31 @@ static void crypto_exit_ops(struct crypto_tfm *tfm) static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags) { + const struct crypto_type *type = alg->cra_type; unsigned int len; + len = alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1); + if (type) + return len + type->ctxsize(alg); + switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { default: BUG(); case CRYPTO_ALG_TYPE_CIPHER: - len = crypto_cipher_ctxsize(alg, flags); + len += crypto_cipher_ctxsize(alg, flags); break; case CRYPTO_ALG_TYPE_DIGEST: - len = crypto_digest_ctxsize(alg, flags); + len += crypto_digest_ctxsize(alg, flags); break; case CRYPTO_ALG_TYPE_COMPRESS: - len = crypto_compress_ctxsize(alg, flags); + len += crypto_compress_ctxsize(alg, flags); break; } - return len + (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1)); + return len; } void crypto_shoot_alg(struct crypto_alg *alg) -- cgit v1.2.1 From fce32d70ba834129b164c40c2d4260e5a7a7d850 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 26 Aug 2006 17:35:45 +1000 Subject: [CRYPTO] api: Add crypto_comp and crypto_has_* This patch adds the crypto_comp type to complete the compile-time checking conversion. The functions crypto_has_alg and crypto_has_cipher, etc. are also added to replace crypto_alg_available. Signed-off-by: Herbert Xu --- crypto/api.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'crypto/api.c') diff --git a/crypto/api.c b/crypto/api.c index edaa843d8e83..2e84d4b54790 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -482,3 +482,17 @@ int crypto_alg_available(const char *name, u32 flags) EXPORT_SYMBOL_GPL(crypto_alloc_tfm); EXPORT_SYMBOL_GPL(crypto_free_tfm); EXPORT_SYMBOL_GPL(crypto_alg_available); + +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); -- cgit v1.2.1