libceph, ceph: incorporate nautilus cephx changes
authorIlya Dryomov <idryomov@gmail.com>
Mon, 26 Oct 2020 15:47:20 +0000 (16:47 +0100)
committerIlya Dryomov <idryomov@gmail.com>
Mon, 14 Dec 2020 22:21:50 +0000 (23:21 +0100)
- request service tickets together with auth ticket.  Currently we get
  auth ticket via CEPHX_GET_AUTH_SESSION_KEY op and then request service
  tickets via CEPHX_GET_PRINCIPAL_SESSION_KEY op in a separate message.
  Since nautilus, desired service tickets are shared togther with auth
  ticket in CEPHX_GET_AUTH_SESSION_KEY reply.

- propagate session key and connection secret, if any.  In preparation
  for msgr2, update handle_reply() and verify_authorizer_reply() auth
  ops to propagate session key and connection secret.  Since nautilus,
  if secure mode is negotiated, connection secret is shared either in
  CEPHX_GET_AUTH_SESSION_KEY reply (for mons) or in a final authorizer
  reply (for osds and mdses).

Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/mds_client.c
include/linux/ceph/auth.h
net/ceph/auth.c
net/ceph/auth_none.c
net/ceph/auth_x.c
net/ceph/auth_x_protocol.h
net/ceph/crypto.h
net/ceph/osd_client.c

index a256d95..278fe67 100644 (file)
@@ -5178,8 +5178,11 @@ static int verify_authorizer_reply(struct ceph_connection *con)
        struct ceph_mds_session *s = con->private;
        struct ceph_mds_client *mdsc = s->s_mdsc;
        struct ceph_auth_client *ac = mdsc->fsc->client->monc.auth;
+       struct ceph_auth_handshake *auth = &s->s_auth;
 
-       return ceph_auth_verify_authorizer_reply(ac, s->s_auth.authorizer);
+       return ceph_auth_verify_authorizer_reply(ac, auth->authorizer,
+               auth->authorizer_reply_buf, auth->authorizer_reply_buf_len,
+               NULL, NULL, NULL, NULL);
 }
 
 static int invalidate_authorizer(struct ceph_connection *con)
index 6728c2e..d9e7d0b 100644 (file)
@@ -53,7 +53,9 @@ struct ceph_auth_client_ops {
         */
        int (*build_request)(struct ceph_auth_client *ac, void *buf, void *end);
        int (*handle_reply)(struct ceph_auth_client *ac, int result,
-                           void *buf, void *end);
+                           void *buf, void *end, u8 *session_key,
+                           int *session_key_len, u8 *con_secret,
+                           int *con_secret_len);
 
        /*
         * Create authorizer for connecting to a service, and verify
@@ -69,7 +71,10 @@ struct ceph_auth_client_ops {
                                        void *challenge_buf,
                                        int challenge_buf_len);
        int (*verify_authorizer_reply)(struct ceph_auth_client *ac,
-                                      struct ceph_authorizer *a);
+                                      struct ceph_authorizer *a,
+                                      void *reply, int reply_len,
+                                      u8 *session_key, int *session_key_len,
+                                      u8 *con_secret, int *con_secret_len);
        void (*invalidate_authorizer)(struct ceph_auth_client *ac,
                                      int peer_type);
 
@@ -126,8 +131,11 @@ int ceph_auth_add_authorizer_challenge(struct ceph_auth_client *ac,
                                       struct ceph_authorizer *a,
                                       void *challenge_buf,
                                       int challenge_buf_len);
-extern int ceph_auth_verify_authorizer_reply(struct ceph_auth_client *ac,
-                                            struct ceph_authorizer *a);
+int ceph_auth_verify_authorizer_reply(struct ceph_auth_client *ac,
+                                     struct ceph_authorizer *a,
+                                     void *reply, int reply_len,
+                                     u8 *session_key, int *session_key_len,
+                                     u8 *con_secret, int *con_secret_len);
 extern void ceph_auth_invalidate_authorizer(struct ceph_auth_client *ac,
                                            int peer_type);
 
index fbeee06..40d3d95 100644 (file)
@@ -240,7 +240,8 @@ int ceph_handle_auth_reply(struct ceph_auth_client *ac,
                ac->negotiating = false;
        }
 
-       ret = ac->ops->handle_reply(ac, result, payload, payload_end);
+       ret = ac->ops->handle_reply(ac, result, payload, payload_end,
+                                   NULL, NULL, NULL, NULL);
        if (ret == -EAGAIN) {
                ret = ceph_build_auth_request(ac, reply_buf, reply_len);
        } else if (ret) {
@@ -332,13 +333,18 @@ int ceph_auth_add_authorizer_challenge(struct ceph_auth_client *ac,
 EXPORT_SYMBOL(ceph_auth_add_authorizer_challenge);
 
 int ceph_auth_verify_authorizer_reply(struct ceph_auth_client *ac,
-                                     struct ceph_authorizer *a)
+                                     struct ceph_authorizer *a,
+                                     void *reply, int reply_len,
+                                     u8 *session_key, int *session_key_len,
+                                     u8 *con_secret, int *con_secret_len)
 {
        int ret = 0;
 
        mutex_lock(&ac->mutex);
        if (ac->ops && ac->ops->verify_authorizer_reply)
-               ret = ac->ops->verify_authorizer_reply(ac, a);
+               ret = ac->ops->verify_authorizer_reply(ac, a,
+                       reply, reply_len, session_key, session_key_len,
+                       con_secret, con_secret_len);
        mutex_unlock(&ac->mutex);
        return ret;
 }
index edb7042..af8ae50 100644 (file)
@@ -70,7 +70,9 @@ static int build_request(struct ceph_auth_client *ac, void *buf, void *end)
  * authenticate state, so nothing happens here.
  */
 static int handle_reply(struct ceph_auth_client *ac, int result,
-                       void *buf, void *end)
+                       void *buf, void *end, u8 *session_key,
+                       int *session_key_len, u8 *con_secret,
+                       int *con_secret_len)
 {
        struct ceph_auth_none_info *xi = ac->private;
 
index 425508d..a265792 100644 (file)
@@ -269,22 +269,21 @@ out:
 
 static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
                                    struct ceph_crypto_key *secret,
-                                   void *buf, void *end)
+                                   void **p, void *end)
 {
-       void *p = buf;
        u8 reply_struct_v;
        u32 num;
        int ret;
 
-       ceph_decode_8_safe(&p, end, reply_struct_v, bad);
+       ceph_decode_8_safe(p, end, reply_struct_v, bad);
        if (reply_struct_v != 1)
                return -EINVAL;
 
-       ceph_decode_32_safe(&p, end, num, bad);
+       ceph_decode_32_safe(p, end, num, bad);
        dout("%d tickets\n", num);
 
        while (num--) {
-               ret = process_one_ticket(ac, secret, &p, end);
+               ret = process_one_ticket(ac, secret, p, end);
                if (ret)
                        return ret;
        }
@@ -527,7 +526,7 @@ static int ceph_x_build_request(struct ceph_auth_client *ac,
                if (ret < 0)
                        return ret;
 
-               auth->struct_v = 1;
+               auth->struct_v = 2;  /* nautilus+ */
                auth->key = 0;
                for (u = (u64 *)enc_buf; u + 1 <= (u64 *)(enc_buf + ret); u++)
                        auth->key ^= *(__le64 *)u;
@@ -540,6 +539,10 @@ static int ceph_x_build_request(struct ceph_auth_client *ac,
                if (ret < 0)
                        return ret;
 
+               /* nautilus+: request service tickets at the same time */
+               need = ac->want_keys & ~CEPH_ENTITY_TYPE_AUTH;
+               WARN_ON(!need);
+               ceph_encode_32_safe(&p, end, need, e_range);
                return p - buf;
        }
 
@@ -566,8 +569,82 @@ e_range:
        return -ERANGE;
 }
 
+static int handle_auth_session_key(struct ceph_auth_client *ac,
+                                  void **p, void *end,
+                                  u8 *session_key, int *session_key_len,
+                                  u8 *con_secret, int *con_secret_len)
+{
+       struct ceph_x_info *xi = ac->private;
+       struct ceph_x_ticket_handler *th;
+       void *dp, *dend;
+       int len;
+       int ret;
+
+       /* AUTH ticket */
+       ret = ceph_x_proc_ticket_reply(ac, &xi->secret, p, end);
+       if (ret)
+               return ret;
+
+       if (*p == end) {
+               /* pre-nautilus (or didn't request service tickets!) */
+               WARN_ON(session_key || con_secret);
+               return 0;
+       }
+
+       th = get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH);
+       if (IS_ERR(th))
+               return PTR_ERR(th);
+
+       if (session_key) {
+               memcpy(session_key, th->session_key.key, th->session_key.len);
+               *session_key_len = th->session_key.len;
+       }
+
+       /* connection secret */
+       ceph_decode_32_safe(p, end, len, e_inval);
+       dout("%s connection secret blob len %d\n", __func__, len);
+       if (len > 0) {
+               dp = *p + ceph_x_encrypt_offset();
+               ret = ceph_x_decrypt(&th->session_key, p, *p + len);
+               if (ret < 0)
+                       return ret;
+
+               dout("%s decrypted %d bytes\n", __func__, ret);
+               dend = dp + ret;
+
+               ceph_decode_32_safe(&dp, dend, len, e_inval);
+               if (len > CEPH_MAX_CON_SECRET_LEN) {
+                       pr_err("connection secret too big %d\n", len);
+                       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 */
+       ceph_decode_32_safe(p, end, len, e_inval);
+       dout("%s service tickets blob len %d\n", __func__, len);
+       if (len > 0) {
+               ret = ceph_x_proc_ticket_reply(ac, &th->session_key,
+                                              p, *p + len);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+
+e_inval:
+       return -EINVAL;
+}
+
 static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result,
-                              void *buf, void *end)
+                              void *buf, void *end,
+                              u8 *session_key, int *session_key_len,
+                              u8 *con_secret, int *con_secret_len)
 {
        struct ceph_x_info *xi = ac->private;
        struct ceph_x_ticket_handler *th;
@@ -599,8 +676,10 @@ static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result,
        dout("handle_reply op %d result %d\n", op, result);
        switch (op) {
        case CEPHX_GET_AUTH_SESSION_KEY:
-               /* verify auth key */
-               ret = ceph_x_proc_ticket_reply(ac, &xi->secret, p, end);
+               /* AUTH ticket + [connection secret] + service tickets */
+               ret = handle_auth_session_key(ac, &p, end, session_key,
+                                             session_key_len, con_secret,
+                                             con_secret_len);
                break;
 
        case CEPHX_GET_PRINCIPAL_SESSION_KEY:
@@ -608,7 +687,8 @@ static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result,
                if (IS_ERR(th))
                        return PTR_ERR(th);
 
-               ret = ceph_x_proc_ticket_reply(ac, &th->session_key, p, end);
+               /* service tickets */
+               ret = ceph_x_proc_ticket_reply(ac, &th->session_key, &p, end);
                break;
 
        default:
@@ -687,40 +767,44 @@ static int ceph_x_update_authorizer(
        return 0;
 }
 
-static int decrypt_authorize_challenge(struct ceph_x_authorizer *au,
-                                      void *challenge_buf,
-                                      int challenge_buf_len,
-                                      u64 *server_challenge)
+/*
+ * CephXAuthorizeChallenge
+ */
+static int decrypt_authorizer_challenge(struct ceph_crypto_key *secret,
+                                       void *challenge, int challenge_len,
+                                       u64 *server_challenge)
 {
-       struct ceph_x_authorize_challenge *ch =
-           challenge_buf + sizeof(struct ceph_x_encrypt_header);
+       void *dp, *dend;
        int ret;
 
        /* no leading len */
-       ret = __ceph_x_decrypt(&au->session_key, challenge_buf,
-                              challenge_buf_len);
+       ret = __ceph_x_decrypt(secret, challenge, challenge_len);
        if (ret < 0)
                return ret;
-       if (ret < sizeof(*ch)) {
-               pr_err("bad size %d for ceph_x_authorize_challenge\n", ret);
-               return -EINVAL;
-       }
 
-       *server_challenge = le64_to_cpu(ch->server_challenge);
+       dout("%s decrypted %d bytes\n", __func__, ret);
+       dp = challenge + sizeof(struct ceph_x_encrypt_header);
+       dend = dp + ret;
+
+       ceph_decode_skip_8(&dp, dend, e_inval);  /* struct_v */
+       ceph_decode_64_safe(&dp, dend, *server_challenge, e_inval);
+       dout("%s server_challenge %llu\n", __func__, *server_challenge);
        return 0;
+
+e_inval:
+       return -EINVAL;
 }
 
 static int ceph_x_add_authorizer_challenge(struct ceph_auth_client *ac,
                                           struct ceph_authorizer *a,
-                                          void *challenge_buf,
-                                          int challenge_buf_len)
+                                          void *challenge, int challenge_len)
 {
        struct ceph_x_authorizer *au = (void *)a;
        u64 server_challenge;
        int ret;
 
-       ret = decrypt_authorize_challenge(au, challenge_buf, challenge_buf_len,
-                                         &server_challenge);
+       ret = decrypt_authorizer_challenge(&au->session_key, challenge,
+                                          challenge_len, &server_challenge);
        if (ret) {
                pr_err("failed to decrypt authorize challenge: %d", ret);
                return ret;
@@ -735,29 +819,76 @@ static int ceph_x_add_authorizer_challenge(struct ceph_auth_client *ac,
        return 0;
 }
 
+/*
+ * CephXAuthorizeReply
+ */
+static int decrypt_authorizer_reply(struct ceph_crypto_key *secret,
+                                   void **p, void *end, u64 *nonce_plus_one,
+                                   u8 *con_secret, int *con_secret_len)
+{
+       void *dp, *dend;
+       u8 struct_v;
+       int len;
+       int ret;
+
+       dp = *p + ceph_x_encrypt_offset();
+       ret = ceph_x_decrypt(secret, p, end);
+       if (ret < 0)
+               return ret;
+
+       dout("%s decrypted %d bytes\n", __func__, ret);
+       dend = dp + ret;
+
+       ceph_decode_8_safe(&dp, dend, struct_v, e_inval);
+       ceph_decode_64_safe(&dp, dend, *nonce_plus_one, e_inval);
+       dout("%s nonce_plus_one %llu\n", __func__, *nonce_plus_one);
+       if (struct_v >= 2) {
+               ceph_decode_32_safe(&dp, dend, len, e_inval);
+               if (len > CEPH_MAX_CON_SECRET_LEN) {
+                       pr_err("connection secret too big %d\n", len);
+                       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;
+
+e_inval:
+       return -EINVAL;
+}
+
 static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac,
-                                         struct ceph_authorizer *a)
+                                         struct ceph_authorizer *a,
+                                         void *reply, int reply_len,
+                                         u8 *session_key, int *session_key_len,
+                                         u8 *con_secret, int *con_secret_len)
 {
        struct ceph_x_authorizer *au = (void *)a;
-       void *p = au->enc_buf;
-       struct ceph_x_authorize_reply *reply = p + ceph_x_encrypt_offset();
+       u64 nonce_plus_one;
        int ret;
 
-       ret = ceph_x_decrypt(&au->session_key, &p, p + CEPHX_AU_ENC_BUF_LEN);
-       if (ret < 0)
+       if (session_key) {
+               memcpy(session_key, au->session_key.key, au->session_key.len);
+               *session_key_len = au->session_key.len;
+       }
+
+       ret = decrypt_authorizer_reply(&au->session_key, &reply,
+                                      reply + reply_len, &nonce_plus_one,
+                                      con_secret, con_secret_len);
+       if (ret)
                return ret;
-       if (ret < sizeof(*reply)) {
-               pr_err("bad size %d for ceph_x_authorize_reply\n", ret);
-               return -EINVAL;
+
+       if (nonce_plus_one != au->nonce + 1) {
+               pr_err("failed to authenticate server\n");
+               return -EPERM;
        }
 
-       if (au->nonce + 1 != le64_to_cpu(reply->nonce_plus_one))
-               ret = -EPERM;
-       else
-               ret = 0;
-       dout("verify_authorizer_reply nonce %llx got %llx ret %d\n",
-            au->nonce, le64_to_cpu(reply->nonce_plus_one), ret);
-       return ret;
+       return 0;
 }
 
 static void ceph_x_reset(struct ceph_auth_client *ac)
index 24b0b74..792fcb9 100644 (file)
@@ -38,7 +38,8 @@ struct ceph_x_authenticate {
        __u8 struct_v;
        __le64 client_challenge;
        __le64 key;
-       /* ticket blob */
+       /* old_ticket blob */
+       /* nautilus+: other_keys */
 } __attribute__ ((packed));
 
 struct ceph_x_service_ticket_request {
index 96ef4d8..13bd526 100644 (file)
@@ -5,6 +5,9 @@
 #include <linux/ceph/types.h>
 #include <linux/ceph/buffer.h>
 
+#define CEPH_KEY_LEN                   16
+#define CEPH_MAX_CON_SECRET_LEN                64
+
 /*
  * cryptographic secret
  */
index 7901ab6..8966eae 100644 (file)
@@ -5623,8 +5623,11 @@ static int verify_authorizer_reply(struct ceph_connection *con)
        struct ceph_osd *o = con->private;
        struct ceph_osd_client *osdc = o->o_osdc;
        struct ceph_auth_client *ac = osdc->client->monc.auth;
+       struct ceph_auth_handshake *auth = &o->o_auth;
 
-       return ceph_auth_verify_authorizer_reply(ac, o->o_auth.authorizer);
+       return ceph_auth_verify_authorizer_reply(ac, auth->authorizer,
+               auth->authorizer_reply_buf, auth->authorizer_reply_buf_len,
+               NULL, NULL, NULL, NULL);
 }
 
 static int invalidate_authorizer(struct ceph_connection *con)