Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libceph, ceph: incorporate nautilus cephx changes

- 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>

+211 -54
+4 -1
fs/ceph/mds_client.c
··· 5178 5178 struct ceph_mds_session *s = con->private; 5179 5179 struct ceph_mds_client *mdsc = s->s_mdsc; 5180 5180 struct ceph_auth_client *ac = mdsc->fsc->client->monc.auth; 5181 + struct ceph_auth_handshake *auth = &s->s_auth; 5181 5182 5182 - return ceph_auth_verify_authorizer_reply(ac, s->s_auth.authorizer); 5183 + return ceph_auth_verify_authorizer_reply(ac, auth->authorizer, 5184 + auth->authorizer_reply_buf, auth->authorizer_reply_buf_len, 5185 + NULL, NULL, NULL, NULL); 5183 5186 } 5184 5187 5185 5188 static int invalidate_authorizer(struct ceph_connection *con)
+12 -4
include/linux/ceph/auth.h
··· 53 53 */ 54 54 int (*build_request)(struct ceph_auth_client *ac, void *buf, void *end); 55 55 int (*handle_reply)(struct ceph_auth_client *ac, int result, 56 - void *buf, void *end); 56 + void *buf, void *end, u8 *session_key, 57 + int *session_key_len, u8 *con_secret, 58 + int *con_secret_len); 57 59 58 60 /* 59 61 * Create authorizer for connecting to a service, and verify ··· 71 69 void *challenge_buf, 72 70 int challenge_buf_len); 73 71 int (*verify_authorizer_reply)(struct ceph_auth_client *ac, 74 - struct ceph_authorizer *a); 72 + struct ceph_authorizer *a, 73 + void *reply, int reply_len, 74 + u8 *session_key, int *session_key_len, 75 + u8 *con_secret, int *con_secret_len); 75 76 void (*invalidate_authorizer)(struct ceph_auth_client *ac, 76 77 int peer_type); 77 78 ··· 131 126 struct ceph_authorizer *a, 132 127 void *challenge_buf, 133 128 int challenge_buf_len); 134 - extern int ceph_auth_verify_authorizer_reply(struct ceph_auth_client *ac, 135 - struct ceph_authorizer *a); 129 + int ceph_auth_verify_authorizer_reply(struct ceph_auth_client *ac, 130 + struct ceph_authorizer *a, 131 + void *reply, int reply_len, 132 + u8 *session_key, int *session_key_len, 133 + u8 *con_secret, int *con_secret_len); 136 134 extern void ceph_auth_invalidate_authorizer(struct ceph_auth_client *ac, 137 135 int peer_type); 138 136
+9 -3
net/ceph/auth.c
··· 240 240 ac->negotiating = false; 241 241 } 242 242 243 - ret = ac->ops->handle_reply(ac, result, payload, payload_end); 243 + ret = ac->ops->handle_reply(ac, result, payload, payload_end, 244 + NULL, NULL, NULL, NULL); 244 245 if (ret == -EAGAIN) { 245 246 ret = ceph_build_auth_request(ac, reply_buf, reply_len); 246 247 } else if (ret) { ··· 333 332 EXPORT_SYMBOL(ceph_auth_add_authorizer_challenge); 334 333 335 334 int ceph_auth_verify_authorizer_reply(struct ceph_auth_client *ac, 336 - struct ceph_authorizer *a) 335 + struct ceph_authorizer *a, 336 + void *reply, int reply_len, 337 + u8 *session_key, int *session_key_len, 338 + u8 *con_secret, int *con_secret_len) 337 339 { 338 340 int ret = 0; 339 341 340 342 mutex_lock(&ac->mutex); 341 343 if (ac->ops && ac->ops->verify_authorizer_reply) 342 - ret = ac->ops->verify_authorizer_reply(ac, a); 344 + ret = ac->ops->verify_authorizer_reply(ac, a, 345 + reply, reply_len, session_key, session_key_len, 346 + con_secret, con_secret_len); 343 347 mutex_unlock(&ac->mutex); 344 348 return ret; 345 349 }
+3 -1
net/ceph/auth_none.c
··· 70 70 * authenticate state, so nothing happens here. 71 71 */ 72 72 static int handle_reply(struct ceph_auth_client *ac, int result, 73 - void *buf, void *end) 73 + void *buf, void *end, u8 *session_key, 74 + int *session_key_len, u8 *con_secret, 75 + int *con_secret_len) 74 76 { 75 77 struct ceph_auth_none_info *xi = ac->private; 76 78
+174 -43
net/ceph/auth_x.c
··· 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 } ··· 526 527 if (ret < 0) 527 528 return ret; 528 529 529 - auth->struct_v = 1; 530 + auth->struct_v = 2; /* nautilus+ */ 530 531 auth->key = 0; 531 532 for (u = (u64 *)enc_buf; u + 1 <= (u64 *)(enc_buf + ret); u++) 532 533 auth->key ^= *(__le64 *)u; ··· 539 540 if (ret < 0) 540 541 return ret; 541 542 543 + /* nautilus+: request service tickets at the same time */ 544 + need = ac->want_keys & ~CEPH_ENTITY_TYPE_AUTH; 545 + WARN_ON(!need); 546 + ceph_encode_32_safe(&p, end, need, e_range); 542 547 return p - buf; 543 548 } 544 549 ··· 569 566 return -ERANGE; 570 567 } 571 568 569 + static int handle_auth_session_key(struct ceph_auth_client *ac, 570 + void **p, void *end, 571 + u8 *session_key, int *session_key_len, 572 + u8 *con_secret, int *con_secret_len) 573 + { 574 + struct ceph_x_info *xi = ac->private; 575 + struct ceph_x_ticket_handler *th; 576 + void *dp, *dend; 577 + int len; 578 + int ret; 579 + 580 + /* AUTH ticket */ 581 + ret = ceph_x_proc_ticket_reply(ac, &xi->secret, p, end); 582 + if (ret) 583 + return ret; 584 + 585 + if (*p == end) { 586 + /* pre-nautilus (or didn't request service tickets!) */ 587 + WARN_ON(session_key || con_secret); 588 + return 0; 589 + } 590 + 591 + th = get_ticket_handler(ac, CEPH_ENTITY_TYPE_AUTH); 592 + if (IS_ERR(th)) 593 + return PTR_ERR(th); 594 + 595 + if (session_key) { 596 + memcpy(session_key, th->session_key.key, th->session_key.len); 597 + *session_key_len = th->session_key.len; 598 + } 599 + 600 + /* connection secret */ 601 + ceph_decode_32_safe(p, end, len, e_inval); 602 + dout("%s connection secret blob len %d\n", __func__, len); 603 + if (len > 0) { 604 + dp = *p + ceph_x_encrypt_offset(); 605 + ret = ceph_x_decrypt(&th->session_key, p, *p + len); 606 + if (ret < 0) 607 + return ret; 608 + 609 + dout("%s decrypted %d bytes\n", __func__, ret); 610 + dend = dp + ret; 611 + 612 + ceph_decode_32_safe(&dp, dend, len, e_inval); 613 + if (len > CEPH_MAX_CON_SECRET_LEN) { 614 + pr_err("connection secret too big %d\n", len); 615 + return -EINVAL; 616 + } 617 + 618 + dout("%s connection secret len %d\n", __func__, len); 619 + if (con_secret) { 620 + memcpy(con_secret, dp, len); 621 + *con_secret_len = len; 622 + } 623 + } 624 + 625 + /* service tickets */ 626 + ceph_decode_32_safe(p, end, len, e_inval); 627 + dout("%s service tickets blob len %d\n", __func__, len); 628 + if (len > 0) { 629 + ret = ceph_x_proc_ticket_reply(ac, &th->session_key, 630 + p, *p + len); 631 + if (ret) 632 + return ret; 633 + } 634 + 635 + return 0; 636 + 637 + e_inval: 638 + return -EINVAL; 639 + } 640 + 572 641 static int ceph_x_handle_reply(struct ceph_auth_client *ac, int result, 573 - void *buf, void *end) 642 + void *buf, void *end, 643 + u8 *session_key, int *session_key_len, 644 + u8 *con_secret, int *con_secret_len) 574 645 { 575 646 struct ceph_x_info *xi = ac->private; 576 647 struct ceph_x_ticket_handler *th; ··· 676 599 dout("handle_reply op %d result %d\n", op, result); 677 600 switch (op) { 678 601 case CEPHX_GET_AUTH_SESSION_KEY: 679 - /* verify auth key */ 680 - ret = ceph_x_proc_ticket_reply(ac, &xi->secret, p, end); 602 + /* AUTH ticket + [connection secret] + service tickets */ 603 + ret = handle_auth_session_key(ac, &p, end, session_key, 604 + session_key_len, con_secret, 605 + con_secret_len); 681 606 break; 682 607 683 608 case CEPHX_GET_PRINCIPAL_SESSION_KEY: ··· 687 608 if (IS_ERR(th)) 688 609 return PTR_ERR(th); 689 610 690 - ret = ceph_x_proc_ticket_reply(ac, &th->session_key, p, end); 611 + /* service tickets */ 612 + ret = ceph_x_proc_ticket_reply(ac, &th->session_key, &p, end); 691 613 break; 692 614 693 615 default: ··· 767 687 return 0; 768 688 } 769 689 770 - static int decrypt_authorize_challenge(struct ceph_x_authorizer *au, 771 - void *challenge_buf, 772 - int challenge_buf_len, 773 - u64 *server_challenge) 690 + /* 691 + * CephXAuthorizeChallenge 692 + */ 693 + static int decrypt_authorizer_challenge(struct ceph_crypto_key *secret, 694 + void *challenge, int challenge_len, 695 + u64 *server_challenge) 774 696 { 775 - struct ceph_x_authorize_challenge *ch = 776 - challenge_buf + sizeof(struct ceph_x_encrypt_header); 697 + void *dp, *dend; 777 698 int ret; 778 699 779 700 /* no leading len */ 780 - ret = __ceph_x_decrypt(&au->session_key, challenge_buf, 781 - challenge_buf_len); 701 + ret = __ceph_x_decrypt(secret, challenge, challenge_len); 782 702 if (ret < 0) 783 703 return ret; 784 - if (ret < sizeof(*ch)) { 785 - pr_err("bad size %d for ceph_x_authorize_challenge\n", ret); 786 - return -EINVAL; 787 - } 788 704 789 - *server_challenge = le64_to_cpu(ch->server_challenge); 705 + dout("%s decrypted %d bytes\n", __func__, ret); 706 + dp = challenge + sizeof(struct ceph_x_encrypt_header); 707 + dend = dp + ret; 708 + 709 + ceph_decode_skip_8(&dp, dend, e_inval); /* struct_v */ 710 + ceph_decode_64_safe(&dp, dend, *server_challenge, e_inval); 711 + dout("%s server_challenge %llu\n", __func__, *server_challenge); 790 712 return 0; 713 + 714 + e_inval: 715 + return -EINVAL; 791 716 } 792 717 793 718 static int ceph_x_add_authorizer_challenge(struct ceph_auth_client *ac, 794 719 struct ceph_authorizer *a, 795 - void *challenge_buf, 796 - int challenge_buf_len) 720 + void *challenge, int challenge_len) 797 721 { 798 722 struct ceph_x_authorizer *au = (void *)a; 799 723 u64 server_challenge; 800 724 int ret; 801 725 802 - ret = decrypt_authorize_challenge(au, challenge_buf, challenge_buf_len, 803 - &server_challenge); 726 + ret = decrypt_authorizer_challenge(&au->session_key, challenge, 727 + challenge_len, &server_challenge); 804 728 if (ret) { 805 729 pr_err("failed to decrypt authorize challenge: %d", ret); 806 730 return ret; ··· 819 735 return 0; 820 736 } 821 737 822 - static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac, 823 - struct ceph_authorizer *a) 738 + /* 739 + * CephXAuthorizeReply 740 + */ 741 + static int decrypt_authorizer_reply(struct ceph_crypto_key *secret, 742 + void **p, void *end, u64 *nonce_plus_one, 743 + u8 *con_secret, int *con_secret_len) 824 744 { 825 - struct ceph_x_authorizer *au = (void *)a; 826 - void *p = au->enc_buf; 827 - struct ceph_x_authorize_reply *reply = p + ceph_x_encrypt_offset(); 745 + void *dp, *dend; 746 + u8 struct_v; 747 + int len; 828 748 int ret; 829 749 830 - ret = ceph_x_decrypt(&au->session_key, &p, p + CEPHX_AU_ENC_BUF_LEN); 750 + dp = *p + ceph_x_encrypt_offset(); 751 + ret = ceph_x_decrypt(secret, p, end); 831 752 if (ret < 0) 832 753 return ret; 833 - if (ret < sizeof(*reply)) { 834 - pr_err("bad size %d for ceph_x_authorize_reply\n", ret); 835 - return -EINVAL; 754 + 755 + dout("%s decrypted %d bytes\n", __func__, ret); 756 + dend = dp + ret; 757 + 758 + ceph_decode_8_safe(&dp, dend, struct_v, e_inval); 759 + ceph_decode_64_safe(&dp, dend, *nonce_plus_one, e_inval); 760 + dout("%s nonce_plus_one %llu\n", __func__, *nonce_plus_one); 761 + if (struct_v >= 2) { 762 + ceph_decode_32_safe(&dp, dend, len, e_inval); 763 + if (len > CEPH_MAX_CON_SECRET_LEN) { 764 + pr_err("connection secret too big %d\n", len); 765 + return -EINVAL; 766 + } 767 + 768 + dout("%s connection secret len %d\n", __func__, len); 769 + if (con_secret) { 770 + memcpy(con_secret, dp, len); 771 + *con_secret_len = len; 772 + } 836 773 } 837 774 838 - if (au->nonce + 1 != le64_to_cpu(reply->nonce_plus_one)) 839 - ret = -EPERM; 840 - else 841 - ret = 0; 842 - dout("verify_authorizer_reply nonce %llx got %llx ret %d\n", 843 - au->nonce, le64_to_cpu(reply->nonce_plus_one), ret); 844 - return ret; 775 + return 0; 776 + 777 + e_inval: 778 + return -EINVAL; 779 + } 780 + 781 + static int ceph_x_verify_authorizer_reply(struct ceph_auth_client *ac, 782 + struct ceph_authorizer *a, 783 + void *reply, int reply_len, 784 + u8 *session_key, int *session_key_len, 785 + u8 *con_secret, int *con_secret_len) 786 + { 787 + struct ceph_x_authorizer *au = (void *)a; 788 + u64 nonce_plus_one; 789 + int ret; 790 + 791 + if (session_key) { 792 + memcpy(session_key, au->session_key.key, au->session_key.len); 793 + *session_key_len = au->session_key.len; 794 + } 795 + 796 + ret = decrypt_authorizer_reply(&au->session_key, &reply, 797 + reply + reply_len, &nonce_plus_one, 798 + con_secret, con_secret_len); 799 + if (ret) 800 + return ret; 801 + 802 + if (nonce_plus_one != au->nonce + 1) { 803 + pr_err("failed to authenticate server\n"); 804 + return -EPERM; 805 + } 806 + 807 + return 0; 845 808 } 846 809 847 810 static void ceph_x_reset(struct ceph_auth_client *ac)
+2 -1
net/ceph/auth_x_protocol.h
··· 38 38 __u8 struct_v; 39 39 __le64 client_challenge; 40 40 __le64 key; 41 - /* ticket blob */ 41 + /* old_ticket blob */ 42 + /* nautilus+: other_keys */ 42 43 } __attribute__ ((packed)); 43 44 44 45 struct ceph_x_service_ticket_request {
+3
net/ceph/crypto.h
··· 5 5 #include <linux/ceph/types.h> 6 6 #include <linux/ceph/buffer.h> 7 7 8 + #define CEPH_KEY_LEN 16 9 + #define CEPH_MAX_CON_SECRET_LEN 64 10 + 8 11 /* 9 12 * cryptographic secret 10 13 */
+4 -1
net/ceph/osd_client.c
··· 5623 5623 struct ceph_osd *o = con->private; 5624 5624 struct ceph_osd_client *osdc = o->o_osdc; 5625 5625 struct ceph_auth_client *ac = osdc->client->monc.auth; 5626 + struct ceph_auth_handshake *auth = &o->o_auth; 5626 5627 5627 - return ceph_auth_verify_authorizer_reply(ac, o->o_auth.authorizer); 5628 + return ceph_auth_verify_authorizer_reply(ac, auth->authorizer, 5629 + auth->authorizer_reply_buf, auth->authorizer_reply_buf_len, 5630 + NULL, NULL, NULL, NULL); 5628 5631 } 5629 5632 5630 5633 static int invalidate_authorizer(struct ceph_connection *con)