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
---
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
#include
#include
+#include
+#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 == _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= _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
#include
#include
+#include
#include
#include
@@ -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