linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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(&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";

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

  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).