This adds support for a new socket options called ALG_SET_KEY_ID that
allows providing the symmetric key via a key serial from the keys
subsystem.

NOTE: Currently we do not have a dedicated symmetric key type and using
the user key type is not optional. Also lookup_user_key() is currently
private to the keys subsystem and might need to be exposed to usage by
the crypto subystem first. This is just a RFC and not for merging !!!

Signed-off-by: Marcel Holtmann <mar...@holtmann.org>
---
 crypto/af_alg.c             | 14 ++++++++++++++
 crypto/algif_skcipher.c     | 25 +++++++++++++++++++++++++
 include/crypto/if_alg.h     |  2 ++
 include/uapi/linux/if_alg.h |  1 +
 4 files changed, 42 insertions(+)

diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index a8e7aa3e257b..48ddbb4063aa 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -203,6 +203,7 @@ static int alg_setsockopt(struct socket *sock, int level, 
int optname,
        struct alg_sock *ask = alg_sk(sk);
        const struct af_alg_type *type;
        int err = -ENOPROTOOPT;
+       key_serial_t keyid;
 
        lock_sock(sk);
        type = ask->type;
@@ -225,6 +226,19 @@ static int alg_setsockopt(struct socket *sock, int level, 
int optname,
                if (!type->setauthsize)
                        goto unlock;
                err = type->setauthsize(ask->private, optlen);
+               break;
+       case ALG_SET_KEY_ID:
+               if (sock->state == SS_CONNECTED)
+                       goto unlock;
+               if (!type->setkeyid)
+                       goto unlock;
+
+               err = -EFAULT;
+               if (get_user(keyid, (key_serial_t __user *) optval))
+                       goto unlock;
+
+               err = type->setkeyid(ask->private, keyid);
+               break;
        }
 
 unlock:
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index 945075292bc9..5dfae3cb6e20 100644
--- a/crypto/algif_skcipher.c
+++ b/crypto/algif_skcipher.c
@@ -22,6 +22,8 @@
 #include <linux/module.h>
 #include <linux/net.h>
 #include <net/sock.h>
+#include <keys/user-type.h>
+#include "../security/keys/internal.h"
 
 struct skcipher_sg_list {
        struct list_head list;
@@ -764,6 +766,28 @@ static int skcipher_setkey(void *private, const u8 *key, 
unsigned int keylen)
        return crypto_ablkcipher_setkey(private, key, keylen);
 }
 
+static int skcipher_setkeyid(void *private, key_serial_t id)
+{
+       key_ref_t key_ref;
+       int err = -EPROTOTYPE;
+
+       key_ref = lookup_user_key(id, 0, KEY_NEED_READ);
+       if (IS_ERR(key_ref))
+               return PTR_ERR(key_ref);
+
+       if (key_ref_to_ptr(key_ref)->type == &key_type_user) {
+               struct user_key_payload *upayload;
+
+               upayload = rcu_dereference_key(key_ref_to_ptr(key_ref));
+
+               err = crypto_ablkcipher_setkey(private, upayload->data,
+                                              upayload->datalen);
+       }
+
+       key_ref_put(key_ref);
+       return err;
+}
+
 static void skcipher_wait(struct sock *sk)
 {
        struct alg_sock *ask = alg_sk(sk);
@@ -832,6 +856,7 @@ static const struct af_alg_type algif_type_skcipher = {
        .bind           =       skcipher_bind,
        .release        =       skcipher_release,
        .setkey         =       skcipher_setkey,
+       .setkeyid       =       skcipher_setkeyid,
        .accept         =       skcipher_accept_parent,
        .ops            =       &algif_skcipher_ops,
        .name           =       "skcipher",
diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
index 018afb264ac2..f71d88162326 100644
--- a/include/crypto/if_alg.h
+++ b/include/crypto/if_alg.h
@@ -17,6 +17,7 @@
 #include <linux/completion.h>
 #include <linux/if_alg.h>
 #include <linux/scatterlist.h>
+#include <linux/key.h>
 #include <linux/types.h>
 #include <net/sock.h>
 
@@ -51,6 +52,7 @@ struct af_alg_type {
        int (*setkey)(void *private, const u8 *key, unsigned int keylen);
        int (*accept)(void *private, struct sock *sk);
        int (*setauthsize)(void *private, unsigned int authsize);
+       int (*setkeyid)(void *private, key_serial_t id);
 
        struct proto_ops *ops;
        struct module *owner;
diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
index d81dcca5bdd7..28cdc05695c0 100644
--- a/include/uapi/linux/if_alg.h
+++ b/include/uapi/linux/if_alg.h
@@ -34,6 +34,7 @@ struct af_alg_iv {
 #define ALG_SET_OP                     3
 #define ALG_SET_AEAD_ASSOCLEN          4
 #define ALG_SET_AEAD_AUTHSIZE          5
+#define ALG_SET_KEY_ID                 6
 
 /* Operations */
 #define ALG_OP_DECRYPT                 0
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to