| @@ -269,22 +269,21 @@ out: · 268 unmodified lines |
| 269 | 269 | |
| 270 | 270 | static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, |
| 271 | 271 | struct ceph_crypto_key *secret, |
| 272 | | − void *buf, void *end) |
| 272 | + void **p, void *end) |
| 273 | 273 | { |
| 274 | | − void *p = buf; |
| 275 | 274 | u8 reply_struct_v; |
| 276 | 275 | u32 num; |
| 277 | 276 | int ret; |
| 278 | 277 | |
| 279 | | − ceph_decode_8_safe(&p, end, reply_struct_v, bad); |
| 278 | + ceph_decode_8_safe(p, end, reply_struct_v, bad); |
| 280 | 279 | if (reply_struct_v != 1) |
| 281 | 280 | return -EINVAL; |
| 282 | 281 | |
| 283 | | − ceph_decode_32_safe(&p, end, num, bad); |
| 282 | + ceph_decode_32_safe(p, end, num, bad); |
| 284 | 283 | dout("%d tickets\n", num); |
| 285 | 284 | |
| 286 | 285 | while (num--) { |
| 287 | | − ret = process_one_ticket(ac, secret, &p, end); |
| 286 | + ret = process_one_ticket(ac, secret, p, end); |
| 288 | 287 | if (ret) |
| 289 | 288 | return ret; |
| 290 | 289 | } |
| @@ -527,7 +526,7 @@ static int ceph_x_build_request(struct ceph_auth_client *ac, · 236 unmodified lines |
| 527 | 526 | if (ret < 0) |
| 528 | 527 | return ret; |
| 529 | 528 | |
| 530 | | − auth->struct_v = 1; |
| 529 | + auth->struct_v = 2; /* nautilus+ */ |
| 531 | 530 | auth->key = 0; |
| 532 | 531 | for (u = (u64 *)enc_buf; u + 1 <= (u64 *)(enc_buf + ret); u++) |
| 533 | 532 | auth->key ^= *(__le64 *)u; |
| @@ -540,6 +539,10 @@ static int ceph_x_build_request(struct ceph_auth_client *ac, · 6 unmodified lines |
| 540 | 539 | if (ret < 0) |
| 541 | 540 | return ret; |
| 542 | 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); |
| 543 | 546 | return p - buf; |
| 544 | 547 | } |
| 545 | 548 | |
| @@ -566,8 +569,82 @@ e_range: · 20 unmodified lines |
| 566 | 569 | return -ERANGE; |
| 567 | 570 | } |
| 568 | 571 | |
| 572 | +static int handle_auth_session_key(struct ceph_auth_client *ac, |
| 573 | + void **p, void *end, |
| 574 | + u8 *session_key, int *session_key_len, |
| 575 | + u8 *con_secret, int *con_secret_len) |
| 576 | +{ |
| 577 | + struct ceph_x_info *xi = ac->private; |
| 578 | + struct ceph_x_ticket_handler *th; |
| 579 | + void *dp, *dend; |
| 580 | + int len; |
| 581 | + int ret; |
| 582 | + |
| 583 | + /* AUTH ticket */ |
| 584 | + ret = ceph_x_proc_ticket_reply(ac, &xi->secret, p, end); |
| 585 | + if (ret) |
| 586 | + return ret; |
| 587 | + |
| 588 | + if (*p == end) { |
| 589 | + /* pre-nautilus (or didn't request service tickets!) */ |
| 590 | + WARN_ON(session_key || con_secret); |
| 591 | + return 0; |
| 592 | + } |
| 593 | + |
| 594 | + th = get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH); |
| 595 | + if (IS_ERR(th)) |
| 596 | + return PTR_ERR(th); |
| 597 | + |
| 598 | + if (session_key) { |
| 599 | + memcpy(session_key, th->session_key.key, th->session_key.len); |
| 600 | + *session_key_len = th->session_key.len; |
| 601 | + } |
| 602 | + |
| 603 | + /* connection secret */ |
| 604 | + ceph_decode_32_safe(p, end, len, e_inval); |
| 605 | + dout("%s connection secret blob len %d\n", __func__, len); |
| 606 | + if (len > 0) { |
| 607 | + dp = *p + ceph_x_encrypt_offset(); |
| 608 | + ret = ceph_x_decrypt(&th->session_key, p, *p + len); |
| 609 | + if (ret < 0) |
| 610 | + return ret; |
| 611 | + |
| 612 | + dout("%s decrypted %d bytes\n", __func__, ret); |
| 613 | + dend = dp + ret; |
| 614 | + |
| 615 | + ceph_decode_32_safe(&dp, dend, len, e_inval); |
| 616 | + if (len > CEPH_MAX_CON_SECRET_LEN) { |
| 617 | + pr_err("connection secret too big %d\n", len); |
| 618 | + return -EINVAL; |
| 619 | + } |
| 620 | + |
| 621 | + dout("%s connection secret len %d\n", __func__, len); |
| 622 | + if (con_secret) { |
| 623 | + memcpy(con_secret, dp, len); |
| 624 | + *con_secret_len = len; |
| 625 | + } |
| 626 | + } |
| 627 | + |
| 628 | + /* service tickets */ |
| 629 | + ceph_decode_32_safe(p, end, len, e_inval); |
| 630 | + dout("%s service tickets blob len %d\n", __func__, len); |
| 631 | + if (len > 0) { |
| 632 | + ret = ceph_x_proc_ticket_reply(ac, &th->session_key, |
| 633 | + p, *p + len); |
| 634 | + if (ret) |
| 635 | + return ret; |
| 636 | + } |
| 637 | + |
| 638 | + return 0; |
| 639 | + |
| 640 | +e_inval: |
| 641 | + return -EINVAL; |
| 642 | +} |
| 643 | + |
| 569 | 644 | static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result, |
| 570 | | − void *buf, void *end) |
| 645 | + void *buf, void *end, |
| 646 | + u8 *session_key, int *session_key_len, |
| 647 | + u8 *con_secret, int *con_secret_len) |
| 571 | 648 | { |
| 572 | 649 | struct ceph_x_info *xi = ac->private; |
| 573 | 650 | struct ceph_x_ticket_handler *th; |
| @@ -599,8 +676,10 @@ static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result, · 25 unmodified lines |
| 599 | 676 | dout("handle_reply op %d result %d\n", op, result); |
| 600 | 677 | switch (op) { |
| 601 | 678 | case CEPHX_GET_AUTH_SESSION_KEY: |
| 602 | | − /* verify auth key */ |
| 603 | | − ret = ceph_x_proc_ticket_reply(ac, &xi->secret, p, end); |
| 679 | + /* AUTH ticket + [connection secret] + service tickets */ |
| 680 | + ret = handle_auth_session_key(ac, &p, end, session_key, |
| 681 | + session_key_len, con_secret, |
| 682 | + con_secret_len); |
| 604 | 683 | break; |
| 605 | 684 | |
| 606 | 685 | case CEPHX_GET_PRINCIPAL_SESSION_KEY: |
| @@ -608,7 +687,8 @@ static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result, · 1 unmodified line |
| 608 | 687 | if (IS_ERR(th)) |
| 609 | 688 | return PTR_ERR(th); |
| 610 | 689 | |
| 611 | | − ret = ceph_x_proc_ticket_reply(ac, &th->session_key, p, end); |
| 690 | + /* service tickets */ |
| 691 | + ret = ceph_x_proc_ticket_reply(ac, &th->session_key, &p, end); |
| 612 | 692 | break; |
| 613 | 693 | |
| 614 | 694 | default: |
| @@ -687,40 +767,44 @@ static int ceph_x_update_authorizer( · 72 unmodified lines |
| 687 | 767 | return 0; |
| 688 | 768 | } |
| 689 | 769 | |
| 690 | | −static int decrypt_authorize_challenge(struct ceph_x_authorizer *au, |
| 691 | | − void *challenge_buf, |
| 692 | | − int challenge_buf_len, |
| 693 | | − u64 *server_challenge) |
| 770 | +/* |
| 771 | + * CephXAuthorizeChallenge |
| 772 | + */ |
| 773 | +static int decrypt_authorizer_challenge(struct ceph_crypto_key *secret, |
| 774 | + void *challenge, int challenge_len, |
| 775 | + u64 *server_challenge) |
| 694 | 776 | { |
| 695 | | − struct ceph_x_authorize_challenge *ch = |
| 696 | | − challenge_buf + sizeof(struct ceph_x_encrypt_header); |
| 777 | + void *dp, *dend; |
| 697 | 778 | int ret; |
| 698 | 779 | |
| 699 | 780 | /* no leading len */ |
| 700 | | − ret = __ceph_x_decrypt(&au->session_key, challenge_buf, |
| 701 | | − challenge_buf_len); |
| 781 | + ret = __ceph_x_decrypt(secret, challenge, challenge_len); |
| 702 | 782 | if (ret < 0) |
| 703 | 783 | return ret; |
| 704 | | − if (ret < sizeof(*ch)) { |
| 705 | | − pr_err("bad size %d for ceph_x_authorize_challenge\n", ret); |
| 706 | | − return -EINVAL; |
| 707 | | − } |
| 708 | 784 | |
| 709 | | − *server_challenge = le64_to_cpu(ch->server_challenge); |
| 785 | + dout("%s decrypted %d bytes\n", __func__, ret); |
| 786 | + dp = challenge + sizeof(struct ceph_x_encrypt_header); |
| 787 | + dend = dp + ret; |
| 788 | + |
| 789 | + ceph_decode_skip_8(&dp, dend, e_inval); /* struct_v */ |
| 790 | + ceph_decode_64_safe(&dp, dend, *server_challenge, e_inval); |
| 791 | + dout("%s server_challenge %llu\n", __func__, *server_challenge); |
| 710 | 792 | return 0; |
| 793 | + |
| 794 | +e_inval: |
| 795 | + return -EINVAL; |
| 711 | 796 | } |
| 712 | 797 | |
| 713 | 798 | static int ceph_x_add_authorizer_challenge(struct ceph_auth_client *ac, |
| 714 | 799 | struct ceph_authorizer *a, |
| 715 | | − void *challenge_buf, |
| 716 | | − int challenge_buf_len) |
| 800 | + void *challenge, int challenge_len) |
| 717 | 801 | { |
| 718 | 802 | struct ceph_x_authorizer *au = (void *)a; |
| 719 | 803 | u64 server_challenge; |
| 720 | 804 | int ret; |
| 721 | 805 | |
| 722 | | − ret = decrypt_authorize_challenge(au, challenge_buf, challenge_buf_len, |
| 723 | | − &server_challenge); |
| 806 | + ret = decrypt_authorizer_challenge(&au->session_key, challenge, |
| 807 | + challenge_len, &server_challenge); |
| 724 | 808 | if (ret) { |
| 725 | 809 | pr_err("failed to decrypt authorize challenge: %d", ret); |
| 726 | 810 | return ret; |
| @@ -735,29 +819,76 @@ static int ceph_x_add_authorizer_challenge(struct ceph_auth_client *ac, · 8 unmodified lines |
| 735 | 819 | return 0; |
| 736 | 820 | } |
| 737 | 821 | |
| 822 | +/* |
| 823 | + * CephXAuthorizeReply |
| 824 | + */ |
| 825 | +static int decrypt_authorizer_reply(struct ceph_crypto_key *secret, |
| 826 | + void **p, void *end, u64 *nonce_plus_one, |
| 827 | + u8 *con_secret, int *con_secret_len) |
| 828 | +{ |
| 829 | + void *dp, *dend; |
| 830 | + u8 struct_v; |
| 831 | + int len; |
| 832 | + int ret; |
| 833 | + |
| 834 | + dp = *p + ceph_x_encrypt_offset(); |
| 835 | + ret = ceph_x_decrypt(secret, p, end); |
| 836 | + if (ret < 0) |
| 837 | + return ret; |
| 838 | + |
| 839 | + dout("%s decrypted %d bytes\n", __func__, ret); |
| 840 | + dend = dp + ret; |
| 841 | + |
| 842 | + ceph_decode_8_safe(&dp, dend, struct_v, e_inval); |
| 843 | + ceph_decode_64_safe(&dp, dend, *nonce_plus_one, e_inval); |
| 844 | + dout("%s nonce_plus_one %llu\n", __func__, *nonce_plus_one); |
| 845 | + if (struct_v >= 2) { |
| 846 | + ceph_decode_32_safe(&dp, dend, len, e_inval); |
| 847 | + if (len > CEPH_MAX_CON_SECRET_LEN) { |
| 848 | + pr_err("connection secret too big %d\n", len); |
| 849 | + return -EINVAL; |
| 850 | + } |
| 851 | + |
| 852 | + dout("%s connection secret len %d\n", __func__, len); |
| 853 | + if (con_secret) { |
| 854 | + memcpy(con_secret, dp, len); |
| 855 | + *con_secret_len = len; |
| 856 | + } |
| 857 | + } |
| 858 | + |
| 859 | + return 0; |
| 860 | + |
| 861 | +e_inval: |
| 862 | + return -EINVAL; |
| 863 | +} |
| 864 | + |
| 738 | 865 | static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac, |
| 739 | | − struct ceph_authorizer *a) |
| 866 | + struct ceph_authorizer *a, |
| 867 | + void *reply, int reply_len, |
| 868 | + u8 *session_key, int *session_key_len, |
| 869 | + u8 *con_secret, int *con_secret_len) |
| 740 | 870 | { |
| 741 | 871 | struct ceph_x_authorizer *au = (void *)a; |
| 742 | | − void *p = au->enc_buf; |
| 743 | | − struct ceph_x_authorize_reply *reply = p + ceph_x_encrypt_offset(); |
| 872 | + u64 nonce_plus_one; |
| 744 | 873 | int ret; |
| 745 | 874 | |
| 746 | | − ret = ceph_x_decrypt(&au->session_key, &p, p + CEPHX_AU_ENC_BUF_LEN); |
| 747 | | − if (ret < 0) |
| 875 | + if (session_key) { |
| 876 | + memcpy(session_key, au->session_key.key, au->session_key.len); |
| 877 | + *session_key_len = au->session_key.len; |
| 878 | + } |
| 879 | + |
| 880 | + ret = decrypt_authorizer_reply(&au->session_key, &reply, |
| 881 | + reply + reply_len, &nonce_plus_one, |
| 882 | + con_secret, con_secret_len); |
| 883 | + if (ret) |
| 748 | 884 | return ret; |
| 749 | | − if (ret < sizeof(*reply)) { |
| 750 | | − pr_err("bad size %d for ceph_x_authorize_reply\n", ret); |
| 751 | | − return -EINVAL; |
| 885 | + |
| 886 | + if (nonce_plus_one != au->nonce + 1) { |
| 887 | + pr_err("failed to authenticate server\n"); |
| 888 | + return -EPERM; |
| 752 | 889 | } |
| 753 | 890 | |
| 754 | | − if (au->nonce + 1 != le64_to_cpu(reply->nonce_plus_one)) |
| 755 | | − ret = -EPERM; |
| 756 | | − else |
| 757 | | − ret = 0; |
| 758 | | − dout("verify_authorizer_reply nonce %llx got %llx ret %d\n", |
| 759 | | − au->nonce, le64_to_cpu(reply->nonce_plus_one), ret); |
| 760 | | − return ret; |
| 891 | + return 0; |
| 761 | 892 | } |
| 762 | 893 | |
| 763 | 894 | static void ceph_x_reset(struct ceph_auth_client *ac) |