linux/net/ceph/auth_x.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3#include <linux/ceph/ceph_debug.h>
   4
   5#include <linux/err.h>
   6#include <linux/module.h>
   7#include <linux/random.h>
   8#include <linux/slab.h>
   9
  10#include <linux/ceph/decode.h>
  11#include <linux/ceph/auth.h>
  12#include <linux/ceph/ceph_features.h>
  13#include <linux/ceph/libceph.h>
  14#include <linux/ceph/messenger.h>
  15
  16#include "crypto.h"
  17#include "auth_x.h"
  18#include "auth_x_protocol.h"
  19
  20static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed);
  21
  22static int ceph_x_is_authenticated(struct ceph_auth_client *ac)
  23{
  24        struct ceph_x_info *xi = ac->private;
  25        int missing;
  26        int need;  /* missing + need renewal */
  27
  28        ceph_x_validate_tickets(ac, &need);
  29        missing = ac->want_keys & ~xi->have_keys;
  30        WARN_ON((need & missing) != missing);
  31        dout("%s want 0x%x have 0x%x missing 0x%x -> %d\n", __func__,
  32             ac->want_keys, xi->have_keys, missing, !missing);
  33        return !missing;
  34}
  35
  36static int ceph_x_should_authenticate(struct ceph_auth_client *ac)
  37{
  38        struct ceph_x_info *xi = ac->private;
  39        int need;
  40
  41        ceph_x_validate_tickets(ac, &need);
  42        dout("%s want 0x%x have 0x%x need 0x%x -> %d\n", __func__,
  43             ac->want_keys, xi->have_keys, need, !!need);
  44        return !!need;
  45}
  46
  47static int ceph_x_encrypt_offset(void)
  48{
  49        return sizeof(u32) + sizeof(struct ceph_x_encrypt_header);
  50}
  51
  52static int ceph_x_encrypt_buflen(int ilen)
  53{
  54        return ceph_x_encrypt_offset() + ilen + 16;
  55}
  56
  57static int ceph_x_encrypt(struct ceph_crypto_key *secret, void *buf,
  58                          int buf_len, int plaintext_len)
  59{
  60        struct ceph_x_encrypt_header *hdr = buf + sizeof(u32);
  61        int ciphertext_len;
  62        int ret;
  63
  64        hdr->struct_v = 1;
  65        hdr->magic = cpu_to_le64(CEPHX_ENC_MAGIC);
  66
  67        ret = ceph_crypt(secret, true, buf + sizeof(u32), buf_len - sizeof(u32),
  68                         plaintext_len + sizeof(struct ceph_x_encrypt_header),
  69                         &ciphertext_len);
  70        if (ret)
  71                return ret;
  72
  73        ceph_encode_32(&buf, ciphertext_len);
  74        return sizeof(u32) + ciphertext_len;
  75}
  76
  77static int __ceph_x_decrypt(struct ceph_crypto_key *secret, void *p,
  78                            int ciphertext_len)
  79{
  80        struct ceph_x_encrypt_header *hdr = p;
  81        int plaintext_len;
  82        int ret;
  83
  84        ret = ceph_crypt(secret, false, p, ciphertext_len, ciphertext_len,
  85                         &plaintext_len);
  86        if (ret)
  87                return ret;
  88
  89        if (le64_to_cpu(hdr->magic) != CEPHX_ENC_MAGIC) {
  90                pr_err("%s bad magic\n", __func__);
  91                return -EINVAL;
  92        }
  93
  94        return plaintext_len - sizeof(*hdr);
  95}
  96
  97static int ceph_x_decrypt(struct ceph_crypto_key *secret, void **p, void *end)
  98{
  99        int ciphertext_len;
 100        int ret;
 101
 102        ceph_decode_32_safe(p, end, ciphertext_len, e_inval);
 103        ceph_decode_need(p, end, ciphertext_len, e_inval);
 104
 105        ret = __ceph_x_decrypt(secret, *p, ciphertext_len);
 106        if (ret < 0)
 107                return ret;
 108
 109        *p += ciphertext_len;
 110        return ret;
 111
 112e_inval:
 113        return -EINVAL;
 114}
 115
 116/*
 117 * get existing (or insert new) ticket handler
 118 */
 119static struct ceph_x_ticket_handler *
 120get_ticket_handler(struct ceph_auth_client *ac, int service)
 121{
 122        struct ceph_x_ticket_handler *th;
 123        struct ceph_x_info *xi = ac->private;
 124        struct rb_node *parent = NULL, **p = &xi->ticket_handlers.rb_node;
 125
 126        while (*p) {
 127                parent = *p;
 128                th = rb_entry(parent, struct ceph_x_ticket_handler, node);
 129                if (service < th->service)
 130                        p = &(*p)->rb_left;
 131                else if (service > th->service)
 132                        p = &(*p)->rb_right;
 133                else
 134                        return th;
 135        }
 136
 137        /* add it */
 138        th = kzalloc(sizeof(*th), GFP_NOFS);
 139        if (!th)
 140                return ERR_PTR(-ENOMEM);
 141        th->service = service;
 142        rb_link_node(&th->node, parent, p);
 143        rb_insert_color(&th->node, &xi->ticket_handlers);
 144        return th;
 145}
 146
 147static void remove_ticket_handler(struct ceph_auth_client *ac,
 148                                  struct ceph_x_ticket_handler *th)
 149{
 150        struct ceph_x_info *xi = ac->private;
 151
 152        dout("remove_ticket_handler %p %d\n", th, th->service);
 153        rb_erase(&th->node, &xi->ticket_handlers);
 154        ceph_crypto_key_destroy(&th->session_key);
 155        if (th->ticket_blob)
 156                ceph_buffer_put(th->ticket_blob);
 157        kfree(th);
 158}
 159
 160static int process_one_ticket(struct ceph_auth_client *ac,
 161                              struct ceph_crypto_key *secret,
 162                              void **p, void *end)
 163{
 164        struct ceph_x_info *xi = ac->private;
 165        int type;
 166        u8 tkt_struct_v, blob_struct_v;
 167        struct ceph_x_ticket_handler *th;
 168        void *dp, *dend;
 169        int dlen;
 170        char is_enc;
 171        struct timespec64 validity;
 172        void *tp, *tpend;
 173        void **ptp;
 174        struct ceph_crypto_key new_session_key = { 0 };
 175        struct ceph_buffer *new_ticket_blob;
 176        time64_t new_expires, new_renew_after;
 177        u64 new_secret_id;
 178        int ret;
 179
 180        ceph_decode_need(p, end, sizeof(u32) + 1, bad);
 181
 182        type = ceph_decode_32(p);
 183        dout(" ticket type %d %s\n", type, ceph_entity_type_name(type));
 184
 185        tkt_struct_v = ceph_decode_8(p);
 186        if (tkt_struct_v != 1)
 187                goto bad;
 188
 189        th = get_ticket_handler(ac, type);
 190        if (IS_ERR(th)) {
 191                ret = PTR_ERR(th);
 192                goto out;
 193        }
 194
 195        /* blob for me */
 196        dp = *p + ceph_x_encrypt_offset();
 197        ret = ceph_x_decrypt(secret, p, end);
 198        if (ret < 0)
 199                goto out;
 200        dout(" decrypted %d bytes\n", ret);
 201        dend = dp + ret;
 202
 203        ceph_decode_8_safe(&dp, dend, tkt_struct_v, bad);
 204        if (tkt_struct_v != 1)
 205                goto bad;
 206
 207        ret = ceph_crypto_key_decode(&new_session_key, &dp, dend);
 208        if (ret)
 209                goto out;
 210
 211        ceph_decode_need(&dp, dend, sizeof(struct ceph_timespec), bad);
 212        ceph_decode_timespec64(&validity, dp);
 213        dp += sizeof(struct ceph_timespec);
 214        new_expires = ktime_get_real_seconds() + validity.tv_sec;
 215        new_renew_after = new_expires - (validity.tv_sec / 4);
 216        dout(" expires=%llu renew_after=%llu\n", new_expires,
 217             new_renew_after);
 218
 219        /* ticket blob for service */
 220        ceph_decode_8_safe(p, end, is_enc, bad);
 221        if (is_enc) {
 222                /* encrypted */
 223                tp = *p + ceph_x_encrypt_offset();
 224                ret = ceph_x_decrypt(&th->session_key, p, end);
 225                if (ret < 0)
 226                        goto out;
 227                dout(" encrypted ticket, decrypted %d bytes\n", ret);
 228                ptp = &tp;
 229                tpend = tp + ret;
 230        } else {
 231                /* unencrypted */
 232                ptp = p;
 233                tpend = end;
 234        }
 235        ceph_decode_32_safe(ptp, tpend, dlen, bad);
 236        dout(" ticket blob is %d bytes\n", dlen);
 237        ceph_decode_need(ptp, tpend, 1 + sizeof(u64), bad);
 238        blob_struct_v = ceph_decode_8(ptp);
 239        if (blob_struct_v != 1)
 240                goto bad;
 241
 242        new_secret_id = ceph_decode_64(ptp);
 243        ret = ceph_decode_buffer(&new_ticket_blob, ptp, tpend);
 244        if (ret)
 245                goto out;
 246
 247        /* all is well, update our ticket */
 248        ceph_crypto_key_destroy(&th->session_key);
 249        if (th->ticket_blob)
 250                ceph_buffer_put(th->ticket_blob);
 251        th->session_key = new_session_key;
 252        th->ticket_blob = new_ticket_blob;
 253        th->secret_id = new_secret_id;
 254        th->expires = new_expires;
 255        th->renew_after = new_renew_after;
 256        th->have_key = true;
 257        dout(" got ticket service %d (%s) secret_id %lld len %d\n",
 258             type, ceph_entity_type_name(type), th->secret_id,
 259             (int)th->ticket_blob->vec.iov_len);
 260        xi->have_keys |= th->service;
 261        return 0;
 262
 263bad:
 264        ret = -EINVAL;
 265out:
 266        ceph_crypto_key_destroy(&new_session_key);
 267        return ret;
 268}
 269
 270static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac,
 271                                    struct ceph_crypto_key *secret,
 272                                    void **p, void *end)
 273{
 274        u8 reply_struct_v;
 275        u32 num;
 276        int ret;
 277
 278        ceph_decode_8_safe(p, end, reply_struct_v, bad);
 279        if (reply_struct_v != 1)
 280                return -EINVAL;
 281
 282        ceph_decode_32_safe(p, end, num, bad);
 283        dout("%d tickets\n", num);
 284
 285        while (num--) {
 286                ret = process_one_ticket(ac, secret, p, end);
 287                if (ret)
 288                        return ret;
 289        }
 290
 291        return 0;
 292
 293bad:
 294        return -EINVAL;
 295}
 296
 297/*
 298 * Encode and encrypt the second part (ceph_x_authorize_b) of the
 299 * authorizer.  The first part (ceph_x_authorize_a) should already be
 300 * encoded.
 301 */
 302static int encrypt_authorizer(struct ceph_x_authorizer *au,
 303                              u64 *server_challenge)
 304{
 305        struct ceph_x_authorize_a *msg_a;
 306        struct ceph_x_authorize_b *msg_b;
 307        void *p, *end;
 308        int ret;
 309
 310        msg_a = au->buf->vec.iov_base;
 311        WARN_ON(msg_a->ticket_blob.secret_id != cpu_to_le64(au->secret_id));
 312        p = (void *)(msg_a + 1) + le32_to_cpu(msg_a->ticket_blob.blob_len);
 313        end = au->buf->vec.iov_base + au->buf->vec.iov_len;
 314
 315        msg_b = p + ceph_x_encrypt_offset();
 316        msg_b->struct_v = 2;
 317        msg_b->nonce = cpu_to_le64(au->nonce);
 318        if (server_challenge) {
 319                msg_b->have_challenge = 1;
 320                msg_b->server_challenge_plus_one =
 321                    cpu_to_le64(*server_challenge + 1);
 322        } else {
 323                msg_b->have_challenge = 0;
 324                msg_b->server_challenge_plus_one = 0;
 325        }
 326
 327        ret = ceph_x_encrypt(&au->session_key, p, end - p, sizeof(*msg_b));
 328        if (ret < 0)
 329                return ret;
 330
 331        p += ret;
 332        if (server_challenge) {
 333                WARN_ON(p != end);
 334        } else {
 335                WARN_ON(p > end);
 336                au->buf->vec.iov_len = p - au->buf->vec.iov_base;
 337        }
 338
 339        return 0;
 340}
 341
 342static void ceph_x_authorizer_cleanup(struct ceph_x_authorizer *au)
 343{
 344        ceph_crypto_key_destroy(&au->session_key);
 345        if (au->buf) {
 346                ceph_buffer_put(au->buf);
 347                au->buf = NULL;
 348        }
 349}
 350
 351static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
 352                                   struct ceph_x_ticket_handler *th,
 353                                   struct ceph_x_authorizer *au)
 354{
 355        int maxlen;
 356        struct ceph_x_authorize_a *msg_a;
 357        struct ceph_x_authorize_b *msg_b;
 358        int ret;
 359        int ticket_blob_len =
 360                (th->ticket_blob ? th->ticket_blob->vec.iov_len : 0);
 361
 362        dout("build_authorizer for %s %p\n",
 363             ceph_entity_type_name(th->service), au);
 364
 365        ceph_crypto_key_destroy(&au->session_key);
 366        ret = ceph_crypto_key_clone(&au->session_key, &th->session_key);
 367        if (ret)
 368                goto out_au;
 369
 370        maxlen = sizeof(*msg_a) + ticket_blob_len +
 371                ceph_x_encrypt_buflen(sizeof(*msg_b));
 372        dout("  need len %d\n", maxlen);
 373        if (au->buf && au->buf->alloc_len < maxlen) {
 374                ceph_buffer_put(au->buf);
 375                au->buf = NULL;
 376        }
 377        if (!au->buf) {
 378                au->buf = ceph_buffer_new(maxlen, GFP_NOFS);
 379                if (!au->buf) {
 380                        ret = -ENOMEM;
 381                        goto out_au;
 382                }
 383        }
 384        au->service = th->service;
 385        WARN_ON(!th->secret_id);
 386        au->secret_id = th->secret_id;
 387
 388        msg_a = au->buf->vec.iov_base;
 389        msg_a->struct_v = 1;
 390        msg_a->global_id = cpu_to_le64(ac->global_id);
 391        msg_a->service_id = cpu_to_le32(th->service);
 392        msg_a->ticket_blob.struct_v = 1;
 393        msg_a->ticket_blob.secret_id = cpu_to_le64(th->secret_id);
 394        msg_a->ticket_blob.blob_len = cpu_to_le32(ticket_blob_len);
 395        if (ticket_blob_len) {
 396                memcpy(msg_a->ticket_blob.blob, th->ticket_blob->vec.iov_base,
 397                       th->ticket_blob->vec.iov_len);
 398        }
 399        dout(" th %p secret_id %lld %lld\n", th, th->secret_id,
 400             le64_to_cpu(msg_a->ticket_blob.secret_id));
 401
 402        get_random_bytes(&au->nonce, sizeof(au->nonce));
 403        ret = encrypt_authorizer(au, NULL);
 404        if (ret) {
 405                pr_err("failed to encrypt authorizer: %d", ret);
 406                goto out_au;
 407        }
 408
 409        dout(" built authorizer nonce %llx len %d\n", au->nonce,
 410             (int)au->buf->vec.iov_len);
 411        return 0;
 412
 413out_au:
 414        ceph_x_authorizer_cleanup(au);
 415        return ret;
 416}
 417
 418static int ceph_x_encode_ticket(struct ceph_x_ticket_handler *th,
 419                                void **p, void *end)
 420{
 421        ceph_decode_need(p, end, 1 + sizeof(u64), bad);
 422        ceph_encode_8(p, 1);
 423        ceph_encode_64(p, th->secret_id);
 424        if (th->ticket_blob) {
 425                const char *buf = th->ticket_blob->vec.iov_base;
 426                u32 len = th->ticket_blob->vec.iov_len;
 427
 428                ceph_encode_32_safe(p, end, len, bad);
 429                ceph_encode_copy_safe(p, end, buf, len, bad);
 430        } else {
 431                ceph_encode_32_safe(p, end, 0, bad);
 432        }
 433
 434        return 0;
 435bad:
 436        return -ERANGE;
 437}
 438
 439static bool need_key(struct ceph_x_ticket_handler *th)
 440{
 441        if (!th->have_key)
 442                return true;
 443
 444        return ktime_get_real_seconds() >= th->renew_after;
 445}
 446
 447static bool have_key(struct ceph_x_ticket_handler *th)
 448{
 449        if (th->have_key && ktime_get_real_seconds() >= th->expires) {
 450                dout("ticket %d (%s) secret_id %llu expired\n", th->service,
 451                     ceph_entity_type_name(th->service), th->secret_id);
 452                th->have_key = false;
 453        }
 454
 455        return th->have_key;
 456}
 457
 458static void ceph_x_validate_tickets(struct ceph_auth_client *ac, int *pneed)
 459{
 460        int want = ac->want_keys;
 461        struct ceph_x_info *xi = ac->private;
 462        int service;
 463
 464        *pneed = ac->want_keys & ~(xi->have_keys);
 465
 466        for (service = 1; service <= want; service <<= 1) {
 467                struct ceph_x_ticket_handler *th;
 468
 469                if (!(ac->want_keys & service))
 470                        continue;
 471
 472                if (*pneed & service)
 473                        continue;
 474
 475                th = get_ticket_handler(ac, service);
 476                if (IS_ERR(th)) {
 477                        *pneed |= service;
 478                        continue;
 479                }
 480
 481                if (need_key(th))
 482                        *pneed |= service;
 483                if (!have_key(th))
 484                        xi->have_keys &= ~service;
 485        }
 486}
 487
 488static int ceph_x_build_request(struct ceph_auth_client *ac,
 489                                void *buf, void *end)
 490{
 491        struct ceph_x_info *xi = ac->private;
 492        int need;
 493        struct ceph_x_request_header *head = buf;
 494        void *p;
 495        int ret;
 496        struct ceph_x_ticket_handler *th =
 497                get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH);
 498
 499        if (IS_ERR(th))
 500                return PTR_ERR(th);
 501
 502        ceph_x_validate_tickets(ac, &need);
 503        dout("%s want 0x%x have 0x%x need 0x%x\n", __func__, ac->want_keys,
 504             xi->have_keys, need);
 505
 506        if (need & CEPH_ENTITY_TYPE_AUTH) {
 507                struct ceph_x_authenticate *auth = (void *)(head + 1);
 508                void *enc_buf = xi->auth_authorizer.enc_buf;
 509                struct ceph_x_challenge_blob *blob = enc_buf +
 510                                                        ceph_x_encrypt_offset();
 511                u64 *u;
 512
 513                p = auth + 1;
 514                if (p > end)
 515                        return -ERANGE;
 516
 517                dout(" get_auth_session_key\n");
 518                head->op = cpu_to_le16(CEPHX_GET_AUTH_SESSION_KEY);
 519
 520                /* encrypt and hash */
 521                get_random_bytes(&auth->client_challenge, sizeof(u64));
 522                blob->client_challenge = auth->client_challenge;
 523                blob->server_challenge = cpu_to_le64(xi->server_challenge);
 524                ret = ceph_x_encrypt(&xi->secret, enc_buf, CEPHX_AU_ENC_BUF_LEN,
 525                                     sizeof(*blob));
 526                if (ret < 0)
 527                        return ret;
 528
 529                auth->struct_v = 3;  /* nautilus+ */
 530                auth->key = 0;
 531                for (u = (u64 *)enc_buf; u + 1 <= (u64 *)(enc_buf + ret); u++)
 532                        auth->key ^= *(__le64 *)u;
 533                dout(" server_challenge %llx client_challenge %llx key %llx\n",
 534                     xi->server_challenge, le64_to_cpu(auth->client_challenge),
 535                     le64_to_cpu(auth->key));
 536
 537                /* now encode the old ticket if exists */
 538                ret = ceph_x_encode_ticket(th, &p, end);
 539                if (ret < 0)
 540                        return ret;
 541
 542                /* nautilus+: request service tickets at the same time */
 543                need = ac->want_keys & ~CEPH_ENTITY_TYPE_AUTH;
 544                WARN_ON(!need);
 545                ceph_encode_32_safe(&p, end, need, e_range);
 546                return p - buf;
 547        }
 548
 549        if (need) {
 550                dout(" get_principal_session_key\n");
 551                ret = ceph_x_build_authorizer(ac, th, &xi->auth_authorizer);
 552                if (ret)
 553                        return ret;
 554
 555                p = buf;
 556                ceph_encode_16_safe(&p, end, CEPHX_GET_PRINCIPAL_SESSION_KEY,
 557                                    e_range);
 558                ceph_encode_copy_safe(&p, end,
 559                        xi->auth_authorizer.buf->vec.iov_base,
 560                        xi->auth_authorizer.buf->vec.iov_len, e_range);
 561                ceph_encode_8_safe(&p, end, 1, e_range);
 562                ceph_encode_32_safe(&p, end, need, e_range);
 563                return p - buf;
 564        }
 565
 566        return 0;
 567
 568e_range:
 569        return -ERANGE;
 570}
 571
 572static int decode_con_secret(void **p, void *end, u8 *con_secret,
 573                             int *con_secret_len)
 574{
 575        int len;
 576
 577        ceph_decode_32_safe(p, end, len, bad);
 578        ceph_decode_need(p, end, len, bad);
 579
 580        dout("%s len %d\n", __func__, len);
 581        if (con_secret) {
 582                if (len > CEPH_MAX_CON_SECRET_LEN) {
 583                        pr_err("connection secret too big %d\n", len);
 584                        goto bad_memzero;
 585                }
 586                memcpy(con_secret, *p, len);
 587                *con_secret_len = len;
 588        }
 589        memzero_explicit(*p, len);
 590        *p += len;
 591        return 0;
 592
 593bad_memzero:
 594        memzero_explicit(*p, len);
 595bad:
 596        pr_err("failed to decode connection secret\n");
 597        return -EINVAL;
 598}
 599
 600static int handle_auth_session_key(struct ceph_auth_client *ac, u64 global_id,
 601                                   void **p, void *end,
 602                                   u8 *session_key, int *session_key_len,
 603                                   u8 *con_secret, int *con_secret_len)
 604{
 605        struct ceph_x_info *xi = ac->private;
 606        struct ceph_x_ticket_handler *th;
 607        void *dp, *dend;
 608        int len;
 609        int ret;
 610
 611        /* AUTH ticket */
 612        ret = ceph_x_proc_ticket_reply(ac, &xi->secret, p, end);
 613        if (ret)
 614                return ret;
 615
 616        ceph_auth_set_global_id(ac, global_id);
 617        if (*p == end) {
 618                /* pre-nautilus (or didn't request service tickets!) */
 619                WARN_ON(session_key || con_secret);
 620                return 0;
 621        }
 622
 623        th = get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH);
 624        if (IS_ERR(th))
 625                return PTR_ERR(th);
 626
 627        if (session_key) {
 628                memcpy(session_key, th->session_key.key, th->session_key.len);
 629                *session_key_len = th->session_key.len;
 630        }
 631
 632        /* connection secret */
 633        ceph_decode_32_safe(p, end, len, e_inval);
 634        dout("%s connection secret blob len %d\n", __func__, len);
 635        if (len > 0) {
 636                dp = *p + ceph_x_encrypt_offset();
 637                ret = ceph_x_decrypt(&th->session_key, p, *p + len);
 638                if (ret < 0)
 639                        return ret;
 640
 641                dout("%s decrypted %d bytes\n", __func__, ret);
 642                dend = dp + ret;
 643
 644                ret = decode_con_secret(&dp, dend, con_secret, con_secret_len);
 645                if (ret)
 646                        return ret;
 647        }
 648
 649        /* service tickets */
 650        ceph_decode_32_safe(p, end, len, e_inval);
 651        dout("%s service tickets blob len %d\n", __func__, len);
 652        if (len > 0) {
 653                ret = ceph_x_proc_ticket_reply(ac, &th->session_key,
 654                                               p, *p + len);
 655                if (ret)
 656                        return ret;
 657        }
 658
 659        return 0;
 660
 661e_inval:
 662        return -EINVAL;
 663}
 664
 665static int ceph_x_handle_reply(struct ceph_auth_client *ac, u64 global_id,
 666                               void *buf, void *end,
 667                               u8 *session_key, int *session_key_len,
 668                               u8 *con_secret, int *con_secret_len)
 669{
 670        struct ceph_x_info *xi = ac->private;
 671        struct ceph_x_ticket_handler *th;
 672        int len = end - buf;
 673        int result;
 674        void *p;
 675        int op;
 676        int ret;
 677
 678        if (xi->starting) {
 679                /* it's a hello */
 680                struct ceph_x_server_challenge *sc = buf;
 681
 682                if (len != sizeof(*sc))
 683                        return -EINVAL;
 684                xi->server_challenge = le64_to_cpu(sc->server_challenge);
 685                dout("handle_reply got server challenge %llx\n",
 686                     xi->server_challenge);
 687                xi->starting = false;
 688                xi->have_keys &= ~CEPH_ENTITY_TYPE_AUTH;
 689                return -EAGAIN;
 690        }
 691
 692        p = buf;
 693        ceph_decode_16_safe(&p, end, op, e_inval);
 694        ceph_decode_32_safe(&p, end, result, e_inval);
 695        dout("handle_reply op %d result %d\n", op, result);
 696        switch (op) {
 697        case CEPHX_GET_AUTH_SESSION_KEY:
 698                /* AUTH ticket + [connection secret] + service tickets */
 699                ret = handle_auth_session_key(ac, global_id, &p, end,
 700                                              session_key, session_key_len,
 701                                              con_secret, con_secret_len);
 702                break;
 703
 704        case CEPHX_GET_PRINCIPAL_SESSION_KEY:
 705                th = get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH);
 706                if (IS_ERR(th))
 707                        return PTR_ERR(th);
 708
 709                /* service tickets */
 710                ret = ceph_x_proc_ticket_reply(ac, &th->session_key, &p, end);
 711                break;
 712
 713        default:
 714                return -EINVAL;
 715        }
 716        if (ret)
 717                return ret;
 718        if (ac->want_keys == xi->have_keys)
 719                return 0;
 720        return -EAGAIN;
 721
 722e_inval:
 723        return -EINVAL;
 724}
 725
 726static void ceph_x_destroy_authorizer(struct ceph_authorizer *a)
 727{
 728        struct ceph_x_authorizer *au = (void *)a;
 729
 730        ceph_x_authorizer_cleanup(au);
 731        kfree(au);
 732}
 733
 734static int ceph_x_create_authorizer(
 735        struct ceph_auth_client *ac, int peer_type,
 736        struct ceph_auth_handshake *auth)
 737{
 738        struct ceph_x_authorizer *au;
 739        struct ceph_x_ticket_handler *th;
 740        int ret;
 741
 742        th = get_ticket_handler(ac, peer_type);
 743        if (IS_ERR(th))
 744                return PTR_ERR(th);
 745
 746        au = kzalloc(sizeof(*au), GFP_NOFS);
 747        if (!au)
 748                return -ENOMEM;
 749
 750        au->base.destroy = ceph_x_destroy_authorizer;
 751
 752        ret = ceph_x_build_authorizer(ac, th, au);
 753        if (ret) {
 754                kfree(au);
 755                return ret;
 756        }
 757
 758        auth->authorizer = (struct ceph_authorizer *) au;
 759        auth->authorizer_buf = au->buf->vec.iov_base;
 760        auth->authorizer_buf_len = au->buf->vec.iov_len;
 761        auth->authorizer_reply_buf = au->enc_buf;
 762        auth->authorizer_reply_buf_len = CEPHX_AU_ENC_BUF_LEN;
 763        auth->sign_message = ac->ops->sign_message;
 764        auth->check_message_signature = ac->ops->check_message_signature;
 765
 766        return 0;
 767}
 768
 769static int ceph_x_update_authorizer(
 770        struct ceph_auth_client *ac, int peer_type,
 771        struct ceph_auth_handshake *auth)
 772{
 773        struct ceph_x_authorizer *au;
 774        struct ceph_x_ticket_handler *th;
 775
 776        th = get_ticket_handler(ac, peer_type);
 777        if (IS_ERR(th))
 778                return PTR_ERR(th);
 779
 780        au = (struct ceph_x_authorizer *)auth->authorizer;
 781        if (au->secret_id < th->secret_id) {
 782                dout("ceph_x_update_authorizer service %u secret %llu < %llu\n",
 783                     au->service, au->secret_id, th->secret_id);
 784                return ceph_x_build_authorizer(ac, th, au);
 785        }
 786        return 0;
 787}
 788
 789/*
 790 * CephXAuthorizeChallenge
 791 */
 792static int decrypt_authorizer_challenge(struct ceph_crypto_key *secret,
 793                                        void *challenge, int challenge_len,
 794                                        u64 *server_challenge)
 795{
 796        void *dp, *dend;
 797        int ret;
 798
 799        /* no leading len */
 800        ret = __ceph_x_decrypt(secret, challenge, challenge_len);
 801        if (ret < 0)
 802                return ret;
 803
 804        dout("%s decrypted %d bytes\n", __func__, ret);
 805        dp = challenge + sizeof(struct ceph_x_encrypt_header);
 806        dend = dp + ret;
 807
 808        ceph_decode_skip_8(&dp, dend, e_inval);  /* struct_v */
 809        ceph_decode_64_safe(&dp, dend, *server_challenge, e_inval);
 810        dout("%s server_challenge %llu\n", __func__, *server_challenge);
 811        return 0;
 812
 813e_inval:
 814        return -EINVAL;
 815}
 816
 817static int ceph_x_add_authorizer_challenge(struct ceph_auth_client *ac,
 818                                           struct ceph_authorizer *a,
 819                                           void *challenge, int challenge_len)
 820{
 821        struct ceph_x_authorizer *au = (void *)a;
 822        u64 server_challenge;
 823        int ret;
 824
 825        ret = decrypt_authorizer_challenge(&au->session_key, challenge,
 826                                           challenge_len, &server_challenge);
 827        if (ret) {
 828                pr_err("failed to decrypt authorize challenge: %d", ret);
 829                return ret;
 830        }
 831
 832        ret = encrypt_authorizer(au, &server_challenge);
 833        if (ret) {
 834                pr_err("failed to encrypt authorizer w/ challenge: %d", ret);
 835                return ret;
 836        }
 837
 838        return 0;
 839}
 840
 841/*
 842 * CephXAuthorizeReply
 843 */
 844static int decrypt_authorizer_reply(struct ceph_crypto_key *secret,
 845                                    void **p, void *end, u64 *nonce_plus_one,
 846                                    u8 *con_secret, int *con_secret_len)
 847{
 848        void *dp, *dend;
 849        u8 struct_v;
 850        int ret;
 851
 852        dp = *p + ceph_x_encrypt_offset();
 853        ret = ceph_x_decrypt(secret, p, end);
 854        if (ret < 0)
 855                return ret;
 856
 857        dout("%s decrypted %d bytes\n", __func__, ret);
 858        dend = dp + ret;
 859
 860        ceph_decode_8_safe(&dp, dend, struct_v, e_inval);
 861        ceph_decode_64_safe(&dp, dend, *nonce_plus_one, e_inval);
 862        dout("%s nonce_plus_one %llu\n", __func__, *nonce_plus_one);
 863        if (struct_v >= 2) {
 864                ret = decode_con_secret(&dp, dend, con_secret, con_secret_len);
 865                if (ret)
 866                        return ret;
 867        }
 868
 869        return 0;
 870
 871e_inval:
 872        return -EINVAL;
 873}
 874
 875static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac,
 876                                          struct ceph_authorizer *a,
 877                                          void *reply, int reply_len,
 878                                          u8 *session_key, int *session_key_len,
 879                                          u8 *con_secret, int *con_secret_len)
 880{
 881        struct ceph_x_authorizer *au = (void *)a;
 882        u64 nonce_plus_one;
 883        int ret;
 884
 885        if (session_key) {
 886                memcpy(session_key, au->session_key.key, au->session_key.len);
 887                *session_key_len = au->session_key.len;
 888        }
 889
 890        ret = decrypt_authorizer_reply(&au->session_key, &reply,
 891                                       reply + reply_len, &nonce_plus_one,
 892                                       con_secret, con_secret_len);
 893        if (ret)
 894                return ret;
 895
 896        if (nonce_plus_one != au->nonce + 1) {
 897                pr_err("failed to authenticate server\n");
 898                return -EPERM;
 899        }
 900
 901        return 0;
 902}
 903
 904static void ceph_x_reset(struct ceph_auth_client *ac)
 905{
 906        struct ceph_x_info *xi = ac->private;
 907
 908        dout("reset\n");
 909        xi->starting = true;
 910        xi->server_challenge = 0;
 911}
 912
 913static void ceph_x_destroy(struct ceph_auth_client *ac)
 914{
 915        struct ceph_x_info *xi = ac->private;
 916        struct rb_node *p;
 917
 918        dout("ceph_x_destroy %p\n", ac);
 919        ceph_crypto_key_destroy(&xi->secret);
 920
 921        while ((p = rb_first(&xi->ticket_handlers)) != NULL) {
 922                struct ceph_x_ticket_handler *th =
 923                        rb_entry(p, struct ceph_x_ticket_handler, node);
 924                remove_ticket_handler(ac, th);
 925        }
 926
 927        ceph_x_authorizer_cleanup(&xi->auth_authorizer);
 928
 929        kfree(ac->private);
 930        ac->private = NULL;
 931}
 932
 933static void invalidate_ticket(struct ceph_auth_client *ac, int peer_type)
 934{
 935        struct ceph_x_ticket_handler *th;
 936
 937        th = get_ticket_handler(ac, peer_type);
 938        if (IS_ERR(th))
 939                return;
 940
 941        if (th->have_key) {
 942                dout("ticket %d (%s) secret_id %llu invalidated\n",
 943                     th->service, ceph_entity_type_name(th->service),
 944                     th->secret_id);
 945                th->have_key = false;
 946        }
 947}
 948
 949static void ceph_x_invalidate_authorizer(struct ceph_auth_client *ac,
 950                                         int peer_type)
 951{
 952        /*
 953         * We are to invalidate a service ticket in the hopes of
 954         * getting a new, hopefully more valid, one.  But, we won't get
 955         * it unless our AUTH ticket is good, so invalidate AUTH ticket
 956         * as well, just in case.
 957         */
 958        invalidate_ticket(ac, peer_type);
 959        invalidate_ticket(ac, CEPH_ENTITY_TYPE_AUTH);
 960}
 961
 962static int calc_signature(struct ceph_x_authorizer *au, struct ceph_msg *msg,
 963                          __le64 *psig)
 964{
 965        void *enc_buf = au->enc_buf;
 966        int ret;
 967
 968        if (!CEPH_HAVE_FEATURE(msg->con->peer_features, CEPHX_V2)) {
 969                struct {
 970                        __le32 len;
 971                        __le32 header_crc;
 972                        __le32 front_crc;
 973                        __le32 middle_crc;
 974                        __le32 data_crc;
 975                } __packed *sigblock = enc_buf + ceph_x_encrypt_offset();
 976
 977                sigblock->len = cpu_to_le32(4*sizeof(u32));
 978                sigblock->header_crc = msg->hdr.crc;
 979                sigblock->front_crc = msg->footer.front_crc;
 980                sigblock->middle_crc = msg->footer.middle_crc;
 981                sigblock->data_crc =  msg->footer.data_crc;
 982
 983                ret = ceph_x_encrypt(&au->session_key, enc_buf,
 984                                     CEPHX_AU_ENC_BUF_LEN, sizeof(*sigblock));
 985                if (ret < 0)
 986                        return ret;
 987
 988                *psig = *(__le64 *)(enc_buf + sizeof(u32));
 989        } else {
 990                struct {
 991                        __le32 header_crc;
 992                        __le32 front_crc;
 993                        __le32 front_len;
 994                        __le32 middle_crc;
 995                        __le32 middle_len;
 996                        __le32 data_crc;
 997                        __le32 data_len;
 998                        __le32 seq_lower_word;
 999                } __packed *sigblock = enc_buf;
1000                struct {
1001                        __le64 a, b, c, d;
1002                } __packed *penc = enc_buf;
1003                int ciphertext_len;
1004
1005                sigblock->header_crc = msg->hdr.crc;
1006                sigblock->front_crc = msg->footer.front_crc;
1007                sigblock->front_len = msg->hdr.front_len;
1008                sigblock->middle_crc = msg->footer.middle_crc;
1009                sigblock->middle_len = msg->hdr.middle_len;
1010                sigblock->data_crc =  msg->footer.data_crc;
1011                sigblock->data_len = msg->hdr.data_len;
1012                sigblock->seq_lower_word = *(__le32 *)&msg->hdr.seq;
1013
1014                /* no leading len, no ceph_x_encrypt_header */
1015                ret = ceph_crypt(&au->session_key, true, enc_buf,
1016                                 CEPHX_AU_ENC_BUF_LEN, sizeof(*sigblock),
1017                                 &ciphertext_len);
1018                if (ret)
1019                        return ret;
1020
1021                *psig = penc->a ^ penc->b ^ penc->c ^ penc->d;
1022        }
1023
1024        return 0;
1025}
1026
1027static int ceph_x_sign_message(struct ceph_auth_handshake *auth,
1028                               struct ceph_msg *msg)
1029{
1030        __le64 sig;
1031        int ret;
1032
1033        if (ceph_test_opt(from_msgr(msg->con->msgr), NOMSGSIGN))
1034                return 0;
1035
1036        ret = calc_signature((struct ceph_x_authorizer *)auth->authorizer,
1037                             msg, &sig);
1038        if (ret)
1039                return ret;
1040
1041        msg->footer.sig = sig;
1042        msg->footer.flags |= CEPH_MSG_FOOTER_SIGNED;
1043        return 0;
1044}
1045
1046static int ceph_x_check_message_signature(struct ceph_auth_handshake *auth,
1047                                          struct ceph_msg *msg)
1048{
1049        __le64 sig_check;
1050        int ret;
1051
1052        if (ceph_test_opt(from_msgr(msg->con->msgr), NOMSGSIGN))
1053                return 0;
1054
1055        ret = calc_signature((struct ceph_x_authorizer *)auth->authorizer,
1056                             msg, &sig_check);
1057        if (ret)
1058                return ret;
1059        if (sig_check == msg->footer.sig)
1060                return 0;
1061        if (msg->footer.flags & CEPH_MSG_FOOTER_SIGNED)
1062                dout("ceph_x_check_message_signature %p has signature %llx "
1063                     "expect %llx\n", msg, msg->footer.sig, sig_check);
1064        else
1065                dout("ceph_x_check_message_signature %p sender did not set "
1066                     "CEPH_MSG_FOOTER_SIGNED\n", msg);
1067        return -EBADMSG;
1068}
1069
1070static const struct ceph_auth_client_ops ceph_x_ops = {
1071        .is_authenticated = ceph_x_is_authenticated,
1072        .should_authenticate = ceph_x_should_authenticate,
1073        .build_request = ceph_x_build_request,
1074        .handle_reply = ceph_x_handle_reply,
1075        .create_authorizer = ceph_x_create_authorizer,
1076        .update_authorizer = ceph_x_update_authorizer,
1077        .add_authorizer_challenge = ceph_x_add_authorizer_challenge,
1078        .verify_authorizer_reply = ceph_x_verify_authorizer_reply,
1079        .invalidate_authorizer = ceph_x_invalidate_authorizer,
1080        .reset =  ceph_x_reset,
1081        .destroy = ceph_x_destroy,
1082        .sign_message = ceph_x_sign_message,
1083        .check_message_signature = ceph_x_check_message_signature,
1084};
1085
1086
1087int ceph_x_init(struct ceph_auth_client *ac)
1088{
1089        struct ceph_x_info *xi;
1090        int ret;
1091
1092        dout("ceph_x_init %p\n", ac);
1093        ret = -ENOMEM;
1094        xi = kzalloc(sizeof(*xi), GFP_NOFS);
1095        if (!xi)
1096                goto out;
1097
1098        ret = -EINVAL;
1099        if (!ac->key) {
1100                pr_err("no secret set (for auth_x protocol)\n");
1101                goto out_nomem;
1102        }
1103
1104        ret = ceph_crypto_key_clone(&xi->secret, ac->key);
1105        if (ret < 0) {
1106                pr_err("cannot clone key: %d\n", ret);
1107                goto out_nomem;
1108        }
1109
1110        xi->starting = true;
1111        xi->ticket_handlers = RB_ROOT;
1112
1113        ac->protocol = CEPH_AUTH_CEPHX;
1114        ac->private = xi;
1115        ac->ops = &ceph_x_ops;
1116        return 0;
1117
1118out_nomem:
1119        kfree(xi);
1120out:
1121        return ret;
1122}
1123