mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
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>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user