From 1adf313ef94aa2652e803e1808facacaa8f0572f Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Wed, 16 Jan 2019 10:46:34 -0600 Subject: [PATCH] auth/cephx: share all tickets and connection_secret in initial reply Previously, we would give the client the auth ticket, like a rbd TGT (ticket granting ticket), and the client would then ask for all of the other tickets it wants in a separate message. Instead, have the client specify which tickets it wants up front and pass them all at the same time. Also, generate and share the connection_secret, which will be used for encryption. Signed-off-by: Sage Weil --- src/auth/cephx/CephxClientHandler.cc | 49 +++++++++++++++++++++++++-- src/auth/cephx/CephxClientHandler.h | 5 +-- src/auth/cephx/CephxProtocol.cc | 17 +++++----- src/auth/cephx/CephxProtocol.h | 31 ++++++++++------- src/auth/cephx/CephxServiceHandler.cc | 46 +++++++++++++++++++++++-- 5 files changed, 118 insertions(+), 30 deletions(-) diff --git a/src/auth/cephx/CephxClientHandler.cc b/src/auth/cephx/CephxClientHandler.cc index 64924777e5b..9d0df43a8c4 100644 --- a/src/auth/cephx/CephxClientHandler.cc +++ b/src/auth/cephx/CephxClientHandler.cc @@ -28,6 +28,13 @@ #undef dout_prefix #define dout_prefix *_dout << "cephx client: " +void CephxClientHandler::reset() +{ + ldout(cct,10) << __func__ << dendl; + starting = true; + server_challenge = 0; +} + int CephxClientHandler::build_request(bufferlist& bl) const { ldout(cct, 10) << "build_request" << dendl; @@ -63,6 +70,9 @@ int CephxClientHandler::build_request(bufferlist& bl) const req.old_ticket = ticket_handler->ticket; + // for nautilus+ servers: request other keys at the same time + req.other_keys = need; + if (req.old_ticket.blob.length()) { ldout(cct, 20) << "old ticket len=" << req.old_ticket.blob.length() << dendl; } @@ -111,7 +121,7 @@ int CephxClientHandler::handle_response( CryptoKey *session_key, CryptoKey *connection_secret) { - ldout(cct, 10) << "handle_response ret = " << ret << dendl; + ldout(cct, 10) << this << " handle_response ret = " << ret << dendl; if (ret < 0) return ret; // hrm! @@ -147,12 +157,47 @@ int CephxClientHandler::handle_response( return -EPERM; } ldout(cct, 10) << " want=" << want << " need=" << need << " have=" << have << dendl; + if (!indata.end()) { + bufferlist cbl, extra_tickets; + decode(cbl, indata); + decode(extra_tickets, indata); + ldout(cct, 10) << " got connection bl " << cbl.length() + << " and extra tickets " << extra_tickets.length() + << dendl; + if (session_key && connection_secret) { + CephXTicketHandler& ticket_handler = + tickets.get_handler(CEPH_ENTITY_TYPE_AUTH); + if (session_key) { + *session_key = ticket_handler.session_key; + } + if (cbl.length() && connection_secret) { + auto p = cbl.cbegin(); + string err; + if (decode_decrypt(cct, *connection_secret, *session_key, p, + err) < 0) { + lderr(cct) << __func__ << " failed to decrypt connection_secret" + << dendl; + } else { + ldout(cct, 10) << " got connection_secret " << dendl; + } + } + if (extra_tickets.length()) { + auto p = extra_tickets.cbegin(); + if (!tickets.verify_service_ticket_reply( + *session_key, p)) { + lderr(cct) << "could not verify extra service_tickets" << dendl; + } else { + ldout(cct, 10) << " got extra service_tickets" << dendl; + } + } + } + } validate_tickets(); if (_need_tickets()) ret = -EAGAIN; else ret = 0; - } + } break; case CEPHX_GET_PRINCIPAL_SESSION_KEY: diff --git a/src/auth/cephx/CephxClientHandler.h b/src/auth/cephx/CephxClientHandler.h index 63a4c7a513b..f56bc1d9137 100644 --- a/src/auth/cephx/CephxClientHandler.h +++ b/src/auth/cephx/CephxClientHandler.h @@ -48,10 +48,7 @@ public: reset(); } - void reset() override { - starting = true; - server_challenge = 0; - } + void reset() override; void prepare_build_request() override; int build_request(bufferlist& bl) const override; int handle_response(int ret, bufferlist::const_iterator& iter, diff --git a/src/auth/cephx/CephxProtocol.cc b/src/auth/cephx/CephxProtocol.cc index 6aa99d9bb52..eca2a1e9b83 100644 --- a/src/auth/cephx/CephxProtocol.cc +++ b/src/auth/cephx/CephxProtocol.cc @@ -56,9 +56,12 @@ bool cephx_build_service_ticket_blob(CephContext *cct, CephXSessionAuthInfo& inf ticket_info.ticket = info.ticket; ticket_info.ticket.caps = info.ticket.caps; - ldout(cct, 10) << "build_service_ticket service " << ceph_entity_type_name(info.service_id) - << " secret_id " << info.secret_id - << " ticket_info.ticket.name=" << ticket_info.ticket.name.to_str() << dendl; + ldout(cct, 10) << "build_service_ticket service " + << ceph_entity_type_name(info.service_id) + << " secret_id " << info.secret_id + << " ticket_info.ticket.name=" + << ticket_info.ticket.name.to_str() + << " ticket.global_id " << info.ticket.global_id << dendl; blob.secret_id = info.secret_id; std::string error; if (!info.service_secret.get_secret().length()) @@ -142,8 +145,9 @@ bool cephx_build_service_ticket_reply(CephContext *cct, * PRINCIPAL: verify our attempt to authenticate succeeded. fill out * this ServiceTicket with the result. */ -bool CephXTicketHandler::verify_service_ticket_reply(CryptoKey& secret, - bufferlist::const_iterator& indata) +bool CephXTicketHandler::verify_service_ticket_reply( + CryptoKey& secret, + bufferlist::const_iterator& indata) { __u8 service_ticket_v; decode(service_ticket_v, indata); @@ -282,9 +286,6 @@ bool CephXTicketManager::verify_service_ticket_reply(CryptoKey& secret, handler.service_id = type; } - if (!indata.end()) - return false; - return true; } diff --git a/src/auth/cephx/CephxProtocol.h b/src/auth/cephx/CephxProtocol.h index 78cb003d337..49793b59a88 100644 --- a/src/auth/cephx/CephxProtocol.h +++ b/src/auth/cephx/CephxProtocol.h @@ -122,23 +122,28 @@ struct CephXAuthenticate { uint64_t client_challenge; uint64_t key; CephXTicketBlob old_ticket; + uint32_t other_keys = 0; // replaces CephXServiceTicketRequest void encode(bufferlist& bl) const { - using ceph::encode; - __u8 struct_v = 1; - encode(struct_v, bl); - encode(client_challenge, bl); - encode(key, bl); - encode(old_ticket, bl); + using ceph::encode; + __u8 struct_v = 2; + encode(struct_v, bl); + encode(client_challenge, bl); + encode(key, bl); + encode(old_ticket, bl); + encode(other_keys, bl); } void decode(bufferlist::const_iterator& bl) { - using ceph::decode; - __u8 struct_v; - decode(struct_v, bl); - decode(client_challenge, bl); - decode(key, bl); - decode(old_ticket, bl); - } + using ceph::decode; + __u8 struct_v; + decode(struct_v, bl); + decode(client_challenge, bl); + decode(key, bl); + decode(old_ticket, bl); + if (struct_v >= 2) { + decode(other_keys, bl); + } + } }; WRITE_CLASS_ENCODER(CephXAuthenticate) diff --git a/src/auth/cephx/CephxServiceHandler.cc b/src/auth/cephx/CephxServiceHandler.cc index 22426d38329..a89c1532354 100644 --- a/src/auth/cephx/CephxServiceHandler.cc +++ b/src/auth/cephx/CephxServiceHandler.cc @@ -52,8 +52,8 @@ int CephxServiceHandler::handle_request( bufferlist *result_bl, uint64_t *global_id, AuthCapsInfo *caps, - CryptoKey *session_key, - CryptoKey *connection_secret) + CryptoKey *psession_key, + CryptoKey *pconnection_secret) { int ret = 0; @@ -119,6 +119,8 @@ int CephxServiceHandler::handle_request( should_enc_ticket = true; } + ldout(cct,10) << __func__ << " auth ticket global_id " << *global_id + << dendl; info.ticket.init_timestamps(ceph_clock_now(), cct->_conf->auth_mon_ticket_ttl); info.ticket.name = entity_name; @@ -128,6 +130,9 @@ int CephxServiceHandler::handle_request( key_server->generate_secret(session_key); info.session_key = session_key; + if (psession_key) { + *psession_key = session_key; + } info.service_id = CEPH_ENTITY_TYPE_AUTH; if (!key_server->get_service_secret(CEPH_ENTITY_TYPE_AUTH, info.service_secret, info.secret_id)) { ldout(cct, 0) << " could not get service secret for auth subsystem" << dendl; @@ -158,6 +163,42 @@ int CephxServiceHandler::handle_request( ret = -EACCES; break; } + + if (req.other_keys) { + // nautilus+ client + // generate a connection_secret + bufferlist cbl; + if (pconnection_secret) { + key_server->generate_secret(*pconnection_secret); + string err; + encode_encrypt(cct, *pconnection_secret, session_key, cbl, err); + } + encode(cbl, *result_bl); + // provite all of the other tickets at the same time + vector info_vec; + for (uint32_t service_id = 1; service_id <= req.other_keys; + service_id <<= 1) { + if (req.other_keys & service_id) { + ldout(cct, 10) << " adding key for service " + << ceph_entity_type_name(service_id) << dendl; + CephXSessionAuthInfo svc_info; + key_server->build_session_auth_info( + service_id, + info.ticket, + svc_info); + svc_info.validity += cct->_conf->auth_service_ticket_ttl; + info_vec.push_back(svc_info); + } + } + bufferlist extra; + if (!info_vec.empty()) { + CryptoKey no_key; + cephx_build_service_ticket_reply( + cct, session_key, info_vec, false, no_key, extra); + } + encode(extra, *result_bl); + } + // caller should try to finish authentication ret = 1; } @@ -173,7 +214,6 @@ int CephxServiceHandler::handle_request( // note: no challenge here. if (!cephx_verify_authorizer( cct, key_server, indata, auth_ticket_info, nullptr, -#warning FIXME mon connection needs connection_secret too nullptr, tmp_bl)) { ret = -EPERM; -- 2.39.5