Commit 6cec0b61 authored by Ilya Dryomov's avatar Ilya Dryomov
Browse files

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: default avatarIlya Dryomov <idryomov@gmail.com>
parent 0ee8bccf
Loading
Loading
Loading
Loading
+20 −6
Original line number Diff line number Diff line
@@ -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;
}
+35 −36
Original line number Diff line number Diff line
@@ -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;

+1 −0
Original line number Diff line number Diff line
@@ -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);