mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
libceph: zero out session key and connection secret
Try and avoid leaving bits and pieces of session key and connection secret (gets split into GCM key and a pair of GCM IVs) around. Signed-off-by: Ilya Dryomov <idryomov@gmail.com> Reviewed-by: Jeff Layton <jlayton@kernel.org>
This commit is contained in:
@@ -569,6 +569,34 @@ e_range:
|
|||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int decode_con_secret(void **p, void *end, u8 *con_secret,
|
||||||
|
int *con_secret_len)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
ceph_decode_32_safe(p, end, len, bad);
|
||||||
|
ceph_decode_need(p, end, len, bad);
|
||||||
|
|
||||||
|
dout("%s len %d\n", __func__, len);
|
||||||
|
if (con_secret) {
|
||||||
|
if (len > CEPH_MAX_CON_SECRET_LEN) {
|
||||||
|
pr_err("connection secret too big %d\n", len);
|
||||||
|
goto bad_memzero;
|
||||||
|
}
|
||||||
|
memcpy(con_secret, *p, len);
|
||||||
|
*con_secret_len = len;
|
||||||
|
}
|
||||||
|
memzero_explicit(*p, len);
|
||||||
|
*p += len;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bad_memzero:
|
||||||
|
memzero_explicit(*p, len);
|
||||||
|
bad:
|
||||||
|
pr_err("failed to decode connection secret\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
static int handle_auth_session_key(struct ceph_auth_client *ac,
|
static int handle_auth_session_key(struct ceph_auth_client *ac,
|
||||||
void **p, void *end,
|
void **p, void *end,
|
||||||
u8 *session_key, int *session_key_len,
|
u8 *session_key, int *session_key_len,
|
||||||
@@ -612,17 +640,9 @@ static int handle_auth_session_key(struct ceph_auth_client *ac,
|
|||||||
dout("%s decrypted %d bytes\n", __func__, ret);
|
dout("%s decrypted %d bytes\n", __func__, ret);
|
||||||
dend = dp + ret;
|
dend = dp + ret;
|
||||||
|
|
||||||
ceph_decode_32_safe(&dp, dend, len, e_inval);
|
ret = decode_con_secret(&dp, dend, con_secret, con_secret_len);
|
||||||
if (len > CEPH_MAX_CON_SECRET_LEN) {
|
if (ret)
|
||||||
pr_err("connection secret too big %d\n", len);
|
return ret;
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dout("%s connection secret len %d\n", __func__, len);
|
|
||||||
if (con_secret) {
|
|
||||||
memcpy(con_secret, dp, len);
|
|
||||||
*con_secret_len = len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* service tickets */
|
/* service tickets */
|
||||||
@@ -828,7 +848,6 @@ static int decrypt_authorizer_reply(struct ceph_crypto_key *secret,
|
|||||||
{
|
{
|
||||||
void *dp, *dend;
|
void *dp, *dend;
|
||||||
u8 struct_v;
|
u8 struct_v;
|
||||||
int len;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dp = *p + ceph_x_encrypt_offset();
|
dp = *p + ceph_x_encrypt_offset();
|
||||||
@@ -843,17 +862,9 @@ static int decrypt_authorizer_reply(struct ceph_crypto_key *secret,
|
|||||||
ceph_decode_64_safe(&dp, dend, *nonce_plus_one, e_inval);
|
ceph_decode_64_safe(&dp, dend, *nonce_plus_one, e_inval);
|
||||||
dout("%s nonce_plus_one %llu\n", __func__, *nonce_plus_one);
|
dout("%s nonce_plus_one %llu\n", __func__, *nonce_plus_one);
|
||||||
if (struct_v >= 2) {
|
if (struct_v >= 2) {
|
||||||
ceph_decode_32_safe(&dp, dend, len, e_inval);
|
ret = decode_con_secret(&dp, dend, con_secret, con_secret_len);
|
||||||
if (len > CEPH_MAX_CON_SECRET_LEN) {
|
if (ret)
|
||||||
pr_err("connection secret too big %d\n", len);
|
return ret;
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dout("%s connection secret len %d\n", __func__, len);
|
|
||||||
if (con_secret) {
|
|
||||||
memcpy(con_secret, dp, len);
|
|
||||||
*con_secret_len = len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -96,6 +96,7 @@ int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end)
|
|||||||
key->len = ceph_decode_16(p);
|
key->len = ceph_decode_16(p);
|
||||||
ceph_decode_need(p, end, key->len, bad);
|
ceph_decode_need(p, end, key->len, bad);
|
||||||
ret = set_secret(key, *p);
|
ret = set_secret(key, *p);
|
||||||
|
memzero_explicit(*p, key->len);
|
||||||
*p += key->len;
|
*p += key->len;
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -134,7 +135,7 @@ int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey)
|
|||||||
void ceph_crypto_key_destroy(struct ceph_crypto_key *key)
|
void ceph_crypto_key_destroy(struct ceph_crypto_key *key)
|
||||||
{
|
{
|
||||||
if (key) {
|
if (key) {
|
||||||
kfree(key->key);
|
kfree_sensitive(key->key);
|
||||||
key->key = NULL;
|
key->key = NULL;
|
||||||
if (key->tfm) {
|
if (key->tfm) {
|
||||||
crypto_free_sync_skcipher(key->tfm);
|
crypto_free_sync_skcipher(key->tfm);
|
||||||
|
@@ -689,11 +689,10 @@ static int verify_epilogue_crcs(struct ceph_connection *con, u32 front_crc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int setup_crypto(struct ceph_connection *con,
|
static int setup_crypto(struct ceph_connection *con,
|
||||||
u8 *session_key, int session_key_len,
|
const u8 *session_key, int session_key_len,
|
||||||
u8 *con_secret, int con_secret_len)
|
const u8 *con_secret, int con_secret_len)
|
||||||
{
|
{
|
||||||
unsigned int noio_flag;
|
unsigned int noio_flag;
|
||||||
void *p;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dout("%s con %p con_mode %d session_key_len %d con_secret_len %d\n",
|
dout("%s con %p con_mode %d session_key_len %d con_secret_len %d\n",
|
||||||
@@ -751,15 +750,14 @@ static int setup_crypto(struct ceph_connection *con,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = con_secret;
|
WARN_ON((unsigned long)con_secret &
|
||||||
WARN_ON((unsigned long)p & crypto_aead_alignmask(con->v2.gcm_tfm));
|
crypto_aead_alignmask(con->v2.gcm_tfm));
|
||||||
ret = crypto_aead_setkey(con->v2.gcm_tfm, p, CEPH_GCM_KEY_LEN);
|
ret = crypto_aead_setkey(con->v2.gcm_tfm, con_secret, CEPH_GCM_KEY_LEN);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("failed to set gcm key: %d\n", ret);
|
pr_err("failed to set gcm key: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
p += CEPH_GCM_KEY_LEN;
|
|
||||||
WARN_ON(crypto_aead_ivsize(con->v2.gcm_tfm) != CEPH_GCM_IV_LEN);
|
WARN_ON(crypto_aead_ivsize(con->v2.gcm_tfm) != CEPH_GCM_IV_LEN);
|
||||||
ret = crypto_aead_setauthsize(con->v2.gcm_tfm, CEPH_GCM_TAG_LEN);
|
ret = crypto_aead_setauthsize(con->v2.gcm_tfm, CEPH_GCM_TAG_LEN);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -777,8 +775,11 @@ static int setup_crypto(struct ceph_connection *con,
|
|||||||
aead_request_set_callback(con->v2.gcm_req, CRYPTO_TFM_REQ_MAY_BACKLOG,
|
aead_request_set_callback(con->v2.gcm_req, CRYPTO_TFM_REQ_MAY_BACKLOG,
|
||||||
crypto_req_done, &con->v2.gcm_wait);
|
crypto_req_done, &con->v2.gcm_wait);
|
||||||
|
|
||||||
memcpy(&con->v2.in_gcm_nonce, p, CEPH_GCM_IV_LEN);
|
memcpy(&con->v2.in_gcm_nonce, con_secret + CEPH_GCM_KEY_LEN,
|
||||||
memcpy(&con->v2.out_gcm_nonce, p + CEPH_GCM_IV_LEN, CEPH_GCM_IV_LEN);
|
CEPH_GCM_IV_LEN);
|
||||||
|
memcpy(&con->v2.out_gcm_nonce,
|
||||||
|
con_secret + CEPH_GCM_KEY_LEN + CEPH_GCM_IV_LEN,
|
||||||
|
CEPH_GCM_IV_LEN);
|
||||||
return 0; /* auth_x, secure mode */
|
return 0; /* auth_x, secure mode */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -800,7 +801,7 @@ static int hmac_sha256(struct ceph_connection *con, const struct kvec *kvecs,
|
|||||||
desc->tfm = con->v2.hmac_tfm;
|
desc->tfm = con->v2.hmac_tfm;
|
||||||
ret = crypto_shash_init(desc);
|
ret = crypto_shash_init(desc);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto out;
|
||||||
|
|
||||||
for (i = 0; i < kvec_cnt; i++) {
|
for (i = 0; i < kvec_cnt; i++) {
|
||||||
WARN_ON((unsigned long)kvecs[i].iov_base &
|
WARN_ON((unsigned long)kvecs[i].iov_base &
|
||||||
@@ -808,15 +809,14 @@ static int hmac_sha256(struct ceph_connection *con, const struct kvec *kvecs,
|
|||||||
ret = crypto_shash_update(desc, kvecs[i].iov_base,
|
ret = crypto_shash_update(desc, kvecs[i].iov_base,
|
||||||
kvecs[i].iov_len);
|
kvecs[i].iov_len);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = crypto_shash_final(desc, hmac);
|
ret = crypto_shash_final(desc, hmac);
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
|
out:
|
||||||
shash_desc_zero(desc);
|
shash_desc_zero(desc);
|
||||||
return 0; /* auth_x, both plain and secure modes */
|
return ret; /* auth_x, both plain and secure modes */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gcm_inc_nonce(struct ceph_gcm_nonce *nonce)
|
static void gcm_inc_nonce(struct ceph_gcm_nonce *nonce)
|
||||||
@@ -2072,27 +2072,32 @@ static int process_auth_done(struct ceph_connection *con, void *p, void *end)
|
|||||||
if (con->state != CEPH_CON_S_V2_AUTH) {
|
if (con->state != CEPH_CON_S_V2_AUTH) {
|
||||||
dout("%s con %p state changed to %d\n", __func__, con,
|
dout("%s con %p state changed to %d\n", __func__, con,
|
||||||
con->state);
|
con->state);
|
||||||
return -EAGAIN;
|
ret = -EAGAIN;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
dout("%s con %p handle_auth_done ret %d\n", __func__, con, ret);
|
dout("%s con %p handle_auth_done ret %d\n", __func__, con, ret);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto out;
|
||||||
|
|
||||||
ret = setup_crypto(con, session_key, session_key_len, con_secret,
|
ret = setup_crypto(con, session_key, session_key_len, con_secret,
|
||||||
con_secret_len);
|
con_secret_len);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto out;
|
||||||
|
|
||||||
reset_out_kvecs(con);
|
reset_out_kvecs(con);
|
||||||
ret = prepare_auth_signature(con);
|
ret = prepare_auth_signature(con);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("prepare_auth_signature failed: %d\n", ret);
|
pr_err("prepare_auth_signature failed: %d\n", ret);
|
||||||
return ret;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
con->state = CEPH_CON_S_V2_AUTH_SIGNATURE;
|
con->state = CEPH_CON_S_V2_AUTH_SIGNATURE;
|
||||||
return 0;
|
|
||||||
|
out:
|
||||||
|
memzero_explicit(session_key_buf, sizeof(session_key_buf));
|
||||||
|
memzero_explicit(con_secret_buf, sizeof(con_secret_buf));
|
||||||
|
return ret;
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
pr_err("failed to decode auth_done\n");
|
pr_err("failed to decode auth_done\n");
|
||||||
@@ -3436,6 +3441,8 @@ void ceph_con_v2_reset_protocol(struct ceph_connection *con)
|
|||||||
}
|
}
|
||||||
|
|
||||||
con->v2.con_mode = CEPH_CON_MODE_UNKNOWN;
|
con->v2.con_mode = CEPH_CON_MODE_UNKNOWN;
|
||||||
|
memzero_explicit(&con->v2.in_gcm_nonce, CEPH_GCM_IV_LEN);
|
||||||
|
memzero_explicit(&con->v2.out_gcm_nonce, CEPH_GCM_IV_LEN);
|
||||||
|
|
||||||
if (con->v2.hmac_tfm) {
|
if (con->v2.hmac_tfm) {
|
||||||
crypto_free_shash(con->v2.hmac_tfm);
|
crypto_free_shash(con->v2.hmac_tfm);
|
||||||
|
Reference in New Issue
Block a user