Message ID | 20160505195120.1843.35821.stgit@tstruk-mobl1 (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Herbert Xu |
Headers | show |
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 -- To unsubscribe from this list: send the line "unsubscribe linux-crypto" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Tadeusz - David updated the keys-asym-keyctl branch, and this patch set won't build any more. On Thu, 5 May 2016, Tadeusz Struk wrote: > 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 > +static int asym_key_encrypt(const struct key *key, struct akcipher_request *req) ... > + params.data_len = req->src_len; > + params.enc_len = req->dst_len; The params member names have changed (now in_len and out_len). > + ret = encrypt_blob(¶ms, in, out); The encrypt function for the key can now be called with params.key->type->asym_eds_op(). This also allows you to factor out the duplication in asym_key_encrypt, asym_key_decrypt, and asym_key_sign. See keyctl_pkey_e_d_s() in keyctl_pkey.c > +static int asym_key_verify(const struct key *key, struct akcipher_request *req) ... > + ret = verify_signature(key, NULL, &sig); key->type->asym_verify_signature() is available as well. Regards, -- Mat Martineau Intel OTC -- To unsubscribe from this list: send the line "unsubscribe linux-crypto" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Mat, On 05/13/2016 04:32 PM, Mat Martineau wrote: > >> + params.data_len = req->src_len; >> + params.enc_len = req->dst_len; Thanks for info. I have sent an update for this. > > The params member names have changed (now in_len and out_len). >> + ret = encrypt_blob(¶ms, in, out); > > The encrypt function for the key can now be called with params.key->type->asym_eds_op(). This also allows you to factor out the duplication in asym_key_encrypt, asym_key_decrypt, and asym_key_sign. See keyctl_pkey_e_d_s() in keyctl_pkey.c > >> +static int asym_key_verify(const struct key *key, struct akcipher_request *req) > ... >> + ret = verify_signature(key, NULL, &sig); > > key->type->asym_verify_signature() is available as well. Since these operation will be triggered from userspace I think it's better to use the official interface as defined in crypto/public_key.h instead of direct calls. Some operation may not be implemented for a given key type and the official interface performs necessary checks. Thanks,
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"; + 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
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(-) -- To unsubscribe from this list: send the line "unsubscribe linux-crypto" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html