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 a public_key info struct that is used to query
information about the public key.
For now it only contains information about where the key is stored.
This is to prevent other modules, like AF_ALG using a key that
can not be directly accessed by software. Later, when keyctl
will allow to reference hardware based public keys this can be
extended to describe other characteristic of the key, like
information on what operations a public key supports, size of data
is supported, whether a password is required to unlock it, etc.
Second patch adds support for ALG_SET_KEY_ID and ALG_SET_PUBKEY_ID
commands to AF_ALG, which can be used to reference sw key stored
in the system keyrings.
Third patch adds algif_akcipher nokey hadlers.
Patches generated on top of 4.6-rc1
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 (3):
crypto: algif_akcipher - add ops_nokey
crypto: KEYS - add public_key info query
crypto: AF_ALG - add support for key_id
crypto/Kconfig | 9
crypto/Makefile | 1
crypto/af_alg.c | 60 ++-
crypto/algif_akcipher.c | 685 +++++++++++++++++++++++++++++
crypto/asymmetric_keys/x509_cert_parser.c | 1
include/crypto/if_alg.h | 1
include/crypto/public_key.h | 31 +
include/uapi/linux/if_alg.h | 5
8 files changed, 788 insertions(+), 5 deletions(-)
create mode 100644 crypto/algif_akcipher.c
--
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");
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 */
It is needed to query the key capabilities and how to use the key correctly.
In case of a key stored in HW (TPM) it can not be passed to the crypto API.
For now it the public_key_info only contains information about where the key
is stored, which is needed to prevent other modules, like AF_ALG, using
a key that can not be accessed by software. Later, when support for hardware
based public keys will be added this can be extended to describe other
characteristic of the key, like information on what operations the key
supports, size of data is supported, whether a password is
required to unlock it, etc.
Signed-off-by: Tadeusz Struk <[email protected]>
---
crypto/asymmetric_keys/x509_cert_parser.c | 1 +
include/crypto/public_key.h | 31 +++++++++++++++++++++++++++++
2 files changed, 32 insertions(+)
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 4a29bac..4d44724 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -107,6 +107,7 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
goto error_decode;
cert->pub->keylen = ctx->key_size;
+ cert->pub->info.stored = KEY_INFO_STOR_SW;
/* Generate cert issuer + serial number key ID */
kid = asymmetric_key_generate_id(cert->raw_serial,
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index aa730ea..1ca1a93 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -29,6 +29,26 @@ enum key_being_used_for {
extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR];
/*
+ * Info indicating where a key is stored.
+ * For instance if the key is stored in software, then it can be accessed
+ * by SW. If the key is stored in hardware e.g. (TPM) then it can not be
+ * directly accessed by SW.
+ */
+enum public_key_info_storage {
+ KEY_INFO_STOR_HW,
+ KEY_INFO_STOR_SW
+};
+
+/*
+ * Information describing public_key.
+ * Struct sotres information about the key i.e.
+ * where key is stored, what operation it supports, etc.
+ */
+struct public_key_info {
+ enum public_key_info_storage stored;
+};
+
+/*
* Cryptographic data for the public-key subtype of the asymmetric key type.
*
* Note that this may include private part of the key as well as the public
@@ -39,6 +59,7 @@ struct public_key {
u32 keylen;
const char *id_type;
const char *pkey_algo;
+ struct public_key_info info;
};
extern void public_key_destroy(void *payload);
@@ -55,6 +76,16 @@ struct public_key_signature {
const char *hash_algo;
};
+static inline bool public_key_query_sw_key(struct public_key *pkey)
+{
+ return pkey->info.stored == KEY_INFO_STOR_SW;
+}
+
+static inline bool public_key_query_hw_key(struct public_key *pkey)
+{
+ return pkey->info.stored == KEY_INFO_STOR_HW;
+}
+
extern struct asymmetric_key_subtype public_key_subtype;
struct key;
extern int verify_signature(const struct key *key,
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 is found, the request_key() function
returns the requested key. Next the asymmetric key subtype will be
used to obtain the public_key, which can be either a public key
or a private key. The key is then verified using the new
key info public_key_query_sw_key query, to check whether or not the key
can be accessed by software. In case when the key is kept
in hardware (TPM) then the function will return -ENOKEY error code.
If the key can be accesses by software then the key payload
will be passed to the akcipher pf_alg subtype.
AF_ALG code will then call crypto API functions, either the
crypto_akcipher_set_priv_key or the crypto_akcipher_set_pub_key,
depending on the used option. Subsequently the asymmetric key
will be freed and return code returned back to the user.
Signed-off-by: Tadeusz Struk <[email protected]>
---
crypto/af_alg.c | 50 ++++++++++++++++++++++++++++++++++++++++---
include/uapi/linux/if_alg.h | 2 ++
2 files changed, 48 insertions(+), 4 deletions(-)
diff --git a/crypto/af_alg.c b/crypto/af_alg.c
index 24dc082..9d109bc 100644
--- a/crypto/af_alg.c
+++ b/crypto/af_alg.c
@@ -22,6 +22,8 @@
#include <linux/net.h>
#include <linux/rwsem.h>
#include <linux/security.h>
+#include <crypto/public_key.h>
+#include <keys/asymmetric-type.h>
struct alg_type_list {
const struct af_alg_type *type;
@@ -201,8 +203,40 @@ unlock:
return err;
}
+static int alg_setkey_id(void *private, const u8 *key, unsigned int keylen,
+ int (*setkey)(void *private, const u8 *key,
+ unsigned int keylen))
+{
+ struct key *keyring;
+ struct public_key *pkey;
+ char key_name[12];
+ u32 keyid = *((u32 *)key);
+ int err;
+
+ sprintf(key_name, "id:%08x", keyid);
+ keyring = request_key(&key_type_asymmetric, key_name, NULL);
+
+ err = -ENOKEY;
+ if (IS_ERR(keyring))
+ goto out;
+
+ pkey = keyring->payload.data[asym_crypto];
+ if (!pkey)
+ goto out_put_key;
+
+ if (!public_key_query_sw_key(pkey))
+ goto out_put_key;
+
+ err = setkey(private, pkey->key, pkey->keylen);
+
+out_put_key:
+ key_put(keyring);
+out:
+ return err;
+}
+
static int alg_setkey(struct sock *sk, char __user *ukey,
- unsigned int keylen,
+ unsigned int keylen, bool key_id,
int (*setkey)(void *private, const u8 *key,
unsigned int keylen))
{
@@ -221,7 +255,8 @@ static int alg_setkey(struct sock *sk, char __user *ukey,
if (copy_from_user(key, ukey, keylen))
goto out;
- err = setkey(ask->private, key, keylen);
+ err = key_id ? alg_setkey_id(ask->private, key, keylen, setkey) :
+ setkey(ask->private, key, keylen);
out:
sock_kzfree_s(sk, key, keylen);
@@ -236,6 +271,8 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
struct alg_sock *ask = alg_sk(sk);
const struct af_alg_type *type;
int err = -EBUSY;
+ bool key_id = ((optname == ALG_SET_PUBKEY_ID) ||
+ (optname == ALG_SET_KEY_ID));
lock_sock(sk);
if (ask->refcnt)
@@ -249,16 +286,21 @@ static int alg_setsockopt(struct socket *sock, int level, int optname,
switch (optname) {
case ALG_SET_KEY:
+ case ALG_SET_KEY_ID:
if (sock->state == SS_CONNECTED)
goto unlock;
+ /* ALG_SET_KEY_ID is only for akcipher */
+ if (!strcmp(type->name, "akcipher") && key_id)
+ goto unlock;
- err = alg_setkey(sk, optval, optlen, type->setkey);
+ err = alg_setkey(sk, optval, optlen, key_id, type->setkey);
break;
case ALG_SET_PUBKEY:
+ case ALG_SET_PUBKEY_ID:
if (sock->state == SS_CONNECTED)
goto unlock;
- err = alg_setkey(sk, optval, optlen, type->setpubkey);
+ err = alg_setkey(sk, optval, optlen, key_id, type->setpubkey);
break;
case ALG_SET_AEAD_AUTHSIZE:
if (sock->state == SS_CONNECTED)
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
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
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
};
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);
Hi Tadeusz,
[auto build test ERROR on v4.6-rc1]
[also build test ERROR on next-20160329]
[cannot apply to crypto/master]
[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/20160330-090754
config: i386-randconfig-i1-03292045 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
All error/warnings (new ones prefixed by >>):
In file included from crypto/af_alg.c:26:0:
include/keys/asymmetric-type.h: In function 'asymmetric_key_ids':
>> include/keys/asymmetric-type.h:74:12: error: dereferencing pointer to incomplete type 'const struct key'
return key->payload.data[asym_key_ids];
^
crypto/af_alg.c: In function 'alg_setkey_id':
>> crypto/af_alg.c:217:12: error: implicit declaration of function 'request_key' [-Werror=implicit-function-declaration]
keyring = request_key(&key_type_asymmetric, key_name, NULL);
^
>> crypto/af_alg.c:217:10: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
keyring = request_key(&key_type_asymmetric, key_name, NULL);
^
>> crypto/af_alg.c:223:16: error: dereferencing pointer to incomplete type 'struct key'
pkey = keyring->payload.data[asym_crypto];
^
cc1: some warnings being treated as errors
vim +74 include/keys/asymmetric-type.h
7901c1a8 David Howells 2014-09-16 68 size_t len_1,
7901c1a8 David Howells 2014-09-16 69 const void *val_2,
7901c1a8 David Howells 2014-09-16 70 size_t len_2);
146aa8b1 David Howells 2015-10-21 71 static inline
146aa8b1 David Howells 2015-10-21 72 const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
146aa8b1 David Howells 2015-10-21 73 {
146aa8b1 David Howells 2015-10-21 @74 return key->payload.data[asym_key_ids];
146aa8b1 David Howells 2015-10-21 75 }
7901c1a8 David Howells 2014-09-16 76
7901c1a8 David Howells 2014-09-16 77 /*
:::::: The code at line 74 was first introduced by commit
:::::: 146aa8b1453bd8f1ff2304ffb71b4ee0eb9acdcc KEYS: Merge the type-specific data with the payload data
:::::: TO: David Howells <[email protected]>
:::::: CC: David Howells <[email protected]>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Tadeusz,
[auto build test ERROR on v4.6-rc1]
[also build test ERROR on next-20160329]
[cannot apply to crypto/master]
[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/20160330-090754
config: arm-at91_dt_defconfig (attached as .config)
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm
All errors (new ones prefixed by >>):
In file included from crypto/af_alg.c:26:0:
include/keys/asymmetric-type.h: In function 'asymmetric_key_ids':
>> include/keys/asymmetric-type.h:74:12: error: dereferencing pointer to incomplete type
return key->payload.data[asym_key_ids];
^
crypto/af_alg.c: In function 'alg_setkey_id':
crypto/af_alg.c:217:2: error: implicit declaration of function 'request_key' [-Werror=implicit-function-declaration]
keyring = request_key(&key_type_asymmetric, key_name, NULL);
^
crypto/af_alg.c:217:10: warning: assignment makes pointer from integer without a cast
keyring = request_key(&key_type_asymmetric, key_name, NULL);
^
>> crypto/af_alg.c:223:16: error: dereferencing pointer to incomplete type
pkey = keyring->payload.data[asym_crypto];
^
cc1: some warnings being treated as errors
vim +74 include/keys/asymmetric-type.h
7901c1a8 David Howells 2014-09-16 68 size_t len_1,
7901c1a8 David Howells 2014-09-16 69 const void *val_2,
7901c1a8 David Howells 2014-09-16 70 size_t len_2);
146aa8b1 David Howells 2015-10-21 71 static inline
146aa8b1 David Howells 2015-10-21 72 const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
146aa8b1 David Howells 2015-10-21 73 {
146aa8b1 David Howells 2015-10-21 @74 return key->payload.data[asym_key_ids];
146aa8b1 David Howells 2015-10-21 75 }
7901c1a8 David Howells 2014-09-16 76
7901c1a8 David Howells 2014-09-16 77 /*
:::::: The code at line 74 was first introduced by commit
:::::: 146aa8b1453bd8f1ff2304ffb71b4ee0eb9acdcc KEYS: Merge the type-specific data with the payload data
:::::: TO: David Howells <[email protected]>
:::::: CC: David Howells <[email protected]>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi Tadeusz,
[auto build test ERROR on v4.6-rc1]
[also build test ERROR on next-20160329]
[cannot apply to crypto/master]
[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/20160330-090754
config: x86_64-allyesdebian (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All errors (new ones prefixed by >>):
crypto/built-in.o: In function `alg_setkey':
>> af_alg.c:(.text+0x36513): undefined reference to `key_type_asymmetric'
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
Hi,
On 03/29/2016 06:49 PM, kbuild test robot wrote:
> Hi Tadeusz,
>
> [auto build test ERROR on v4.6-rc1]
> [also build test ERROR on next-20160329]
> [cannot apply to crypto/master]
> [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/20160330-090754
> config: i386-randconfig-i1-03292045 (attached as .config)
> reproduce:
> # save the attached .config to linux build tree
> make ARCH=i386
>
> All error/warnings (new ones prefixed by >>):
The patches have been generated against cryptodev-2.6 rebased on top of 4.6-rc1.
It should work with crypto as soon as Herbert will rebase his repo.
Thanks,
--
TS
Tadeusz Struk <[email protected]> wrote:
> + keyring = request_key(&key_type_asymmetric, key_name, NULL);
> +
> + err = -ENOKEY;
> + if (IS_ERR(keyring))
> + goto out;
> +
> + pkey = keyring->payload.data[asym_crypto];
NAK. This is liable to crash in future. You may not assume that you know
what keyring->payload.data[asym_crypto] points to.
You may not use struct public_key outside of crypto/asymmetric_key/. It's the
internal data of the software subtype. I'll move it out of the global header
to remove the temptation;-).
You must use accessor functions such as verify_signature(). Feel free to add
further accessor functions such as query_asym_capabilities(),
create_signature(), encrypt_blob() and decrypt_blob() or something like that.
David
> Tadeusz Struk <[email protected]> wrote:
>
>> + keyring = request_key(&key_type_asymmetric, key_name, NULL);
>> +
>> + err = -ENOKEY;
>> + if (IS_ERR(keyring))
>> + goto out;
>> +
>> + pkey = keyring->payload.data[asym_crypto];
>
> NAK. This is liable to crash in future. You may not assume that you know
> what keyring->payload.data[asym_crypto] points to.
>
> You may not use struct public_key outside of crypto/asymmetric_key/. It's
> the
> internal data of the software subtype. I'll move it out of the global
> header
> to remove the temptation;-).
>
> You must use accessor functions such as verify_signature(). Feel free to
> add
> further accessor functions such as query_asym_capabilities(),
> create_signature(), encrypt_blob() and decrypt_blob() or something like
> that.
Grr. This is not the first time this has been pointed out. And it
shouldn't have *needed* to be pointed out in the first place.
Please do not ignore review feedback.
Or common sense.
--
dwmw2
> Tadeusz Struk <[email protected]> wrote:
>
>> + keyring = request_key(&key_type_asymmetric, key_name, NULL);
>> +
>> + err = -ENOKEY;
>> + if (IS_ERR(keyring))
>> + goto out;
>> +
>> + pkey = keyring->payload.data[asym_crypto];
>
> NAK. This is liable to crash in future. You may not assume that you know
> what keyring->payload.data[asym_crypto] points to.
>
> You may not use struct public_key outside of crypto/asymmetric_key/. It's
> the
> internal data of the software subtype. I'll move it out of the global
> header
> to remove the temptation;-).
>
> You must use accessor functions such as verify_signature(). Feel free to
> add
> further accessor functions such as query_asym_capabilities(),
> create_signature(), encrypt_blob() and decrypt_blob() or something like
> that.
Grr. This is not the first time this has been pointed out. And it
shouldn't have *needed* to be pointed out in the first place.
Please do not ignore review feedback.
Or common sense.
--
dwmw2
Hi David,
On 03/30/2016 09:31 AM, David Howells wrote:
>> + keyring = request_key(&key_type_asymmetric, key_name, NULL);
>> > +
>> > + err = -ENOKEY;
>> > + if (IS_ERR(keyring))
>> > + goto out;
>> > +
>> > + pkey = keyring->payload.data[asym_crypto];
> NAK. This is liable to crash in future. You may not assume that you know
> what keyring->payload.data[asym_crypto] points to.
>
> You may not use struct public_key outside of crypto/asymmetric_key/. It's the
> internal data of the software subtype. I'll move it out of the global header
> to remove the temptation;-).
>
> You must use accessor functions such as verify_signature(). Feel free to add
> further accessor functions such as query_asym_capabilities(),
> create_signature(), encrypt_blob() and decrypt_blob() or something like that.
Thanks for your response. I thought that the public_key_query_sw_key(pkey)
check was enough for now.
I'll remove public_key stuff from af_alg and add the accessors.
Thanks,
--
TS