summaryrefslogtreecommitdiff
path: root/net/ceph
diff options
context:
space:
mode:
authorIlya Dryomov <idryomov@gmail.com>2025-12-22 19:44:24 +0100
committerIlya Dryomov <idryomov@gmail.com>2026-02-09 12:29:22 +0100
commit6cec0b61aacce4da5125b21c718189f0dc11eb51 (patch)
tree1ba4fdee07a51e85a1653f2bdd69ad8cd97d6292 /net/ceph
parent0ee8bccf7396d50726c9c8dd3135fb64a9fe8426 (diff)
libceph: introduce ceph_crypto_key_prepare()
In preparation for bringing in a new encryption scheme/key type, decouple decoding or cloning the key from allocating required crypto API objects and setting them up. The rationale is that a) in some cases a shallow clone is sufficient and b) ceph_crypto_key_prepare() may grow additional parameters that would be inconvenient to provide at the point the key is originally decoded. Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'net/ceph')
-rw-r--r--net/ceph/auth_x.c26
-rw-r--r--net/ceph/crypto.c71
-rw-r--r--net/ceph/crypto.h1
3 files changed, 56 insertions, 42 deletions
diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c
index 5d7245884f95..abdd35be263a 100644
--- a/net/ceph/auth_x.c
+++ b/net/ceph/auth_x.c
@@ -221,6 +221,10 @@ static int process_one_ticket(struct ceph_auth_client *ac,
if (ret)
goto out;
+ ret = ceph_crypto_key_prepare(&new_session_key);
+ if (ret)
+ goto out;
+
ceph_decode_need(&dp, dend, sizeof(struct ceph_timespec), bad);
ceph_decode_timespec64(&validity, dp);
dp += sizeof(struct ceph_timespec);
@@ -380,6 +384,10 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
if (ret)
goto out_au;
+ ret = ceph_crypto_key_prepare(&au->session_key);
+ if (ret)
+ goto out_au;
+
maxlen = sizeof(*msg_a) + ticket_blob_len +
ceph_x_encrypt_buflen(&au->session_key, sizeof(*msg_b));
dout(" need len %d\n", maxlen);
@@ -1106,21 +1114,26 @@ int ceph_x_init(struct ceph_auth_client *ac)
int ret;
dout("ceph_x_init %p\n", ac);
- ret = -ENOMEM;
xi = kzalloc(sizeof(*xi), GFP_NOFS);
if (!xi)
- goto out;
+ return -ENOMEM;
ret = -EINVAL;
if (!ac->key) {
pr_err("no secret set (for auth_x protocol)\n");
- goto out_nomem;
+ goto err_xi;
}
ret = ceph_crypto_key_clone(&xi->secret, ac->key);
if (ret < 0) {
pr_err("cannot clone key: %d\n", ret);
- goto out_nomem;
+ goto err_xi;
+ }
+
+ ret = ceph_crypto_key_prepare(&xi->secret);
+ if (ret) {
+ pr_err("cannot prepare key: %d\n", ret);
+ goto err_secret;
}
xi->starting = true;
@@ -1131,8 +1144,9 @@ int ceph_x_init(struct ceph_auth_client *ac)
ac->ops = &ceph_x_ops;
return 0;
-out_nomem:
+err_secret:
+ ceph_crypto_key_destroy(&xi->secret);
+err_xi:
kfree(xi);
-out:
return ret;
}
diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c
index 2b98daffe9af..3453dc303315 100644
--- a/net/ceph/crypto.c
+++ b/net/ceph/crypto.c
@@ -16,65 +16,61 @@
#include <linux/ceph/decode.h>
#include "crypto.h"
-/*
- * Set ->key and ->tfm. The rest of the key should be filled in before
- * this function is called.
- */
-static int set_secret(struct ceph_crypto_key *key, void *buf)
+static int set_aes_tfm(struct ceph_crypto_key *key)
{
unsigned int noio_flag;
int ret;
- key->key = NULL;
- key->tfm = NULL;
-
- switch (key->type) {
- case CEPH_CRYPTO_NONE:
- return 0; /* nothing to do */
- case CEPH_CRYPTO_AES:
- break;
- default:
- return -ENOTSUPP;
- }
-
- key->key = kmemdup(buf, key->len, GFP_NOIO);
- if (!key->key) {
- ret = -ENOMEM;
- goto fail;
- }
-
- /* crypto_alloc_sync_skcipher() allocates with GFP_KERNEL */
noio_flag = memalloc_noio_save();
key->tfm = crypto_alloc_sync_skcipher("cbc(aes)", 0, 0);
memalloc_noio_restore(noio_flag);
if (IS_ERR(key->tfm)) {
ret = PTR_ERR(key->tfm);
key->tfm = NULL;
- goto fail;
+ return ret;
}
ret = crypto_sync_skcipher_setkey(key->tfm, key->key, key->len);
if (ret)
- goto fail;
+ return ret;
return 0;
+}
-fail:
- ceph_crypto_key_destroy(key);
- return ret;
+int ceph_crypto_key_prepare(struct ceph_crypto_key *key)
+{
+ switch (key->type) {
+ case CEPH_CRYPTO_NONE:
+ return 0; /* nothing to do */
+ case CEPH_CRYPTO_AES:
+ return set_aes_tfm(key);
+ default:
+ return -ENOTSUPP;
+ }
}
+/*
+ * @dst should be zeroed before this function is called.
+ */
int ceph_crypto_key_clone(struct ceph_crypto_key *dst,
const struct ceph_crypto_key *src)
{
- memcpy(dst, src, sizeof(struct ceph_crypto_key));
- return set_secret(dst, src->key);
+ dst->type = src->type;
+ dst->created = src->created;
+ dst->len = src->len;
+
+ dst->key = kmemdup(src->key, src->len, GFP_NOIO);
+ if (!dst->key)
+ return -ENOMEM;
+
+ return 0;
}
+/*
+ * @key should be zeroed before this function is called.
+ */
int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end)
{
- int ret;
-
ceph_decode_need(p, end, 2*sizeof(u16) + sizeof(key->created), bad);
key->type = ceph_decode_16(p);
ceph_decode_copy(p, &key->created, sizeof(key->created));
@@ -85,10 +81,13 @@ int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end)
return -EINVAL;
}
- ret = set_secret(key, *p);
+ key->key = kmemdup(*p, key->len, GFP_NOIO);
+ if (!key->key)
+ return -ENOMEM;
+
memzero_explicit(*p, key->len);
*p += key->len;
- return ret;
+ return 0;
bad:
dout("failed to decode crypto key\n");
@@ -322,7 +321,7 @@ static int ceph_key_preparse(struct key_preparsed_payload *prep)
goto err;
ret = -ENOMEM;
- ckey = kmalloc(sizeof(*ckey), GFP_KERNEL);
+ ckey = kzalloc(sizeof(*ckey), GFP_KERNEL);
if (!ckey)
goto err;
diff --git a/net/ceph/crypto.h b/net/ceph/crypto.h
index 736ec6d2fbcb..2b8f8f68ff7a 100644
--- a/net/ceph/crypto.h
+++ b/net/ceph/crypto.h
@@ -19,6 +19,7 @@ struct ceph_crypto_key {
struct crypto_sync_skcipher *tfm;
};
+int ceph_crypto_key_prepare(struct ceph_crypto_key *key);
int ceph_crypto_key_clone(struct ceph_crypto_key *dst,
const struct ceph_crypto_key *src);
int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end);