From: Stephan Mueller <smueller@chronox.de>
To: Tadeusz Struk <tadeusz.struk@intel.com>
Cc: dhowells@redhat.com, herbert@gondor.apana.org.au,
linux-api@vger.kernel.org, marcel@holtmann.org,
linux-kernel@vger.kernel.org, keyrings@vger.kernel.org,
linux-crypto@vger.kernel.org, dwmw2@infradead.org,
davem@davemloft.net
Subject: Re: [PATCH RESEND v5 6/6] crypto: AF_ALG - add support for key_id
Date: Fri, 06 May 2016 13:46:03 +0200 [thread overview]
Message-ID: <4630984.GumaURqptq@positron.chronox.de> (raw)
In-Reply-To: <20160505195120.1843.35821.stgit@tstruk-mobl1>
Am Donnerstag, 5. Mai 2016, 12:51:20 schrieb Tadeusz Struk:
Hi Tadeusz,
> 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 <tadeusz.struk@intel.com>
> ---
> 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..f486b6d 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(¶ms, 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(¶ms, 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(¶ms, 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";
This comment shall not hold up any merging with the mainline tree.
I am not yet fully up to speed on the keys framework. But commonly, the
signature's hash type is identical to the hash used for the key. Is there a
way to obtain the key's signature type from the key framework?
> + sig.digest_size = 20;
> + sig.s_size = req->src_len;
> + sig.s = src;
> + ret = verify_signature(key, NULL, &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
Ciao
Stephan
next prev parent reply other threads:[~2016-05-06 14:50 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-05-05 19:50 [PATCH RESEND v5 0/6] crypto: algif - add akcipher Tadeusz Struk
2016-05-05 19:50 ` [PATCH RESEND v5 1/6] crypto: AF_ALG -- add sign/verify API Tadeusz Struk
2016-05-06 10:36 ` Stephan Mueller
2016-05-05 19:50 ` [PATCH RESEND v5 2/6] crypto: AF_ALG -- add setpubkey setsockopt call Tadeusz Struk
2016-05-05 19:51 ` [PATCH RESEND v5 3/6] crypto: AF_ALG -- add asymmetric cipher interface Tadeusz Struk
2016-05-05 19:51 ` [PATCH RESEND v5 4/6] crypto: algif_akcipher - enable compilation Tadeusz Struk
2016-05-05 19:51 ` [PATCH RESEND v5 5/6] crypto: algif_akcipher - add ops_nokey Tadeusz Struk
2016-05-05 19:51 ` [PATCH RESEND v5 6/6] crypto: AF_ALG - add support for key_id Tadeusz Struk
2016-05-06 11:46 ` Stephan Mueller [this message]
2016-05-13 23:32 ` Mat Martineau
2016-05-16 14:23 ` Tadeusz Struk
2016-05-11 14:25 ` [PATCH RESEND v5 0/6] crypto: algif - add akcipher David Howells
2016-05-15 4:16 ` [PATCH v6 " Tadeusz Struk
2016-05-15 4:16 ` [PATCH v6 1/6] crypto: AF_ALG -- add sign/verify API Tadeusz Struk
2016-05-15 4:16 ` [PATCH v6 2/6] crypto: AF_ALG -- add setpubkey setsockopt call Tadeusz Struk
2016-05-15 4:17 ` [PATCH v6 3/6] crypto: AF_ALG -- add asymmetric cipher interface Tadeusz Struk
2016-06-08 0:28 ` Mat Martineau
2016-06-08 5:31 ` Stephan Mueller
2016-06-08 19:14 ` Mat Martineau
2016-06-09 9:28 ` Stephan Mueller
2016-06-09 18:18 ` Mat Martineau
2016-06-09 18:24 ` Stephan Mueller
2016-06-09 18:27 ` Mat Martineau
2016-06-09 18:36 ` Stephan Mueller
2016-06-10 14:42 ` Tadeusz Struk
2016-06-22 22:45 ` Mat Martineau
2016-06-23 5:07 ` Stephan Mueller
2016-06-23 15:22 ` Denis Kenzior
2016-06-13 22:16 ` Andrew Zaborowski
2016-06-14 5:12 ` Stephan Mueller
2016-06-14 7:42 ` Andrew Zaborowski
2016-06-16 8:05 ` Stephan Mueller
2016-06-16 14:59 ` Andrew Zaborowski
2016-06-16 15:38 ` Stephan Mueller
2016-06-17 0:39 ` Andrew Zaborowski
2016-06-14 17:22 ` Mat Martineau
2016-06-15 7:04 ` Stephan Mueller
2016-05-15 4:17 ` [PATCH v6 4/6] crypto: algif_akcipher - enable compilation Tadeusz Struk
2016-05-15 4:17 ` [PATCH v6 5/6] crypto: algif_akcipher - add ops_nokey Tadeusz Struk
2016-05-15 4:17 ` [PATCH v6 6/6] crypto: AF_ALG - add support for key_id Tadeusz Struk
2016-05-26 0:45 ` Mat Martineau
2016-05-31 17:44 ` Tadeusz Struk
2016-05-15 11:59 ` [PATCH v6 0/6] crypto: algif - add akcipher Stephan Mueller
2016-05-16 20:46 ` Tadeusz Struk
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4630984.GumaURqptq@positron.chronox.de \
--to=smueller@chronox.de \
--cc=davem@davemloft.net \
--cc=dhowells@redhat.com \
--cc=dwmw2@infradead.org \
--cc=herbert@gondor.apana.org.au \
--cc=keyrings@vger.kernel.org \
--cc=linux-api@vger.kernel.org \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=marcel@holtmann.org \
--cc=tadeusz.struk@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).