| @@ -269,22 +269,21 @@ out: · 268 unmodified lines |
| 269 | | 269 | |
| 270 | static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, | 270 | static int ceph_x_proc_ticket_reply(struct ceph_auth_client *ac, |
| 271 | struct ceph_crypto_key *secret, | 271 | struct ceph_crypto_key *secret, |
| 272 | void *buf, void *end) | 272 | void **p, void *end) |
| 273 | { | 273 | { |
| 274 | void *p = buf; | | |
| 275 | u8 reply_struct_v; | 274 | u8 reply_struct_v; |
| 276 | u32 num; | 275 | u32 num; |
| 277 | int ret; | 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 | if (reply_struct_v != 1) | 279 | if (reply_struct_v != 1) |
| 281 | return -EINVAL; | 280 | return -EINVAL; |
| 282 | | 281 | |
| 283 | ceph_decode_32_safe(&p, end, num, bad); | 282 | ceph_decode_32_safe(p, end, num, bad); |
| 284 | dout("%d tickets\n", num); | 283 | dout("%d tickets\n", num); |
| 285 | | 284 | |
| 286 | while (num--) { | 285 | while (num--) { |
| 287 | ret = process_one_ticket(ac, secret, &p, end); | 286 | ret = process_one_ticket(ac, secret, p, end); |
| 288 | if (ret) | 287 | if (ret) |
| 289 | return ret; | 288 | return ret; |
| 290 | } | 289 | } |
| @@ -527,7 +526,7 @@ static int ceph_x_build_request(struct ceph_auth_client *ac, · 236 unmodified lines |
| 527 | if (ret < 0) | 526 | if (ret < 0) |
| 528 | return ret; | 527 | return ret; |
| 529 | | 528 | |
| 530 | auth->struct_v = 1; | 529 | auth->struct_v = 2; /* nautilus+ */ |
| 531 | auth->key = 0; | 530 | auth->key = 0; |
| 532 | for (u = (u64 *)enc_buf; u + 1 <= (u64 *)(enc_buf + ret); u++) | 531 | for (u = (u64 *)enc_buf; u + 1 <= (u64 *)(enc_buf + ret); u++) |
| 533 | auth->key ^= *(__le64 *)u; | 532 | auth->key ^= *(__le64 *)u; |
| @@ -540,6 +539,10 @@ static int ceph_x_build_request(struct ceph_auth_client *ac, · 6 unmodified lines |
| 540 | if (ret < 0) | 539 | if (ret < 0) |
| 541 | return ret; | 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 | return p - buf; | 546 | return p - buf; |
| 544 | } | 547 | } |
| 545 | | 548 | |
| @@ -566,8 +569,82 @@ e_range: · 20 unmodified lines |
| 566 | return -ERANGE; | 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 | static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result, | 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 | struct ceph_x_info *xi = ac->private; | 649 | struct ceph_x_info *xi = ac->private; |
| 573 | struct ceph_x_ticket_handler *th; | 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 | dout("handle_reply op %d result %d\n", op, result); | 676 | dout("handle_reply op %d result %d\n", op, result); |
| 600 | switch (op) { | 677 | switch (op) { |
| 601 | case CEPHX_GET_AUTH_SESSION_KEY: | 678 | case CEPHX_GET_AUTH_SESSION_KEY: |
| 602 | /* verify auth key */ | 679 | /* AUTH ticket + [connection secret] + service tickets */ |
| 603 | ret = ceph_x_proc_ticket_reply(ac, &xi->secret, p, end); | 680 | ret = handle_auth_session_key(ac, &p, end, session_key, |
| | 681 | session_key_len, con_secret, |
| | 682 | con_secret_len); |
| 604 | break; | 683 | break; |
| 605 | | 684 | |
| 606 | case CEPHX_GET_PRINCIPAL_SESSION_KEY: | 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 | if (IS_ERR(th)) | 687 | if (IS_ERR(th)) |
| 609 | return PTR_ERR(th); | 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 | break; | 692 | break; |
| 613 | | 693 | |
| 614 | default: | 694 | default: |
| @@ -687,40 +767,44 @@ static int ceph_x_update_authorizer( · 72 unmodified lines |
| 687 | return 0; | 767 | return 0; |
| 688 | } | 768 | } |
| 689 | | 769 | |
| 690 | static int decrypt_authorize_challenge(struct ceph_x_authorizer *au, | 770 | /* |
| 691 | void *challenge_buf, | 771 | * CephXAuthorizeChallenge |
| 692 | int challenge_buf_len, | 772 | */ |
| 693 | u64 *server_challenge) | 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 = | 777 | void *dp, *dend; |
| 696 | challenge_buf + sizeof(struct ceph_x_encrypt_header); | | |
| 697 | int ret; | 778 | int ret; |
| 698 | | 779 | |
| 699 | /* no leading len */ | 780 | /* no leading len */ |
| 700 | ret = __ceph_x_decrypt(&au->session_key, challenge_buf, | 781 | ret = __ceph_x_decrypt(secret, challenge, challenge_len); |
| 701 | challenge_buf_len); | | |
| 702 | if (ret < 0) | 782 | if (ret < 0) |
| 703 | return ret; | 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 | return 0; | 792 | return 0; |
| | 793 | |
| | 794 | e_inval: |
| | 795 | return -EINVAL; |
| 711 | } | 796 | } |
| 712 | | 797 | |
| 713 | static int ceph_x_add_authorizer_challenge(struct ceph_auth_client *ac, | 798 | static int ceph_x_add_authorizer_challenge(struct ceph_auth_client *ac, |
| 714 | struct ceph_authorizer *a, | 799 | struct ceph_authorizer *a, |
| 715 | void *challenge_buf, | 800 | void *challenge, int challenge_len) |
| 716 | int challenge_buf_len) | | |
| 717 | { | 801 | { |
| 718 | struct ceph_x_authorizer *au = (void *)a; | 802 | struct ceph_x_authorizer *au = (void *)a; |
| 719 | u64 server_challenge; | 803 | u64 server_challenge; |
| 720 | int ret; | 804 | int ret; |
| 721 | | 805 | |
| 722 | ret = decrypt_authorize_challenge(au, challenge_buf, challenge_buf_len, | 806 | ret = decrypt_authorizer_challenge(&au->session_key, challenge, |
| 723 | &server_challenge); | 807 | challenge_len, &server_challenge); |
| 724 | if (ret) { | 808 | if (ret) { |
| 725 | pr_err("failed to decrypt authorize challenge: %d", ret); | 809 | pr_err("failed to decrypt authorize challenge: %d", ret); |
| 726 | return ret; | 810 | return ret; |
| @@ -735,29 +819,76 @@ static int ceph_x_add_authorizer_challenge(struct ceph_auth_client *ac, · 8 unmodified lines |
| 735 | return 0; | 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 | static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac, | 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 | struct ceph_x_authorizer *au = (void *)a; | 871 | struct ceph_x_authorizer *au = (void *)a; |
| 742 | void *p = au->enc_buf; | 872 | u64 nonce_plus_one; |
| 743 | struct ceph_x_authorize_reply *reply = p + ceph_x_encrypt_offset(); | | |
| 744 | int ret; | 873 | int ret; |
| 745 | | 874 | |
| 746 | ret = ceph_x_decrypt(&au->session_key, &p, p + CEPHX_AU_ENC_BUF_LEN); | 875 | if (session_key) { |
| 747 | if (ret < 0) | 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 | return ret; | 884 | return ret; |
| 749 | if (ret < sizeof(*reply)) { | 885 | |
| 750 | pr_err("bad size %d for ceph_x_authorize_reply\n", ret); | 886 | if (nonce_plus_one != au->nonce + 1) { |
| 751 | return -EINVAL; | 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)) | 891 | return 0; |
| 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; | | |
| 761 | } | 892 | } |
| 762 | | 893 | |
| 763 | static void ceph_x_reset(struct ceph_auth_client *ac) | 894 | static void ceph_x_reset(struct ceph_auth_client *ac) |