crypto: user - Fix lookup of algorithms with IV generator
[linux-flexiantxendom0-3.2.10.git] / crypto / crypto_user.c
index f76e42b..e91c161 100644 (file)
 #include <linux/module.h>
 #include <linux/crypto.h>
 #include <linux/cryptouser.h>
+#include <linux/sched.h>
 #include <net/netlink.h>
 #include <linux/security.h>
 #include <net/net_namespace.h>
+#include <crypto/internal/aead.h>
+#include <crypto/internal/skcipher.h>
+
 #include "internal.h"
 
 DEFINE_MUTEX(crypto_cfg_mutex);
@@ -301,6 +305,60 @@ static int crypto_del_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
        return crypto_unregister_instance(alg);
 }
 
+static struct crypto_alg *crypto_user_skcipher_alg(const char *name, u32 type,
+                                                  u32 mask)
+{
+       int err;
+       struct crypto_alg *alg;
+
+       type = crypto_skcipher_type(type);
+       mask = crypto_skcipher_mask(mask);
+
+       for (;;) {
+               alg = crypto_lookup_skcipher(name,  type, mask);
+               if (!IS_ERR(alg))
+                       return alg;
+
+               err = PTR_ERR(alg);
+               if (err != -EAGAIN)
+                       break;
+               if (signal_pending(current)) {
+                       err = -EINTR;
+                       break;
+               }
+       }
+
+       return ERR_PTR(err);
+}
+
+static struct crypto_alg *crypto_user_aead_alg(const char *name, u32 type,
+                                              u32 mask)
+{
+       int err;
+       struct crypto_alg *alg;
+
+       type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+       type |= CRYPTO_ALG_TYPE_AEAD;
+       mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
+       mask |= CRYPTO_ALG_TYPE_MASK;
+
+       for (;;) {
+               alg = crypto_lookup_aead(name,  type, mask);
+               if (!IS_ERR(alg))
+                       return alg;
+
+               err = PTR_ERR(alg);
+               if (err != -EAGAIN)
+                       break;
+               if (signal_pending(current)) {
+                       err = -EINTR;
+                       break;
+               }
+       }
+
+       return ERR_PTR(err);
+}
+
 static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
                          struct nlattr **attrs)
 {
@@ -325,7 +383,19 @@ static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh,
        else
                name = p->cru_name;
 
-       alg = crypto_alg_mod_lookup(name, p->cru_type, p->cru_mask);
+       switch (p->cru_type & p->cru_mask & CRYPTO_ALG_TYPE_MASK) {
+       case CRYPTO_ALG_TYPE_AEAD:
+               alg = crypto_user_aead_alg(name, p->cru_type, p->cru_mask);
+               break;
+       case CRYPTO_ALG_TYPE_GIVCIPHER:
+       case CRYPTO_ALG_TYPE_BLKCIPHER:
+       case CRYPTO_ALG_TYPE_ABLKCIPHER:
+               alg = crypto_user_skcipher_alg(name, p->cru_type, p->cru_mask);
+               break;
+       default:
+               alg = crypto_alg_mod_lookup(name, p->cru_type, p->cru_mask);
+       }
+
        if (IS_ERR(alg))
                return PTR_ERR(alg);