Skip to content

Commit 8356b4b

Browse files
committed
libceph: adapt ceph_x_challenge_blob hashing and msgr1 message signing
The existing approach where ceph_x_challenge_blob is encrypted with the client's secret key and then the digest derived from the ciphertext is used for the test doesn't work with CEPH_CRYPTO_AES256KRB5 because the confounder randomizes the ciphertext: the client and the server get two different ciphertexts and therefore two different digests. msgr1 signatures are affected the same way: a digest derived from the ciphertext for the message's "sigblock" is what becomes a signature and the two sides disagree on the expected value. For CEPH_CRYPTO_AES256KRB5 (and potential future encryption schemes), switch to HMAC-SHA256 function keyed in the same way as the existing encryption. For CEPH_CRYPTO_AES, everything is preserved as is. Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
1 parent b7cc142 commit 8356b4b

4 files changed

Lines changed: 72 additions & 23 deletions

File tree

net/ceph/auth_x.c

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -553,8 +553,7 @@ static int ceph_x_build_request(struct ceph_auth_client *ac,
553553
if (need & CEPH_ENTITY_TYPE_AUTH) {
554554
struct ceph_x_authenticate *auth = (void *)(head + 1);
555555
void *enc_buf = xi->auth_authorizer.enc_buf;
556-
struct ceph_x_challenge_blob *blob = enc_buf +
557-
ceph_x_encrypt_offset(&xi->secret);
556+
struct ceph_x_challenge_blob *blob;
558557
u64 *u;
559558

560559
p = auth + 1;
@@ -564,15 +563,29 @@ static int ceph_x_build_request(struct ceph_auth_client *ac,
564563
dout(" get_auth_session_key\n");
565564
head->op = cpu_to_le16(CEPHX_GET_AUTH_SESSION_KEY);
566565

567-
/* encrypt and hash */
566+
if (xi->secret.type == CEPH_CRYPTO_AES) {
567+
blob = enc_buf + ceph_x_encrypt_offset(&xi->secret);
568+
} else {
569+
BUILD_BUG_ON(SHA256_DIGEST_SIZE + sizeof(*blob) >
570+
CEPHX_AU_ENC_BUF_LEN);
571+
blob = enc_buf + SHA256_DIGEST_SIZE;
572+
}
573+
568574
get_random_bytes(&auth->client_challenge, sizeof(u64));
569575
blob->client_challenge = auth->client_challenge;
570576
blob->server_challenge = cpu_to_le64(xi->server_challenge);
571-
ret = ceph_x_encrypt(&xi->secret, 0 /* dummy */,
572-
enc_buf, CEPHX_AU_ENC_BUF_LEN,
573-
sizeof(*blob));
574-
if (ret < 0)
575-
return ret;
577+
578+
if (xi->secret.type == CEPH_CRYPTO_AES) {
579+
ret = ceph_x_encrypt(&xi->secret, 0 /* dummy */,
580+
enc_buf, CEPHX_AU_ENC_BUF_LEN,
581+
sizeof(*blob));
582+
if (ret < 0)
583+
return ret;
584+
} else {
585+
ceph_hmac_sha256(&xi->secret, blob, sizeof(*blob),
586+
enc_buf);
587+
ret = SHA256_DIGEST_SIZE;
588+
}
576589

577590
auth->struct_v = 3; /* nautilus+ */
578591
auth->key = 0;
@@ -1053,11 +1066,19 @@ static int calc_signature(struct ceph_x_authorizer *au, struct ceph_msg *msg,
10531066
__le32 data_crc;
10541067
__le32 data_len;
10551068
__le32 seq_lower_word;
1056-
} __packed *sigblock = enc_buf;
1069+
} __packed *sigblock;
10571070
struct {
10581071
__le64 a, b, c, d;
10591072
} __packed *penc = enc_buf;
1060-
int ciphertext_len;
1073+
1074+
if (au->session_key.type == CEPH_CRYPTO_AES) {
1075+
/* no leading len, no ceph_x_encrypt_header */
1076+
sigblock = enc_buf;
1077+
} else {
1078+
BUILD_BUG_ON(SHA256_DIGEST_SIZE + sizeof(*sigblock) >
1079+
CEPHX_AU_ENC_BUF_LEN);
1080+
sigblock = enc_buf + SHA256_DIGEST_SIZE;
1081+
}
10611082

10621083
sigblock->header_crc = msg->hdr.crc;
10631084
sigblock->front_crc = msg->footer.front_crc;
@@ -1068,12 +1089,18 @@ static int calc_signature(struct ceph_x_authorizer *au, struct ceph_msg *msg,
10681089
sigblock->data_len = msg->hdr.data_len;
10691090
sigblock->seq_lower_word = *(__le32 *)&msg->hdr.seq;
10701091

1071-
/* no leading len, no ceph_x_encrypt_header */
1072-
ret = ceph_crypt(&au->session_key, 0 /* dummy */,
1073-
true, enc_buf, CEPHX_AU_ENC_BUF_LEN,
1074-
sizeof(*sigblock), &ciphertext_len);
1075-
if (ret)
1076-
return ret;
1092+
if (au->session_key.type == CEPH_CRYPTO_AES) {
1093+
int ciphertext_len; /* unused */
1094+
1095+
ret = ceph_crypt(&au->session_key, 0 /* dummy */,
1096+
true, enc_buf, CEPHX_AU_ENC_BUF_LEN,
1097+
sizeof(*sigblock), &ciphertext_len);
1098+
if (ret)
1099+
return ret;
1100+
} else {
1101+
ceph_hmac_sha256(&au->session_key, sigblock,
1102+
sizeof(*sigblock), enc_buf);
1103+
}
10771104

10781105
*psig = penc->a ^ penc->b ^ penc->c ^ penc->d;
10791106
}

net/ceph/crypto.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ int ceph_crypto_key_prepare(struct ceph_crypto_key *key,
8484
case CEPH_CRYPTO_AES:
8585
return set_aes_tfm(key);
8686
case CEPH_CRYPTO_AES256KRB5:
87+
hmac_sha256_preparekey(&key->hmac_key, key->key, key->len);
8788
return set_krb5_tfms(key, key_usages, key_usage_cnt);
8889
default:
8990
return -ENOTSUPP;
@@ -178,6 +179,7 @@ void ceph_crypto_key_destroy(struct ceph_crypto_key *key)
178179
key->aes_tfm = NULL;
179180
}
180181
} else if (key->type == CEPH_CRYPTO_AES256KRB5) {
182+
memzero_explicit(&key->hmac_key, sizeof(key->hmac_key));
181183
for (i = 0; i < ARRAY_SIZE(key->krb5_tfms); i++) {
182184
if (key->krb5_tfms[i]) {
183185
crypto_free_aead(key->krb5_tfms[i]);
@@ -436,6 +438,22 @@ int ceph_crypt_buflen(const struct ceph_crypto_key *key, int data_len)
436438
}
437439
}
438440

441+
void ceph_hmac_sha256(const struct ceph_crypto_key *key, const void *buf,
442+
int buf_len, u8 hmac[SHA256_DIGEST_SIZE])
443+
{
444+
switch (key->type) {
445+
case CEPH_CRYPTO_NONE:
446+
case CEPH_CRYPTO_AES:
447+
memset(hmac, 0, SHA256_DIGEST_SIZE);
448+
return;
449+
case CEPH_CRYPTO_AES256KRB5:
450+
hmac_sha256(&key->hmac_key, buf, buf_len, hmac);
451+
return;
452+
default:
453+
BUG();
454+
}
455+
}
456+
439457
static int ceph_key_preparse(struct key_preparsed_payload *prep)
440458
{
441459
struct ceph_crypto_key *ckey;

net/ceph/crypto.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#ifndef _FS_CEPH_CRYPTO_H
33
#define _FS_CEPH_CRYPTO_H
44

5+
#include <crypto/sha2.h>
56
#include <linux/ceph/types.h>
67
#include <linux/ceph/buffer.h>
78

@@ -20,6 +21,7 @@ struct ceph_crypto_key {
2021
union {
2122
struct crypto_sync_skcipher *aes_tfm;
2223
struct {
24+
struct hmac_sha256_key hmac_key;
2325
const struct krb5_enctype *krb5_type;
2426
struct crypto_aead *krb5_tfms[3];
2527
};
@@ -39,6 +41,8 @@ int ceph_crypt(const struct ceph_crypto_key *key, int usage_slot, bool encrypt,
3941
void *buf, int buf_len, int in_len, int *pout_len);
4042
int ceph_crypt_data_offset(const struct ceph_crypto_key *key);
4143
int ceph_crypt_buflen(const struct ceph_crypto_key *key, int data_len);
44+
void ceph_hmac_sha256(const struct ceph_crypto_key *key, const void *buf,
45+
int buf_len, u8 hmac[SHA256_DIGEST_SIZE]);
4246
int ceph_crypto_init(void);
4347
void ceph_crypto_shutdown(void);
4448

net/ceph/messenger_v2.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -779,9 +779,9 @@ static int setup_crypto(struct ceph_connection *con,
779779
return 0; /* auth_x, secure mode */
780780
}
781781

782-
static void ceph_hmac_sha256(struct ceph_connection *con,
783-
const struct kvec *kvecs, int kvec_cnt,
784-
u8 hmac[SHA256_DIGEST_SIZE])
782+
static void con_hmac_sha256(struct ceph_connection *con,
783+
const struct kvec *kvecs, int kvec_cnt,
784+
u8 hmac[SHA256_DIGEST_SIZE])
785785
{
786786
struct hmac_sha256_ctx ctx;
787787
int i;
@@ -1438,8 +1438,8 @@ static int prepare_auth_signature(struct ceph_connection *con)
14381438
if (!buf)
14391439
return -ENOMEM;
14401440

1441-
ceph_hmac_sha256(con, con->v2.in_sign_kvecs, con->v2.in_sign_kvec_cnt,
1442-
CTRL_BODY(buf));
1441+
con_hmac_sha256(con, con->v2.in_sign_kvecs, con->v2.in_sign_kvec_cnt,
1442+
CTRL_BODY(buf));
14431443

14441444
return prepare_control(con, FRAME_TAG_AUTH_SIGNATURE, buf,
14451445
SHA256_DIGEST_SIZE);
@@ -2436,8 +2436,8 @@ static int process_auth_signature(struct ceph_connection *con,
24362436
return -EINVAL;
24372437
}
24382438

2439-
ceph_hmac_sha256(con, con->v2.out_sign_kvecs, con->v2.out_sign_kvec_cnt,
2440-
hmac);
2439+
con_hmac_sha256(con, con->v2.out_sign_kvecs, con->v2.out_sign_kvec_cnt,
2440+
hmac);
24412441

24422442
ceph_decode_need(&p, end, SHA256_DIGEST_SIZE, bad);
24432443
if (crypto_memneq(p, hmac, SHA256_DIGEST_SIZE)) {

0 commit comments

Comments
 (0)