2016-04-15 20:28:01

by Tadeusz Struk

[permalink] [raw]
Subject: [PATCH v5 0/6] crypto: algif - add akcipher

First four patches are a resend of the v3 algif_akcipher from
Stephan Mueller, with minor changes after rebase on top of 4.6-rc1.

The next three patches add support for keys stored in system
keyring subsystem.

First patch adds algif_akcipher nokey hadlers.

Second patch adds generic sign, verify, encrypt, decrypt accessors
functions to the asymmetric key type. These will be defined by
asymmetric subtypes, similarly to how public_key currently defines
the verify_signature function.

Third patch adds support for ALG_SET_KEY_ID and ALG_SET_PUBKEY_ID
commands to AF_ALG and setkeyid operation to the af_alg_type struct.
If the keyid is used then the afalg layer acquires the key for the
keyring subsystem and uses the new asymmetric accessor functions
instead of akcipher api. The asymmetric subtypes can use akcipher
api internally.

Patches generated on top of
https://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-next
plus this:
https://patchwork.kernel.org/patch/8843381/

v5 changes:
- drop public key changes and use new version provided by David
- rebase on key-next and https://patchwork.kernel.org/patch/8843381/

v4 changes:
- don't use internal public_key struct in af_alg.
- add generic accessor functions to asymmetric key type, which take
the generic struct key type and resolve the specific subtype internally

v3 changes:
- include Stephan's patches (rebased on 4.6-rc1)
- add algif_akcipher nokey hadlers
- add public_key info struct to public_key and helper query functions
- add a check if a key is a software accessible key on af_alg, and
return -ENOKEY if it isn't

v2 changes:
- pass the original skcipher request in ablkcipher.base.data instead of
casting it back from the ablkcipher request.
- rename _req to base_req
- dropped 3/3

---

Stephan Mueller (4):
crypto: AF_ALG -- add sign/verify API
crypto: AF_ALG -- add setpubkey setsockopt call
crypto: AF_ALG -- add asymmetric cipher interface
crypto: algif_akcipher - enable compilation

Tadeusz Struk (2):
crypto: algif_akcipher - add ops_nokey
crypto: AF_ALG - add support for key_id


crypto/Kconfig | 9
crypto/Makefile | 1
crypto/af_alg.c | 28 +
crypto/algif_akcipher.c | 884 +++++++++++++++++++++++++++++++++++++++++++
include/crypto/if_alg.h | 2
include/uapi/linux/if_alg.h | 5
6 files changed, 924 insertions(+), 5 deletions(-)
create mode 100644 crypto/algif_akcipher.c
--


2016-04-15 20:28:09

by Tadeusz Struk

[permalink] [raw]
Subject: [PATCH v5 1/6] crypto: AF_ALG -- add sign/verify API

From: Stephan Mueller <[email protected]>

Add the flags for handling signature generation and signature
verification.

Also, the patch adds the interface for setting a public key.

Signed-off-by: Stephan Mueller <[email protected]>
Signed-off-by: Tadeusz Struk <[email protected]>
---
include/uapi/linux/if_alg.h | 3 +++
1 file changed, 3 insertions(+)

diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
index f2acd2f..02e6162 100644
--- a/include/uapi/linux/if_alg.h
+++ b/include/uapi/linux/if_alg.h
@@ -34,9 +34,12 @@ struct af_alg_iv {
#define ALG_SET_OP 3
#define ALG_SET_AEAD_ASSOCLEN 4
#define ALG_SET_AEAD_AUTHSIZE 5
+#define ALG_SET_PUBKEY 6

/* Operations */
#define ALG_OP_DECRYPT 0
#define ALG_OP_ENCRYPT 1
+#define ALG_OP_SIGN 2
+#define ALG_OP_VERIFY 3

#endif /* _LINUX_IF_ALG_H */

2016-04-15 20:28:13

by Tadeusz Struk

[permalink] [raw]
Subject: [PATCH v5 2/6] crypto: AF_ALG -- add setpubkey setsockopt call

From: Stephan Mueller <[email protected]>

For supporting asymmetric ciphers, user space must be able to set the
public key. The patch adds a new setsockopt call for setting the public
key.

Signed-off-by: Stephan Mueller <[email protected]>
Signed-off-by: Tadeusz Struk <[email protected]>
---
crypto/af_alg.c | 18 +++++++++++++-----
include/crypto/if_alg.h | 1 +
2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index f5e18c2..24dc082 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -202,13 +202,17 @@ unlock:
}

static int alg_setkey(struct sock *sk, char __user *ukey,
- unsigned int keylen)
+ unsigned int keylen,
+ int (*setkey)(void *private, const u8 *key,
+ unsigned int keylen))
{
struct alg_sock *ask = alg_sk(sk);
- const struct af_alg_type *type = ask->type;
u8 *key;
int err;

+ if (!setkey)
+ return -ENOPROTOOPT;
+
key = sock_kmalloc(sk, keylen, GFP_KERNEL);
if (!key)
return -ENOMEM;
@@ -217,7 +221,7 @@ static int alg_setkey(struct sock *sk, char __user *ukey,
if (copy_from_user(key, ukey, keylen))
goto out;

- err = type->setkey(ask->private, key, keylen);
+ err = setkey(ask->private, key, keylen);

out:
sock_kzfree_s(sk, key, keylen);
@@ -247,10 +251,14 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
case ALG_SET_KEY:
if (sock->state == SS_CONNECTED)
goto unlock;
- if (!type->setkey)
+
+ err = alg_setkey(sk, optval, optlen, type->setkey);
+ break;
+ case ALG_SET_PUBKEY:
+ if (sock->state == SS_CONNECTED)
goto unlock;

- err = alg_setkey(sk, optval, optlen);
+ err = alg_setkey(sk, optval, optlen, type->setpubkey);
break;
case ALG_SET_AEAD_AUTHSIZE:
if (sock->state == SS_CONNECTED)
diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
index a2bfd78..6c3e6e7 100644
--- a/include/crypto/if_alg.h
+++ b/include/crypto/if_alg.h
@@ -52,6 +52,7 @@ struct af_alg_type {
void *(*bind)(const char *name, u32 type, u32 mask);
void (*release)(void *private);
int (*setkey)(void *private, const u8 *key, unsigned int keylen);
+ int (*setpubkey)(void *private, const u8 *key, unsigned int keylen);
int (*accept)(void *private, struct sock *sk);
int (*accept_nokey)(void *private, struct sock *sk);
int (*setauthsize)(void *private, unsigned int authsize);

2016-04-15 20:28:23

by Tadeusz Struk

[permalink] [raw]
Subject: [PATCH v5 4/6] crypto: algif_akcipher - enable compilation

From: Stephan Mueller <[email protected]>

Add the Makefile and Kconfig updates to allow algif_akcipher to be
compiled.

Signed-off-by: Stephan Mueller <[email protected]>
Signed-off-by: Tadeusz Struk <[email protected]>
---
crypto/Kconfig | 9 +++++++++
crypto/Makefile | 1 +
2 files changed, 10 insertions(+)

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 93a1fdc..b932319 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1626,6 +1626,15 @@ config CRYPTO_USER_API_AEAD
This option enables the user-spaces interface for AEAD
cipher algorithms.

+config CRYPTO_USER_API_AKCIPHER
+ tristate "User-space interface for asymmetric key cipher algorithms"
+ depends on NET
+ select CRYPTO_AKCIPHER2
+ select CRYPTO_USER_API
+ help
+ This option enables the user-spaces interface for asymmetric
+ key cipher algorithms.
+
config CRYPTO_HASH_INFO
bool

diff --git a/crypto/Makefile b/crypto/Makefile
index 4f4ef7e..c51ac16 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -121,6 +121,7 @@ obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o
obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o
obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o
+obj-$(CONFIG_CRYPTO_USER_API_AKCIPHER) += algif_akcipher.o

#
# generic algorithms and the async_tx api

2016-04-15 20:28:36

by Tadeusz Struk

[permalink] [raw]
Subject: [PATCH v5 5/6] crypto: algif_akcipher - add ops_nokey

Similar to algif_skcipher and algif_hash, algif_akcipher needs
to prevent user space from using the interface in an improper way.
This patch adds nokey ops handlers, which do just that.

Signed-off-by: Tadeusz Struk <[email protected]>
---
crypto/algif_akcipher.c | 159 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 152 insertions(+), 7 deletions(-)

diff --git a/crypto/algif_akcipher.c b/crypto/algif_akcipher.c
index 6342b6e..e00793d 100644
--- a/crypto/algif_akcipher.c
+++ b/crypto/algif_akcipher.c
@@ -27,6 +27,11 @@ struct akcipher_sg_list {
struct scatterlist sg[ALG_MAX_PAGES];
};

+struct akcipher_tfm {
+ struct crypto_akcipher *akcipher;
+ bool has_key;
+};
+
struct akcipher_ctx {
struct akcipher_sg_list tsgl;
struct af_alg_sgl rsgl[ALG_MAX_PAGES];
@@ -450,25 +455,151 @@ static struct proto_ops algif_akcipher_ops = {
.poll = akcipher_poll,
};

+static int akcipher_check_key(struct socket *sock)
+{
+ int err = 0;
+ struct sock *psk;
+ struct alg_sock *pask;
+ struct akcipher_tfm *tfm;
+ struct sock *sk = sock->sk;
+ struct alg_sock *ask = alg_sk(sk);
+
+ lock_sock(sk);
+ if (ask->refcnt)
+ goto unlock_child;
+
+ psk = ask->parent;
+ pask = alg_sk(ask->parent);
+ tfm = pask->private;
+
+ err = -ENOKEY;
+ lock_sock_nested(psk, SINGLE_DEPTH_NESTING);
+ if (!tfm->has_key)
+ goto unlock;
+
+ if (!pask->refcnt++)
+ sock_hold(psk);
+
+ ask->refcnt = 1;
+ sock_put(psk);
+
+ err = 0;
+
+unlock:
+ release_sock(psk);
+unlock_child:
+ release_sock(sk);
+
+ return err;
+}
+
+static int akcipher_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
+ size_t size)
+{
+ int err;
+
+ err = akcipher_check_key(sock);
+ if (err)
+ return err;
+
+ return akcipher_sendmsg(sock, msg, size);
+}
+
+static ssize_t akcipher_sendpage_nokey(struct socket *sock, struct page *page,
+ int offset, size_t size, int flags)
+{
+ int err;
+
+ err = akcipher_check_key(sock);
+ if (err)
+ return err;
+
+ return akcipher_sendpage(sock, page, offset, size, flags);
+}
+
+static int akcipher_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
+ size_t ignored, int flags)
+{
+ int err;
+
+ err = akcipher_check_key(sock);
+ if (err)
+ return err;
+
+ return akcipher_recvmsg(sock, msg, ignored, flags);
+}
+
+static struct proto_ops algif_akcipher_ops_nokey = {
+ .family = PF_ALG,
+
+ .connect = sock_no_connect,
+ .socketpair = sock_no_socketpair,
+ .getname = sock_no_getname,
+ .ioctl = sock_no_ioctl,
+ .listen = sock_no_listen,
+ .shutdown = sock_no_shutdown,
+ .getsockopt = sock_no_getsockopt,
+ .mmap = sock_no_mmap,
+ .bind = sock_no_bind,
+ .accept = sock_no_accept,
+ .setsockopt = sock_no_setsockopt,
+
+ .release = af_alg_release,
+ .sendmsg = akcipher_sendmsg_nokey,
+ .sendpage = akcipher_sendpage_nokey,
+ .recvmsg = akcipher_recvmsg_nokey,
+ .poll = akcipher_poll,
+};
+
static void *akcipher_bind(const char *name, u32 type, u32 mask)
{
- return crypto_alloc_akcipher(name, type, mask);
+ struct akcipher_tfm *tfm;
+ struct crypto_akcipher *akcipher;
+
+ tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
+ if (!tfm)
+ return ERR_PTR(-ENOMEM);
+
+ akcipher = crypto_alloc_akcipher(name, type, mask);
+ if (IS_ERR(akcipher)) {
+ kfree(tfm);
+ return ERR_CAST(akcipher);
+ }
+
+ tfm->akcipher = akcipher;
+ return tfm;
}

static void akcipher_release(void *private)
{
- crypto_free_akcipher(private);
+ struct akcipher_tfm *tfm = private;
+ struct crypto_akcipher *akcipher = tfm->akcipher;
+
+ crypto_free_akcipher(akcipher);
+ kfree(tfm);
}

static int akcipher_setprivkey(void *private, const u8 *key,
unsigned int keylen)
{
- return crypto_akcipher_set_priv_key(private, key, keylen);
+ struct akcipher_tfm *tfm = private;
+ struct crypto_akcipher *akcipher = tfm->akcipher;
+ int err;
+
+ err = crypto_akcipher_set_priv_key(akcipher, key, keylen);
+ tfm->has_key = !err;
+ return err;
}

static int akcipher_setpubkey(void *private, const u8 *key, unsigned int keylen)
{
- return crypto_akcipher_set_pub_key(private, key, keylen);
+ struct akcipher_tfm *tfm = private;
+ struct crypto_akcipher *akcipher = tfm->akcipher;
+ int err;
+
+ err = crypto_akcipher_set_pub_key(akcipher, key, keylen);
+ tfm->has_key = !err;
+ return err;
}

static void akcipher_sock_destruct(struct sock *sk)
@@ -481,11 +612,13 @@ static void akcipher_sock_destruct(struct sock *sk)
af_alg_release_parent(sk);
}

-static int akcipher_accept_parent(void *private, struct sock *sk)
+static int akcipher_accept_parent_nokey(void *private, struct sock *sk)
{
struct akcipher_ctx *ctx;
struct alg_sock *ask = alg_sk(sk);
- unsigned int len = sizeof(*ctx) + crypto_akcipher_reqsize(private);
+ struct akcipher_tfm *tfm = private;
+ struct crypto_akcipher *akcipher = tfm->akcipher;
+ unsigned int len = sizeof(*ctx) + crypto_akcipher_reqsize(akcipher);

ctx = sock_kmalloc(sk, len, GFP_KERNEL);
if (!ctx)
@@ -503,7 +636,7 @@ static int akcipher_accept_parent(void *private, struct sock *sk)

ask->private = ctx;

- akcipher_request_set_tfm(&ctx->req, private);
+ akcipher_request_set_tfm(&ctx->req, akcipher);
akcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
af_alg_complete, &ctx->completion);

@@ -512,13 +645,25 @@ static int akcipher_accept_parent(void *private, struct sock *sk)
return 0;
}

+static int akcipher_accept_parent(void *private, struct sock *sk)
+{
+ struct akcipher_tfm *tfm = private;
+
+ if (!tfm->has_key)
+ return -ENOKEY;
+
+ return akcipher_accept_parent_nokey(private, sk);
+}
+
static const struct af_alg_type algif_type_akcipher = {
.bind = akcipher_bind,
.release = akcipher_release,
.setkey = akcipher_setprivkey,
.setpubkey = akcipher_setpubkey,
.accept = akcipher_accept_parent,
+ .accept_nokey = akcipher_accept_parent_nokey,
.ops = &algif_akcipher_ops,
+ .ops_nokey = &algif_akcipher_ops_nokey,
.name = "akcipher",
.owner = THIS_MODULE
};

2016-04-15 20:28:35

by Tadeusz Struk

[permalink] [raw]
Subject: [PATCH v5 6/6] crypto: AF_ALG - add support for key_id

This patch adds support for asymmetric key type to AF_ALG.
It will work as follows: A new PF_ALG socket options are
added on top of existing ALG_SET_KEY and ALG_SET_PUBKEY, namely
ALG_SET_KEY_ID and ALG_SET_PUBKEY_ID for setting public and
private keys respectively. When these new options will be used
the user, instead of providing the key material, will provide a
key id and the key itself will be obtained from kernel keyring
subsystem. The user will use the standard tools (keyctl tool
or the keyctl syscall) for key instantiation and to obtain the
key id. The key id can also be obtained by reading the
/proc/keys file.

When a key corresponding to the given keyid is found, it is stored
in the socket context and subsequent crypto operation invoked by the
user will use the new asymmetric accessor functions instead of akcipher
api. The asymmetric subtype can internally use akcipher api or
invoke operations defined by a given subtype, depending on the
key type.

Signed-off-by: Tadeusz Struk <[email protected]>
---
crypto/af_alg.c | 10 ++
crypto/algif_akcipher.c | 207 ++++++++++++++++++++++++++++++++++++++++++-
include/crypto/if_alg.h | 1
include/uapi/linux/if_alg.h | 2
4 files changed, 215 insertions(+), 5 deletions(-)

diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index 24dc082..59c8244 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -260,6 +260,16 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,

err = alg_setkey(sk, optval, optlen, type->setpubkey);
break;
+
+ case ALG_SET_KEY_ID:
+ case ALG_SET_PUBKEY_ID:
+ /* ALG_SET_KEY_ID is only for akcipher */
+ if (!strcmp(type->name, "akcipher") ||
+ sock->state == SS_CONNECTED)
+ goto unlock;
+
+ err = alg_setkey(sk, optval, optlen, type->setkeyid);
+ break;
case ALG_SET_AEAD_AUTHSIZE:
if (sock->state == SS_CONNECTED)
goto unlock;
diff --git a/crypto/algif_akcipher.c b/crypto/algif_akcipher.c
index e00793d..863866d 100644
--- a/crypto/algif_akcipher.c
+++ b/crypto/algif_akcipher.c
@@ -14,6 +14,8 @@
#include <crypto/akcipher.h>
#include <crypto/scatterwalk.h>
#include <crypto/if_alg.h>
+#include <crypto/public_key.h>
+#include <keys/asymmetric-type.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/kernel.h>
@@ -29,6 +31,7 @@ struct akcipher_sg_list {

struct akcipher_tfm {
struct crypto_akcipher *akcipher;
+ char keyid[12];
bool has_key;
};

@@ -37,6 +40,7 @@ struct akcipher_ctx {
struct af_alg_sgl rsgl[ALG_MAX_PAGES];

struct af_alg_completion completion;
+ struct key *key;

unsigned long used;

@@ -322,6 +326,153 @@ unlock:
return err ? err : size;
}

+static int asym_key_encrypt(const struct key *key, struct akcipher_request *req)
+{
+ struct kernel_pkey_params params = {0};
+ char *src = NULL, *dst = NULL, *in, *out;
+ int ret;
+
+ if (!sg_is_last(req->src)) {
+ src = kmalloc(req->src_len, GFP_KERNEL);
+ if (!src)
+ return -ENOMEM;
+ scatterwalk_map_and_copy(src, req->src, 0, req->src_len, 0);
+ in = src;
+ } else {
+ in = sg_virt(req->src);
+ }
+ if (!sg_is_last(req->dst)) {
+ dst = kmalloc(req->dst_len, GFP_KERNEL);
+ if (!dst) {
+ kfree(src);
+ return -ENOMEM;
+ }
+ out = dst;
+ } else {
+ out = sg_virt(req->dst);
+ }
+ params.key = (struct key *)key;
+ params.data_len = req->src_len;
+ params.enc_len = req->dst_len;
+ ret = encrypt_blob(&params, in, out);
+ if (ret)
+ goto free;
+
+ if (dst)
+ scatterwalk_map_and_copy(dst, req->dst, 0, req->dst_len, 1);
+free:
+ kfree(src);
+ kfree(dst);
+ return ret;
+}
+
+static int asym_key_decrypt(const struct key *key, struct akcipher_request *req)
+{
+ struct kernel_pkey_params params = {0};
+ char *src = NULL, *dst = NULL, *in, *out;
+ int ret;
+
+ if (!sg_is_last(req->src)) {
+ src = kmalloc(req->src_len, GFP_KERNEL);
+ if (!src)
+ return -ENOMEM;
+ scatterwalk_map_and_copy(src, req->src, 0, req->src_len, 0);
+ in = src;
+ } else {
+ in = sg_virt(req->src);
+ }
+ if (!sg_is_last(req->dst)) {
+ dst = kmalloc(req->dst_len, GFP_KERNEL);
+ if (!dst) {
+ kfree(src);
+ return -ENOMEM;
+ }
+ out = dst;
+ } else {
+ out = sg_virt(req->dst);
+ }
+ params.key = (struct key *)key;
+ params.data_len = req->src_len;
+ params.enc_len = req->dst_len;
+ ret = decrypt_blob(&params, in, out);
+ if (ret)
+ goto free;
+
+ if (dst)
+ scatterwalk_map_and_copy(dst, req->dst, 0, req->dst_len, 1);
+free:
+ kfree(src);
+ kfree(dst);
+ return ret;
+}
+
+static int asym_key_sign(const struct key *key, struct akcipher_request *req)
+{
+ struct kernel_pkey_params params = {0};
+ char *src = NULL, *dst = NULL, *in, *out;
+ int ret;
+
+ if (!sg_is_last(req->src)) {
+ src = kmalloc(req->src_len, GFP_KERNEL);
+ if (!src)
+ return -ENOMEM;
+ scatterwalk_map_and_copy(src, req->src, 0, req->src_len, 0);
+ in = src;
+ } else {
+ in = sg_virt(req->src);
+ }
+ if (!sg_is_last(req->dst)) {
+ dst = kmalloc(req->dst_len, GFP_KERNEL);
+ if (!dst) {
+ kfree(src);
+ return -ENOMEM;
+ }
+ out = dst;
+ } else {
+ out = sg_virt(req->dst);
+ }
+ params.key = (struct key *)key;
+ params.data_len = req->src_len;
+ params.enc_len = req->dst_len;
+ ret = create_signature(&params, in, out);
+ if (ret)
+ goto free;
+
+ if (dst)
+ scatterwalk_map_and_copy(dst, req->dst, 0, req->dst_len, 1);
+free:
+ kfree(src);
+ kfree(dst);
+ return ret;
+}
+
+static int asym_key_verify(const struct key *key, struct akcipher_request *req)
+{
+ struct public_key_signature sig;
+ char *src = NULL, *in;
+ int ret;
+
+ if (!sg_is_last(req->src)) {
+ src = kmalloc(req->src_len, GFP_KERNEL);
+ if (!src)
+ return -ENOMEM;
+ scatterwalk_map_and_copy(src, req->src, 0, req->src_len, 0);
+ in = src;
+ } else {
+ in = sg_virt(req->src);
+ }
+ sig.pkey_algo = "rsa";
+ sig.encoding = "pkcs1";
+ /* Need to find a way to pass the hash param */
+ sig.hash_algo = "sha1";
+ sig.digest_size = 20;
+ sig.s_size = req->src_len;
+ sig.s = src;
+ ret = verify_signature(key, &sig);
+ kfree(src);
+ return ret;
+}
+
static int akcipher_recvmsg(struct socket *sock, struct msghdr *msg,
size_t ignored, int flags)
{
@@ -377,16 +528,28 @@ static int akcipher_recvmsg(struct socket *sock, struct msghdr *msg,
usedpages);
switch (ctx->op) {
case ALG_OP_VERIFY:
- err = crypto_akcipher_verify(&ctx->req);
+ if (ctx->key)
+ err = asym_key_verify(ctx->key, &ctx->req);
+ else
+ err = crypto_akcipher_verify(&ctx->req);
break;
case ALG_OP_SIGN:
- err = crypto_akcipher_sign(&ctx->req);
+ if (ctx->key)
+ err = asym_key_sign(ctx->key, &ctx->req);
+ else
+ err = crypto_akcipher_sign(&ctx->req);
break;
case ALG_OP_ENCRYPT:
- err = crypto_akcipher_encrypt(&ctx->req);
+ if (ctx->key)
+ err = asym_key_encrypt(ctx->key, &ctx->req);
+ else
+ err = crypto_akcipher_encrypt(&ctx->req);
break;
case ALG_OP_DECRYPT:
- err = crypto_akcipher_decrypt(&ctx->req);
+ if (ctx->key)
+ err = asym_key_decrypt(ctx->key, &ctx->req);
+ else
+ err = crypto_akcipher_decrypt(&ctx->req);
break;
default:
err = -EFAULT;
@@ -579,6 +742,27 @@ static void akcipher_release(void *private)
kfree(tfm);
}

+static int akcipher_setkeyid(void *private, const u8 *key, unsigned int keylen)
+{
+ struct akcipher_tfm *tfm = private;
+ struct key *akey;
+ u32 keyid = *((u32 *)key);
+ int err = -ENOKEY;
+
+ /* Store the key id and verify that a key with the given id is present.
+ * The actual key will be acquired in the accept_parent function
+ */
+ sprintf(tfm->keyid, "id:%08x", keyid);
+ akey = request_key(&key_type_asymmetric, tfm->keyid, NULL);
+ if (IS_ERR(key))
+ goto out;
+
+ tfm->has_key = true;
+ key_put(akey);
+out:
+ return err;
+}
+
static int akcipher_setprivkey(void *private, const u8 *key,
unsigned int keylen)
{
@@ -610,6 +794,8 @@ static void akcipher_sock_destruct(struct sock *sk)
akcipher_put_sgl(sk);
sock_kfree_s(sk, ctx, ctx->len);
af_alg_release_parent(sk);
+ if (ctx->key)
+ key_put(ctx->key);
}

static int akcipher_accept_parent_nokey(void *private, struct sock *sk)
@@ -618,6 +804,7 @@ static int akcipher_accept_parent_nokey(void *private, struct sock *sk)
struct alg_sock *ask = alg_sk(sk);
struct akcipher_tfm *tfm = private;
struct crypto_akcipher *akcipher = tfm->akcipher;
+ struct key *key;
unsigned int len = sizeof(*ctx) + crypto_akcipher_reqsize(akcipher);

ctx = sock_kmalloc(sk, len, GFP_KERNEL);
@@ -634,11 +821,20 @@ static int akcipher_accept_parent_nokey(void *private, struct sock *sk)
af_alg_init_completion(&ctx->completion);
sg_init_table(ctx->tsgl.sg, ALG_MAX_PAGES);

- ask->private = ctx;
+ if (strlen(tfm->keyid)) {
+ key = request_key(&key_type_asymmetric, tfm->keyid, NULL);
+ if (IS_ERR(key)) {
+ sock_kfree_s(sk, ctx, len);
+ return -ENOKEY;
+ }

+ ctx->key = key;
+ memset(tfm->keyid, '\0', sizeof(tfm->keyid));
+ }
akcipher_request_set_tfm(&ctx->req, akcipher);
akcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
af_alg_complete, &ctx->completion);
+ ask->private = ctx;

sk->sk_destruct = akcipher_sock_destruct;

@@ -660,6 +856,7 @@ static const struct af_alg_type algif_type_akcipher = {
.release = akcipher_release,
.setkey = akcipher_setprivkey,
.setpubkey = akcipher_setpubkey,
+ .setkeyid = akcipher_setkeyid,
.accept = akcipher_accept_parent,
.accept_nokey = akcipher_accept_parent_nokey,
.ops = &algif_akcipher_ops,
diff --git a/include/crypto/if_alg.h b/include/crypto/if_alg.h
index 6c3e6e7..09c99ab 100644
--- a/include/crypto/if_alg.h
+++ b/include/crypto/if_alg.h
@@ -53,6 +53,7 @@ struct af_alg_type {
void (*release)(void *private);
int (*setkey)(void *private, const u8 *key, unsigned int keylen);
int (*setpubkey)(void *private, const u8 *key, unsigned int keylen);
+ int (*setkeyid)(void *private, const u8 *key, unsigned int keylen);
int (*accept)(void *private, struct sock *sk);
int (*accept_nokey)(void *private, struct sock *sk);
int (*setauthsize)(void *private, unsigned int authsize);
diff --git a/include/uapi/linux/if_alg.h b/include/uapi/linux/if_alg.h
index 02e6162..0379766 100644
--- a/include/uapi/linux/if_alg.h
+++ b/include/uapi/linux/if_alg.h
@@ -35,6 +35,8 @@ struct af_alg_iv {
#define ALG_SET_AEAD_ASSOCLEN 4
#define ALG_SET_AEAD_AUTHSIZE 5
#define ALG_SET_PUBKEY 6
+#define ALG_SET_PUBKEY_ID 7
+#define ALG_SET_KEY_ID 8

/* Operations */
#define ALG_OP_DECRYPT 0

2016-04-15 20:29:09

by Tadeusz Struk

[permalink] [raw]
Subject: [PATCH v5 3/6] crypto: AF_ALG -- add asymmetric cipher interface

From: Stephan Mueller <[email protected]>

This patch adds the user space interface for asymmetric ciphers. The
interface allows the use of sendmsg as well as vmsplice to provide data.

This version has been rebased on top of 4.6 and a few chackpatch issues
have been fixed.

Signed-off-by: Stephan Mueller <[email protected]>
Signed-off-by: Tadeusz Struk <[email protected]>
---
crypto/algif_akcipher.c | 542 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 542 insertions(+)
create mode 100644 crypto/algif_akcipher.c

diff --git a/crypto/algif_akcipher.c b/crypto/algif_akcipher.c
new file mode 100644
index 0000000..6342b6e
--- /dev/null
+++ b/crypto/algif_akcipher.c
@@ -0,0 +1,542 @@
+/*
+ * algif_akcipher: User-space interface for asymmetric cipher algorithms
+ *
+ * Copyright (C) 2015, Stephan Mueller <[email protected]>
+ *
+ * This file provides the user-space API for asymmetric ciphers.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <crypto/akcipher.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/if_alg.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/net.h>
+#include <net/sock.h>
+
+struct akcipher_sg_list {
+ unsigned int cur;
+ struct scatterlist sg[ALG_MAX_PAGES];
+};
+
+struct akcipher_ctx {
+ struct akcipher_sg_list tsgl;
+ struct af_alg_sgl rsgl[ALG_MAX_PAGES];
+
+ struct af_alg_completion completion;
+
+ unsigned long used;
+
+ unsigned int len;
+ bool more;
+ bool merge;
+ int op;
+
+ struct akcipher_request req;
+};
+
+static inline int akcipher_sndbuf(struct sock *sk)
+{
+ struct alg_sock *ask = alg_sk(sk);
+ struct akcipher_ctx *ctx = ask->private;
+
+ return max_t(int, max_t(int, sk->sk_sndbuf & PAGE_MASK, PAGE_SIZE) -
+ ctx->used, 0);
+}
+
+static inline bool akcipher_writable(struct sock *sk)
+{
+ return akcipher_sndbuf(sk) >= PAGE_SIZE;
+}
+
+static inline int akcipher_calcsize(struct akcipher_ctx *ctx)
+{
+ return crypto_akcipher_maxsize(crypto_akcipher_reqtfm(&ctx->req));
+}
+
+static void akcipher_put_sgl(struct sock *sk)
+{
+ struct alg_sock *ask = alg_sk(sk);
+ struct akcipher_ctx *ctx = ask->private;
+ struct akcipher_sg_list *sgl = &ctx->tsgl;
+ struct scatterlist *sg = sgl->sg;
+ unsigned int i;
+
+ for (i = 0; i < sgl->cur; i++) {
+ if (!sg_page(sg + i))
+ continue;
+
+ put_page(sg_page(sg + i));
+ sg_assign_page(sg + i, NULL);
+ }
+ sg_init_table(sg, ALG_MAX_PAGES);
+ sgl->cur = 0;
+ ctx->used = 0;
+ ctx->more = 0;
+ ctx->merge = 0;
+}
+
+static void akcipher_wmem_wakeup(struct sock *sk)
+{
+ struct socket_wq *wq;
+
+ if (!akcipher_writable(sk))
+ return;
+
+ rcu_read_lock();
+ wq = rcu_dereference(sk->sk_wq);
+ if (wq_has_sleeper(&wq->wait))
+ wake_up_interruptible_sync_poll(&wq->wait, POLLIN |
+ POLLRDNORM |
+ POLLRDBAND);
+ sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
+ rcu_read_unlock();
+}
+
+static int akcipher_wait_for_data(struct sock *sk, unsigned int flags)
+{
+ struct alg_sock *ask = alg_sk(sk);
+ struct akcipher_ctx *ctx = ask->private;
+ long timeout;
+ DEFINE_WAIT(wait);
+ int err = -ERESTARTSYS;
+
+ if (flags & MSG_DONTWAIT)
+ return -EAGAIN;
+
+ set_bit(SOCKWQ_ASYNC_WAITDATA, &sk->sk_socket->flags);
+
+ for (;;) {
+ if (signal_pending(current))
+ break;
+ prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ if (sk_wait_event(sk, &timeout, !ctx->more)) {
+ err = 0;
+ break;
+ }
+ }
+ finish_wait(sk_sleep(sk), &wait);
+
+ clear_bit(SOCKWQ_ASYNC_WAITDATA, &sk->sk_socket->flags);
+
+ return err;
+}
+
+static void akcipher_data_wakeup(struct sock *sk)
+{
+ struct alg_sock *ask = alg_sk(sk);
+ struct akcipher_ctx *ctx = ask->private;
+ struct socket_wq *wq;
+
+ if (ctx->more)
+ return;
+ if (!ctx->used)
+ return;
+
+ rcu_read_lock();
+ wq = rcu_dereference(sk->sk_wq);
+ if (wq_has_sleeper(&wq->wait))
+ wake_up_interruptible_sync_poll(&wq->wait, POLLOUT |
+ POLLRDNORM |
+ POLLRDBAND);
+ sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
+ rcu_read_unlock();
+}
+
+static int akcipher_sendmsg(struct socket *sock, struct msghdr *msg,
+ size_t size)
+{
+ struct sock *sk = sock->sk;
+ struct alg_sock *ask = alg_sk(sk);
+ struct akcipher_ctx *ctx = ask->private;
+ struct akcipher_sg_list *sgl = &ctx->tsgl;
+ struct af_alg_control con = {};
+ long copied = 0;
+ int op = 0;
+ bool init = 0;
+ int err;
+
+ if (msg->msg_controllen) {
+ err = af_alg_cmsg_send(msg, &con);
+ if (err)
+ return err;
+
+ init = 1;
+ switch (con.op) {
+ case ALG_OP_VERIFY:
+ case ALG_OP_SIGN:
+ case ALG_OP_ENCRYPT:
+ case ALG_OP_DECRYPT:
+ op = con.op;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ lock_sock(sk);
+ if (!ctx->more && ctx->used)
+ goto unlock;
+
+ if (init)
+ ctx->op = op;
+
+ while (size) {
+ unsigned long len = size;
+ struct scatterlist *sg = NULL;
+
+ /* use the existing memory in an allocated page */
+ if (ctx->merge) {
+ sg = sgl->sg + sgl->cur - 1;
+ len = min_t(unsigned long, len,
+ PAGE_SIZE - sg->offset - sg->length);
+ err = memcpy_from_msg(page_address(sg_page(sg)) +
+ sg->offset + sg->length,
+ msg, len);
+ if (err)
+ goto unlock;
+
+ sg->length += len;
+ ctx->merge = (sg->offset + sg->length) &
+ (PAGE_SIZE - 1);
+
+ ctx->used += len;
+ copied += len;
+ size -= len;
+ continue;
+ }
+
+ if (!akcipher_writable(sk)) {
+ /* user space sent too much data */
+ akcipher_put_sgl(sk);
+ err = -EMSGSIZE;
+ goto unlock;
+ }
+
+ /* allocate a new page */
+ len = min_t(unsigned long, size, akcipher_sndbuf(sk));
+ while (len) {
+ int plen = 0;
+
+ if (sgl->cur >= ALG_MAX_PAGES) {
+ akcipher_put_sgl(sk);
+ err = -E2BIG;
+ goto unlock;
+ }
+
+ sg = sgl->sg + sgl->cur;
+ plen = min_t(int, len, PAGE_SIZE);
+
+ sg_assign_page(sg, alloc_page(GFP_KERNEL));
+ if (!sg_page(sg)) {
+ err = -ENOMEM;
+ goto unlock;
+ }
+
+ err = memcpy_from_msg(page_address(sg_page(sg)),
+ msg, plen);
+ if (err) {
+ __free_page(sg_page(sg));
+ sg_assign_page(sg, NULL);
+ goto unlock;
+ }
+
+ sg->offset = 0;
+ sg->length = plen;
+ len -= plen;
+ ctx->used += plen;
+ copied += plen;
+ sgl->cur++;
+ size -= plen;
+ ctx->merge = plen & (PAGE_SIZE - 1);
+ }
+ }
+
+ err = 0;
+
+ ctx->more = msg->msg_flags & MSG_MORE;
+
+unlock:
+ akcipher_data_wakeup(sk);
+ release_sock(sk);
+
+ return err ?: copied;
+}
+
+static ssize_t akcipher_sendpage(struct socket *sock, struct page *page,
+ int offset, size_t size, int flags)
+{
+ struct sock *sk = sock->sk;
+ struct alg_sock *ask = alg_sk(sk);
+ struct akcipher_ctx *ctx = ask->private;
+ struct akcipher_sg_list *sgl = &ctx->tsgl;
+ int err = 0;
+
+ if (flags & MSG_SENDPAGE_NOTLAST)
+ flags |= MSG_MORE;
+
+ if (sgl->cur >= ALG_MAX_PAGES)
+ return -E2BIG;
+
+ lock_sock(sk);
+ if (!ctx->more && ctx->used)
+ goto unlock;
+
+ if (!size)
+ goto done;
+
+ if (!akcipher_writable(sk)) {
+ /* user space sent too much data */
+ akcipher_put_sgl(sk);
+ err = -EMSGSIZE;
+ goto unlock;
+ }
+
+ ctx->merge = 0;
+
+ get_page(page);
+ sg_set_page(sgl->sg + sgl->cur, page, size, offset);
+ sgl->cur++;
+ ctx->used += size;
+
+done:
+ ctx->more = flags & MSG_MORE;
+unlock:
+ akcipher_data_wakeup(sk);
+ release_sock(sk);
+
+ return err ? err : size;
+}
+
+static int akcipher_recvmsg(struct socket *sock, struct msghdr *msg,
+ size_t ignored, int flags)
+{
+ struct sock *sk = sock->sk;
+ struct alg_sock *ask = alg_sk(sk);
+ struct akcipher_ctx *ctx = ask->private;
+ struct akcipher_sg_list *sgl = &ctx->tsgl;
+ unsigned int i = 0;
+ int err;
+ unsigned long used = 0;
+ size_t usedpages = 0;
+ unsigned int cnt = 0;
+
+ /* Limit number of IOV blocks to be accessed below */
+ if (msg->msg_iter.nr_segs > ALG_MAX_PAGES)
+ return -ENOMSG;
+
+ lock_sock(sk);
+
+ if (ctx->more) {
+ err = akcipher_wait_for_data(sk, flags);
+ if (err)
+ goto unlock;
+ }
+
+ used = ctx->used;
+
+ /* convert iovecs of output buffers into scatterlists */
+ while (iov_iter_count(&msg->msg_iter)) {
+ /* make one iovec available as scatterlist */
+ err = af_alg_make_sg(&ctx->rsgl[cnt], &msg->msg_iter,
+ iov_iter_count(&msg->msg_iter));
+ if (err < 0)
+ goto unlock;
+ usedpages += err;
+ /* chain the new scatterlist with previous one */
+ if (cnt)
+ af_alg_link_sg(&ctx->rsgl[cnt - 1], &ctx->rsgl[cnt]);
+
+ iov_iter_advance(&msg->msg_iter, err);
+ cnt++;
+ }
+
+ /* ensure output buffer is sufficiently large */
+ if (usedpages < akcipher_calcsize(ctx)) {
+ err = -EMSGSIZE;
+ goto unlock;
+ }
+
+ sg_mark_end(sgl->sg + sgl->cur - 1);
+
+ akcipher_request_set_crypt(&ctx->req, sgl->sg, ctx->rsgl[0].sg, used,
+ usedpages);
+ switch (ctx->op) {
+ case ALG_OP_VERIFY:
+ err = crypto_akcipher_verify(&ctx->req);
+ break;
+ case ALG_OP_SIGN:
+ err = crypto_akcipher_sign(&ctx->req);
+ break;
+ case ALG_OP_ENCRYPT:
+ err = crypto_akcipher_encrypt(&ctx->req);
+ break;
+ case ALG_OP_DECRYPT:
+ err = crypto_akcipher_decrypt(&ctx->req);
+ break;
+ default:
+ err = -EFAULT;
+ goto unlock;
+ }
+
+ err = af_alg_wait_for_completion(err, &ctx->completion);
+
+ if (err) {
+ /* EBADMSG implies a valid cipher operation took place */
+ if (err == -EBADMSG)
+ akcipher_put_sgl(sk);
+ goto unlock;
+ }
+
+ akcipher_put_sgl(sk);
+
+unlock:
+ for (i = 0; i < cnt; i++)
+ af_alg_free_sg(&ctx->rsgl[i]);
+
+ akcipher_wmem_wakeup(sk);
+ release_sock(sk);
+
+ return err ? err : ctx->req.dst_len;
+}
+
+static unsigned int akcipher_poll(struct file *file, struct socket *sock,
+ poll_table *wait)
+{
+ struct sock *sk = sock->sk;
+ struct alg_sock *ask = alg_sk(sk);
+ struct akcipher_ctx *ctx = ask->private;
+ unsigned int mask = 0;
+
+ sock_poll_wait(file, sk_sleep(sk), wait);
+
+ if (!ctx->more)
+ mask |= POLLIN | POLLRDNORM;
+
+ if (akcipher_writable(sk))
+ mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+
+ return mask;
+}
+
+static struct proto_ops algif_akcipher_ops = {
+ .family = PF_ALG,
+
+ .connect = sock_no_connect,
+ .socketpair = sock_no_socketpair,
+ .getname = sock_no_getname,
+ .ioctl = sock_no_ioctl,
+ .listen = sock_no_listen,
+ .shutdown = sock_no_shutdown,
+ .getsockopt = sock_no_getsockopt,
+ .mmap = sock_no_mmap,
+ .bind = sock_no_bind,
+ .accept = sock_no_accept,
+ .setsockopt = sock_no_setsockopt,
+
+ .release = af_alg_release,
+ .sendmsg = akcipher_sendmsg,
+ .sendpage = akcipher_sendpage,
+ .recvmsg = akcipher_recvmsg,
+ .poll = akcipher_poll,
+};
+
+static void *akcipher_bind(const char *name, u32 type, u32 mask)
+{
+ return crypto_alloc_akcipher(name, type, mask);
+}
+
+static void akcipher_release(void *private)
+{
+ crypto_free_akcipher(private);
+}
+
+static int akcipher_setprivkey(void *private, const u8 *key,
+ unsigned int keylen)
+{
+ return crypto_akcipher_set_priv_key(private, key, keylen);
+}
+
+static int akcipher_setpubkey(void *private, const u8 *key, unsigned int keylen)
+{
+ return crypto_akcipher_set_pub_key(private, key, keylen);
+}
+
+static void akcipher_sock_destruct(struct sock *sk)
+{
+ struct alg_sock *ask = alg_sk(sk);
+ struct akcipher_ctx *ctx = ask->private;
+
+ akcipher_put_sgl(sk);
+ sock_kfree_s(sk, ctx, ctx->len);
+ af_alg_release_parent(sk);
+}
+
+static int akcipher_accept_parent(void *private, struct sock *sk)
+{
+ struct akcipher_ctx *ctx;
+ struct alg_sock *ask = alg_sk(sk);
+ unsigned int len = sizeof(*ctx) + crypto_akcipher_reqsize(private);
+
+ ctx = sock_kmalloc(sk, len, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+ memset(ctx, 0, len);
+
+ ctx->len = len;
+ ctx->used = 0;
+ ctx->more = 0;
+ ctx->merge = 0;
+ ctx->op = 0;
+ ctx->tsgl.cur = 0;
+ af_alg_init_completion(&ctx->completion);
+ sg_init_table(ctx->tsgl.sg, ALG_MAX_PAGES);
+
+ ask->private = ctx;
+
+ akcipher_request_set_tfm(&ctx->req, private);
+ akcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ af_alg_complete, &ctx->completion);
+
+ sk->sk_destruct = akcipher_sock_destruct;
+
+ return 0;
+}
+
+static const struct af_alg_type algif_type_akcipher = {
+ .bind = akcipher_bind,
+ .release = akcipher_release,
+ .setkey = akcipher_setprivkey,
+ .setpubkey = akcipher_setpubkey,
+ .accept = akcipher_accept_parent,
+ .ops = &algif_akcipher_ops,
+ .name = "akcipher",
+ .owner = THIS_MODULE
+};
+
+static int __init algif_akcipher_init(void)
+{
+ return af_alg_register_type(&algif_type_akcipher);
+}
+
+static void __exit algif_akcipher_exit(void)
+{
+ int err = af_alg_unregister_type(&algif_type_akcipher);
+
+ WARN_ON(err);
+}
+
+module_init(algif_akcipher_init);
+module_exit(algif_akcipher_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Stephan Mueller <[email protected]>");
+MODULE_DESCRIPTION("Asymmetric kernel crypto API user space interface");

2016-04-15 21:33:49

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v5 6/6] crypto: AF_ALG - add support for key_id

Hi Tadeusz,

[auto build test ERROR on cryptodev/master]
[also build test ERROR on v4.6-rc3 next-20160415]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url: https://github.com/0day-ci/linux/commits/Tadeusz-Struk/crypto-algif-add-akcipher/20160416-043207
base: https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
config: i386-allmodconfig (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=i386

All error/warnings (new ones prefixed by >>):

crypto/algif_akcipher.c: In function 'asym_key_encrypt':
>> crypto/algif_akcipher.c:331:9: error: variable 'params' has initializer but incomplete type
struct kernel_pkey_params params = {0};
^
>> crypto/algif_akcipher.c:331:38: warning: excess elements in struct initializer
struct kernel_pkey_params params = {0};
^
crypto/algif_akcipher.c:331:38: note: (near initialization for 'params')
>> crypto/algif_akcipher.c:331:28: error: storage size of 'params' isn't known
struct kernel_pkey_params params = {0};
^
>> crypto/algif_akcipher.c:357:8: error: implicit declaration of function 'encrypt_blob' [-Werror=implicit-function-declaration]
ret = encrypt_blob(&params, in, out);
^
>> crypto/algif_akcipher.c:331:28: warning: unused variable 'params' [-Wunused-variable]
struct kernel_pkey_params params = {0};
^
crypto/algif_akcipher.c: In function 'asym_key_decrypt':
crypto/algif_akcipher.c:371:9: error: variable 'params' has initializer but incomplete type
struct kernel_pkey_params params = {0};
^
crypto/algif_akcipher.c:371:38: warning: excess elements in struct initializer
struct kernel_pkey_params params = {0};
^
crypto/algif_akcipher.c:371:38: note: (near initialization for 'params')
crypto/algif_akcipher.c:371:28: error: storage size of 'params' isn't known
struct kernel_pkey_params params = {0};
^
>> crypto/algif_akcipher.c:397:8: error: implicit declaration of function 'decrypt_blob' [-Werror=implicit-function-declaration]
ret = decrypt_blob(&params, in, out);
^
crypto/algif_akcipher.c:371:28: warning: unused variable 'params' [-Wunused-variable]
struct kernel_pkey_params params = {0};
^
crypto/algif_akcipher.c: In function 'asym_key_sign':
crypto/algif_akcipher.c:411:9: error: variable 'params' has initializer but incomplete type
struct kernel_pkey_params params = {0};
^
crypto/algif_akcipher.c:411:38: warning: excess elements in struct initializer
struct kernel_pkey_params params = {0};
^
crypto/algif_akcipher.c:411:38: note: (near initialization for 'params')
crypto/algif_akcipher.c:411:28: error: storage size of 'params' isn't known
struct kernel_pkey_params params = {0};
^
>> crypto/algif_akcipher.c:437:8: error: implicit declaration of function 'create_signature' [-Werror=implicit-function-declaration]
ret = create_signature(&params, in, out);
^
crypto/algif_akcipher.c:411:28: warning: unused variable 'params' [-Wunused-variable]
struct kernel_pkey_params params = {0};
^
crypto/algif_akcipher.c: In function 'asym_key_verify':
>> crypto/algif_akcipher.c:465:5: error: 'struct public_key_signature' has no member named 'encoding'
sig.encoding = "pkcs1";
^
cc1: some warnings being treated as errors

vim +/params +331 crypto/algif_akcipher.c

325
326 return err ? err : size;
327 }
328
329 static int asym_key_encrypt(const struct key *key, struct akcipher_request *req)
330 {
> 331 struct kernel_pkey_params params = {0};
332 char *src = NULL, *dst = NULL, *in, *out;
333 int ret;
334
335 if (!sg_is_last(req->src)) {
336 src = kmalloc(req->src_len, GFP_KERNEL);
337 if (!src)
338 return -ENOMEM;
339 scatterwalk_map_and_copy(src, req->src, 0, req->src_len, 0);
340 in = src;
341 } else {
342 in = sg_virt(req->src);
343 }
344 if (!sg_is_last(req->dst)) {
345 dst = kmalloc(req->dst_len, GFP_KERNEL);
346 if (!dst) {
347 kfree(src);
348 return -ENOMEM;
349 }
350 out = dst;
351 } else {
352 out = sg_virt(req->dst);
353 }
354 params.key = (struct key *)key;
355 params.data_len = req->src_len;
356 params.enc_len = req->dst_len;
> 357 ret = encrypt_blob(&params, in, out);
358 if (ret)
359 goto free;
360
361 if (dst)
362 scatterwalk_map_and_copy(dst, req->dst, 0, req->dst_len, 1);
363 free:
364 kfree(src);
365 kfree(dst);
366 return ret;
367 }
368
369 static int asym_key_decrypt(const struct key *key, struct akcipher_request *req)
370 {
> 371 struct kernel_pkey_params params = {0};
372 char *src = NULL, *dst = NULL, *in, *out;
373 int ret;
374
375 if (!sg_is_last(req->src)) {
376 src = kmalloc(req->src_len, GFP_KERNEL);
377 if (!src)
378 return -ENOMEM;
379 scatterwalk_map_and_copy(src, req->src, 0, req->src_len, 0);
380 in = src;
381 } else {
382 in = sg_virt(req->src);
383 }
384 if (!sg_is_last(req->dst)) {
385 dst = kmalloc(req->dst_len, GFP_KERNEL);
386 if (!dst) {
387 kfree(src);
388 return -ENOMEM;
389 }
390 out = dst;
391 } else {
392 out = sg_virt(req->dst);
393 }
394 params.key = (struct key *)key;
395 params.data_len = req->src_len;
396 params.enc_len = req->dst_len;
> 397 ret = decrypt_blob(&params, in, out);
398 if (ret)
399 goto free;
400
401 if (dst)
402 scatterwalk_map_and_copy(dst, req->dst, 0, req->dst_len, 1);
403 free:
404 kfree(src);
405 kfree(dst);
406 return ret;
407 }
408
409 static int asym_key_sign(const struct key *key, struct akcipher_request *req)
410 {
> 411 struct kernel_pkey_params params = {0};
412 char *src = NULL, *dst = NULL, *in, *out;
413 int ret;
414
415 if (!sg_is_last(req->src)) {
416 src = kmalloc(req->src_len, GFP_KERNEL);
417 if (!src)
418 return -ENOMEM;
419 scatterwalk_map_and_copy(src, req->src, 0, req->src_len, 0);
420 in = src;
421 } else {
422 in = sg_virt(req->src);
423 }
424 if (!sg_is_last(req->dst)) {
425 dst = kmalloc(req->dst_len, GFP_KERNEL);
426 if (!dst) {
427 kfree(src);
428 return -ENOMEM;
429 }
430 out = dst;
431 } else {
432 out = sg_virt(req->dst);
433 }
434 params.key = (struct key *)key;
435 params.data_len = req->src_len;
436 params.enc_len = req->dst_len;
> 437 ret = create_signature(&params, in, out);
438 if (ret)
439 goto free;
440
441 if (dst)
442 scatterwalk_map_and_copy(dst, req->dst, 0, req->dst_len, 1);
443 free:
444 kfree(src);
445 kfree(dst);
446 return ret;
447 }
448
449 static int asym_key_verify(const struct key *key, struct akcipher_request *req)
450 {
451 struct public_key_signature sig;
452 char *src = NULL, *in;
453 int ret;
454
455 if (!sg_is_last(req->src)) {
456 src = kmalloc(req->src_len, GFP_KERNEL);
457 if (!src)
458 return -ENOMEM;
459 scatterwalk_map_and_copy(src, req->src, 0, req->src_len, 0);
460 in = src;
461 } else {
462 in = sg_virt(req->src);
463 }
464 sig.pkey_algo = "rsa";
> 465 sig.encoding = "pkcs1";
466 /* Need to find a way to pass the hash param */
467 sig.hash_algo = "sha1";
468 sig.digest_size = 20;

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (7.89 kB)
.config.gz (53.17 kB)
Download all attachments

2016-04-15 21:38:10

by Tadeusz Struk

[permalink] [raw]
Subject: Re: [PATCH v5 6/6] crypto: AF_ALG - add support for key_id

On 04/15/2016 02:32 PM, kbuild test robot wrote:
> Hi Tadeusz,
>
> [auto build test ERROR on cryptodev/master]
> [also build test ERROR on v4.6-rc3 next-20160415]
> [if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
>
> url: https://github.com/0day-ci/linux/commits/Tadeusz-Struk/crypto-algif-add-akcipher/20160416-043207
> base: https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
> config: i386-allmodconfig (attached as .config)
> reproduce:
> # save the attached .config to linux build tree
> make ARCH=i386

Hi,
It's is for https://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-next
plus this:
https://patchwork.kernel.org/patch/8843381/
Thanks,
--
TS

2016-04-19 10:21:41

by Philip Li

[permalink] [raw]
Subject: Re: [PATCH v5 6/6] crypto: AF_ALG - add support for key_id

On Fri, Apr 15, 2016 at 02:32:47PM -0700, Tadeusz Struk wrote:
> On 04/15/2016 02:32 PM, kbuild test robot wrote:
> > Hi Tadeusz,
> >
> > [auto build test ERROR on cryptodev/master]
> > [also build test ERROR on v4.6-rc3 next-20160415]
> > [if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
> >
> > url: https://github.com/0day-ci/linux/commits/Tadeusz-Struk/crypto-algif-add-akcipher/20160416-043207
> > base: https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
> > config: i386-allmodconfig (attached as .config)
> > reproduce:
> > # save the attached .config to linux build tree
> > make ARCH=i386
>
> Hi,
> It's is for https://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-next
> plus this:
> https://patchwork.kernel.org/patch/8843381/

Thanks Tadeusz for the feedback.

hi Xiaolong, anything we can do in 0day side to detect the base for this case?

> Thanks,
> --
> TS
>