summaryrefslogtreecommitdiff
path: root/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'crypto')
-rw-r--r--crypto/ahash.c79
-rw-r--r--crypto/algif_aead.c157
-rw-r--r--crypto/gcm.c6
-rw-r--r--crypto/testmgr.c5
4 files changed, 204 insertions, 43 deletions
diff --git a/crypto/ahash.c b/crypto/ahash.c
index dac1c24e9c3e..f9caf0f74199 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -31,6 +31,7 @@ struct ahash_request_priv {
crypto_completion_t complete;
void *data;
u8 *result;
+ u32 flags;
void *ubuf[] CRYPTO_MINALIGN_ATTR;
};
@@ -270,6 +271,8 @@ static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt)
priv->result = req->result;
priv->complete = req->base.complete;
priv->data = req->base.data;
+ priv->flags = req->base.flags;
+
/*
* WARNING: We do not backup req->priv here! The req->priv
* is for internal use of the Crypto API and the
@@ -284,38 +287,44 @@ static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt)
return 0;
}
-static void ahash_restore_req(struct ahash_request *req)
+static void ahash_restore_req(struct ahash_request *req, int err)
{
struct ahash_request_priv *priv = req->priv;
+ if (!err)
+ memcpy(priv->result, req->result,
+ crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
+
/* Restore the original crypto request. */
req->result = priv->result;
- req->base.complete = priv->complete;
- req->base.data = priv->data;
+
+ ahash_request_set_callback(req, priv->flags,
+ priv->complete, priv->data);
req->priv = NULL;
/* Free the req->priv.priv from the ADJUSTED request. */
kzfree(priv);
}
-static void ahash_op_unaligned_finish(struct ahash_request *req, int err)
+static void ahash_notify_einprogress(struct ahash_request *req)
{
struct ahash_request_priv *priv = req->priv;
+ struct crypto_async_request oreq;
- if (err == -EINPROGRESS)
- return;
-
- if (!err)
- memcpy(priv->result, req->result,
- crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
+ oreq.data = priv->data;
- ahash_restore_req(req);
+ priv->complete(&oreq, -EINPROGRESS);
}
static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
{
struct ahash_request *areq = req->data;
+ if (err == -EINPROGRESS) {
+ ahash_notify_einprogress(areq);
+ return;
+ }
+
/*
* Restore the original request, see ahash_op_unaligned() for what
* goes where.
@@ -326,7 +335,7 @@ static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
*/
/* First copy req->result into req->priv.result */
- ahash_op_unaligned_finish(areq, err);
+ ahash_restore_req(areq, err);
/* Complete the ORIGINAL request. */
areq->base.complete(&areq->base, err);
@@ -342,7 +351,12 @@ static int ahash_op_unaligned(struct ahash_request *req,
return err;
err = op(req);
- ahash_op_unaligned_finish(req, err);
+ if (err == -EINPROGRESS ||
+ (err == -EBUSY && (ahash_request_flags(req) &
+ CRYPTO_TFM_REQ_MAY_BACKLOG)))
+ return err;
+
+ ahash_restore_req(req, err);
return err;
}
@@ -377,25 +391,14 @@ int crypto_ahash_digest(struct ahash_request *req)
}
EXPORT_SYMBOL_GPL(crypto_ahash_digest);
-static void ahash_def_finup_finish2(struct ahash_request *req, int err)
+static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
{
- struct ahash_request_priv *priv = req->priv;
+ struct ahash_request *areq = req->data;
if (err == -EINPROGRESS)
return;
- if (!err)
- memcpy(priv->result, req->result,
- crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
-
- ahash_restore_req(req);
-}
-
-static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
-{
- struct ahash_request *areq = req->data;
-
- ahash_def_finup_finish2(areq, err);
+ ahash_restore_req(areq, err);
areq->base.complete(&areq->base, err);
}
@@ -406,11 +409,15 @@ static int ahash_def_finup_finish1(struct ahash_request *req, int err)
goto out;
req->base.complete = ahash_def_finup_done2;
- req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
err = crypto_ahash_reqtfm(req)->final(req);
+ if (err == -EINPROGRESS ||
+ (err == -EBUSY && (ahash_request_flags(req) &
+ CRYPTO_TFM_REQ_MAY_BACKLOG)))
+ return err;
out:
- ahash_def_finup_finish2(req, err);
+ ahash_restore_req(req, err);
return err;
}
@@ -418,7 +425,16 @@ static void ahash_def_finup_done1(struct crypto_async_request *req, int err)
{
struct ahash_request *areq = req->data;
+ if (err == -EINPROGRESS) {
+ ahash_notify_einprogress(areq);
+ return;
+ }
+
+ areq->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
err = ahash_def_finup_finish1(areq, err);
+ if (areq->priv)
+ return;
areq->base.complete(&areq->base, err);
}
@@ -433,6 +449,11 @@ static int ahash_def_finup(struct ahash_request *req)
return err;
err = tfm->update(req);
+ if (err == -EINPROGRESS ||
+ (err == -EBUSY && (ahash_request_flags(req) &
+ CRYPTO_TFM_REQ_MAY_BACKLOG)))
+ return err;
+
return ahash_def_finup_finish1(req, err);
}
diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
index 6d4d4569447e..faea9d728fd2 100644
--- a/crypto/algif_aead.c
+++ b/crypto/algif_aead.c
@@ -29,6 +29,11 @@ struct aead_sg_list {
struct scatterlist sg[ALG_MAX_PAGES];
};
+struct aead_tfm {
+ struct crypto_aead *aead;
+ bool has_key;
+};
+
struct aead_ctx {
struct aead_sg_list tsgl;
/*
@@ -513,24 +518,146 @@ static struct proto_ops algif_aead_ops = {
.poll = aead_poll,
};
+static int aead_check_key(struct socket *sock)
+{
+ int err = 0;
+ struct sock *psk;
+ struct alg_sock *pask;
+ struct aead_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 aead_sendmsg_nokey(struct socket *sock, struct msghdr *msg,
+ size_t size)
+{
+ int err;
+
+ err = aead_check_key(sock);
+ if (err)
+ return err;
+
+ return aead_sendmsg(sock, msg, size);
+}
+
+static ssize_t aead_sendpage_nokey(struct socket *sock, struct page *page,
+ int offset, size_t size, int flags)
+{
+ int err;
+
+ err = aead_check_key(sock);
+ if (err)
+ return err;
+
+ return aead_sendpage(sock, page, offset, size, flags);
+}
+
+static int aead_recvmsg_nokey(struct socket *sock, struct msghdr *msg,
+ size_t ignored, int flags)
+{
+ int err;
+
+ err = aead_check_key(sock);
+ if (err)
+ return err;
+
+ return aead_recvmsg(sock, msg, ignored, flags);
+}
+
+static struct proto_ops algif_aead_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 = aead_sendmsg_nokey,
+ .sendpage = aead_sendpage_nokey,
+ .recvmsg = aead_recvmsg_nokey,
+ .poll = aead_poll,
+};
+
static void *aead_bind(const char *name, u32 type, u32 mask)
{
- return crypto_alloc_aead(name, type, mask);
+ struct aead_tfm *tfm;
+ struct crypto_aead *aead;
+
+ tfm = kzalloc(sizeof(*tfm), GFP_KERNEL);
+ if (!tfm)
+ return ERR_PTR(-ENOMEM);
+
+ aead = crypto_alloc_aead(name, type, mask);
+ if (IS_ERR(aead)) {
+ kfree(tfm);
+ return ERR_CAST(aead);
+ }
+
+ tfm->aead = aead;
+
+ return tfm;
}
static void aead_release(void *private)
{
- crypto_free_aead(private);
+ struct aead_tfm *tfm = private;
+
+ crypto_free_aead(tfm->aead);
+ kfree(tfm);
}
static int aead_setauthsize(void *private, unsigned int authsize)
{
- return crypto_aead_setauthsize(private, authsize);
+ struct aead_tfm *tfm = private;
+
+ return crypto_aead_setauthsize(tfm->aead, authsize);
}
static int aead_setkey(void *private, const u8 *key, unsigned int keylen)
{
- return crypto_aead_setkey(private, key, keylen);
+ struct aead_tfm *tfm = private;
+ int err;
+
+ err = crypto_aead_setkey(tfm->aead, key, keylen);
+ tfm->has_key = !err;
+
+ return err;
}
static void aead_sock_destruct(struct sock *sk)
@@ -546,12 +673,14 @@ static void aead_sock_destruct(struct sock *sk)
af_alg_release_parent(sk);
}
-static int aead_accept_parent(void *private, struct sock *sk)
+static int aead_accept_parent_nokey(void *private, struct sock *sk)
{
struct aead_ctx *ctx;
struct alg_sock *ask = alg_sk(sk);
- unsigned int len = sizeof(*ctx) + crypto_aead_reqsize(private);
- unsigned int ivlen = crypto_aead_ivsize(private);
+ struct aead_tfm *tfm = private;
+ struct crypto_aead *aead = tfm->aead;
+ unsigned int len = sizeof(*ctx) + crypto_aead_reqsize(aead);
+ unsigned int ivlen = crypto_aead_ivsize(aead);
ctx = sock_kmalloc(sk, len, GFP_KERNEL);
if (!ctx)
@@ -577,7 +706,7 @@ static int aead_accept_parent(void *private, struct sock *sk)
ask->private = ctx;
- aead_request_set_tfm(&ctx->aead_req, private);
+ aead_request_set_tfm(&ctx->aead_req, aead);
aead_request_set_callback(&ctx->aead_req, CRYPTO_TFM_REQ_MAY_BACKLOG,
af_alg_complete, &ctx->completion);
@@ -586,13 +715,25 @@ static int aead_accept_parent(void *private, struct sock *sk)
return 0;
}
+static int aead_accept_parent(void *private, struct sock *sk)
+{
+ struct aead_tfm *tfm = private;
+
+ if (!tfm->has_key)
+ return -ENOKEY;
+
+ return aead_accept_parent_nokey(private, sk);
+}
+
static const struct af_alg_type algif_type_aead = {
.bind = aead_bind,
.release = aead_release,
.setkey = aead_setkey,
.setauthsize = aead_setauthsize,
.accept = aead_accept_parent,
+ .accept_nokey = aead_accept_parent_nokey,
.ops = &algif_aead_ops,
+ .ops_nokey = &algif_aead_ops_nokey,
.name = "aead",
.owner = THIS_MODULE
};
diff --git a/crypto/gcm.c b/crypto/gcm.c
index 1238b3c5a321..0a12c09d7cb2 100644
--- a/crypto/gcm.c
+++ b/crypto/gcm.c
@@ -152,10 +152,8 @@ static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key,
err = crypto_ablkcipher_encrypt(&data->req);
if (err == -EINPROGRESS || err == -EBUSY) {
- err = wait_for_completion_interruptible(
- &data->result.completion);
- if (!err)
- err = data->result.err;
+ wait_for_completion(&data->result.completion);
+ err = data->result.err;
}
if (err)
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index d4944318ca1f..5f15f45fcc9f 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -488,6 +488,8 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
tcrypt_complete, &result);
+ iv_len = crypto_aead_ivsize(tfm);
+
for (i = 0, j = 0; i < tcount; i++) {
if (template[i].np)
continue;
@@ -508,7 +510,6 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
memcpy(input, template[i].input, template[i].ilen);
memcpy(assoc, template[i].assoc, template[i].alen);
- iv_len = crypto_aead_ivsize(tfm);
if (template[i].iv)
memcpy(iv, template[i].iv, iv_len);
else
@@ -617,7 +618,7 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
j++;
if (template[i].iv)
- memcpy(iv, template[i].iv, MAX_IVLEN);
+ memcpy(iv, template[i].iv, iv_len);
else
memset(iv, 0, MAX_IVLEN);