Skip to content

Commit 5ead971

Browse files
committed
auth/cephx: add authorizer challenge
Allow the accepting side of a connection to reject an initial authorizer with a random challenge. The connecting side then has to respond with an updated authorizer proving they are able to decrypt the service's challenge and that the new authorizer was produced for this specific connection instance. The accepting side requires this challenge and response unconditionally if the client side advertises they have the feature bit. Servers wishing to require this improved level of authentication simply have to require the appropriate feature. Signed-off-by: Sage Weil <sage@redhat.com> (cherry picked from commit f80b848) # Conflicts: # src/auth/Auth.h # src/auth/cephx/CephxProtocol.cc # src/auth/cephx/CephxProtocol.h # src/auth/none/AuthNoneProtocol.h # src/msg/Dispatcher.h # src/msg/async/AsyncConnection.cc - const_iterator - ::decode vs decode - AsyncConnection ctor arg noise - get_random_bytes(), not cct->random()
1 parent 94b1ca1 commit 5ead971

34 files changed

+273
-81
lines changed

Diff for: src/auth/Auth.h

+5
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ struct AuthAuthorizer {
136136
explicit AuthAuthorizer(__u32 p) : protocol(p) {}
137137
virtual ~AuthAuthorizer() {}
138138
virtual bool verify_reply(bufferlist::iterator& reply) = 0;
139+
virtual bool add_challenge(CephContext *cct, bufferlist& challenge) = 0;
140+
};
141+
142+
struct AuthAuthorizerChallenge {
143+
virtual ~AuthAuthorizerChallenge() {}
139144
};
140145

141146

Diff for: src/auth/AuthAuthorizeHandler.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ struct AuthAuthorizeHandler {
3434
virtual bool verify_authorizer(CephContext *cct, KeyStore *keys,
3535
bufferlist& authorizer_data, bufferlist& authorizer_reply,
3636
EntityName& entity_name, uint64_t& global_id,
37-
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid = NULL) = 0;
37+
AuthCapsInfo& caps_info, CryptoKey& session_key,
38+
uint64_t *auid,
39+
std::unique_ptr<AuthAuthorizerChallenge> *challenge) = 0;
3840
virtual int authorizer_session_crypto() = 0;
3941
};
4042

Diff for: src/auth/cephx/CephxAuthorizeHandler.cc

+8-4
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66

77

88

9-
bool CephxAuthorizeHandler::verify_authorizer(CephContext *cct, KeyStore *keys,
10-
bufferlist& authorizer_data, bufferlist& authorizer_reply,
11-
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid)
9+
bool CephxAuthorizeHandler::verify_authorizer(
10+
CephContext *cct, KeyStore *keys,
11+
bufferlist& authorizer_data, bufferlist& authorizer_reply,
12+
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info,
13+
CryptoKey& session_key, uint64_t *auid,
14+
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
1215
{
1316
bufferlist::iterator iter = authorizer_data.begin();
1417

@@ -19,7 +22,8 @@ bool CephxAuthorizeHandler::verify_authorizer(CephContext *cct, KeyStore *keys,
1922

2023
CephXServiceTicketInfo auth_ticket_info;
2124

22-
bool isvalid = cephx_verify_authorizer(cct, keys, iter, auth_ticket_info, authorizer_reply);
25+
bool isvalid = cephx_verify_authorizer(cct, keys, iter, auth_ticket_info, challenge,
26+
authorizer_reply);
2327

2428
if (isvalid) {
2529
caps_info = auth_ticket_info.ticket.caps;

Diff for: src/auth/cephx/CephxAuthorizeHandler.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ struct CephxAuthorizeHandler : public AuthAuthorizeHandler {
2323
bool verify_authorizer(CephContext *cct, KeyStore *keys,
2424
bufferlist& authorizer_data, bufferlist& authorizer_reply,
2525
EntityName& entity_name, uint64_t& global_id,
26-
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid = NULL) override;
26+
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid,
27+
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
2728
int authorizer_session_crypto() override;
2829
};
2930

Diff for: src/auth/cephx/CephxProtocol.cc

+56-1
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ CephXAuthorizer *CephXTicketHandler::build_authorizer(uint64_t global_id) const
304304
::encode(service_id, a->bl);
305305

306306
::encode(ticket, a->bl);
307+
a->base_bl = a->bl;
307308

308309
CephXAuthorize msg;
309310
msg.nonce = a->nonce;
@@ -390,7 +391,9 @@ bool cephx_decode_ticket(CephContext *cct, KeyStore *keys, uint32_t service_id,
390391
*/
391392
bool cephx_verify_authorizer(CephContext *cct, KeyStore *keys,
392393
bufferlist::iterator& indata,
393-
CephXServiceTicketInfo& ticket_info, bufferlist& reply_bl)
394+
CephXServiceTicketInfo& ticket_info,
395+
std::unique_ptr<AuthAuthorizerChallenge> *challenge,
396+
bufferlist& reply_bl)
394397
{
395398
__u8 authorizer_v;
396399
uint32_t service_id;
@@ -457,6 +460,30 @@ bool cephx_verify_authorizer(CephContext *cct, KeyStore *keys,
457460
return false;
458461
}
459462

463+
if (challenge) {
464+
auto *c = static_cast<CephXAuthorizeChallenge*>(challenge->get());
465+
if (!auth_msg.have_challenge || !c) {
466+
c = new CephXAuthorizeChallenge;
467+
challenge->reset(c);
468+
get_random_bytes((char*)&c->server_challenge, sizeof(c->server_challenge));
469+
ldout(cct,10) << __func__ << " adding server_challenge " << c->server_challenge
470+
<< dendl;
471+
472+
encode_encrypt_enc_bl(cct, *c, ticket_info.session_key, reply_bl, error);
473+
if (!error.empty()) {
474+
ldout(cct, 10) << "verify_authorizer: encode_encrypt error: " << error << dendl;
475+
return false;
476+
}
477+
return false;
478+
}
479+
ldout(cct, 10) << __func__ << " got server_challenge+1 "
480+
<< auth_msg.server_challenge_plus_one
481+
<< " expecting " << c->server_challenge + 1 << dendl;
482+
if (c->server_challenge + 1 != auth_msg.server_challenge_plus_one) {
483+
return false;
484+
}
485+
}
486+
460487
/*
461488
* Reply authorizer:
462489
* {timestamp + 1}^session_key
@@ -493,3 +520,31 @@ bool CephXAuthorizer::verify_reply(bufferlist::iterator& indata)
493520
return true;
494521
}
495522

523+
bool CephXAuthorizer::add_challenge(CephContext *cct, bufferlist& challenge)
524+
{
525+
bl = base_bl;
526+
527+
CephXAuthorize msg;
528+
msg.nonce = nonce;
529+
530+
auto p = challenge.begin();
531+
if (!p.end()) {
532+
std::string error;
533+
CephXAuthorizeChallenge ch;
534+
decode_decrypt_enc_bl(cct, ch, session_key, challenge, error);
535+
if (!error.empty()) {
536+
ldout(cct, 0) << "failed to decrypt challenge (" << challenge.length() << " bytes): "
537+
<< error << dendl;
538+
return false;
539+
}
540+
msg.have_challenge = true;
541+
msg.server_challenge_plus_one = ch.server_challenge + 1;
542+
}
543+
544+
std::string error;
545+
if (encode_encrypt(cct, msg, session_key, bl, error)) {
546+
ldout(cct, 0) << __func__ << " failed to encrypt authorizer: " << error << dendl;
547+
return false;
548+
}
549+
return true;
550+
}

Diff for: src/auth/cephx/CephxProtocol.h

+33-4
Original file line numberDiff line numberDiff line change
@@ -273,12 +273,14 @@ struct CephXAuthorizer : public AuthAuthorizer {
273273
CephContext *cct;
274274
public:
275275
uint64_t nonce;
276+
bufferlist base_bl;
276277

277278
explicit CephXAuthorizer(CephContext *cct_)
278279
: AuthAuthorizer(CEPH_AUTH_CEPHX), cct(cct_), nonce(0) {}
279280

280281
bool build_authorizer();
281282
bool verify_reply(bufferlist::iterator& reply) override;
283+
bool add_challenge(CephContext *cct, bufferlist& challenge) override;
282284
};
283285

284286

@@ -384,17 +386,41 @@ struct CephXServiceTicketInfo {
384386
};
385387
WRITE_CLASS_ENCODER(CephXServiceTicketInfo)
386388

389+
struct CephXAuthorizeChallenge : public AuthAuthorizerChallenge {
390+
uint64_t server_challenge;
391+
void encode(bufferlist& bl) const {
392+
__u8 struct_v = 1;
393+
::encode(struct_v, bl);
394+
::encode(server_challenge, bl);
395+
}
396+
void decode(bufferlist::iterator& bl) {
397+
__u8 struct_v;
398+
::decode(struct_v, bl);
399+
::decode(server_challenge, bl);
400+
}
401+
};
402+
WRITE_CLASS_ENCODER(CephXAuthorizeChallenge)
403+
387404
struct CephXAuthorize {
388405
uint64_t nonce;
406+
bool have_challenge = false;
407+
uint64_t server_challenge_plus_one = 0;
389408
void encode(bufferlist& bl) const {
390-
__u8 struct_v = 1;
409+
__u8 struct_v = 2;
391410
::encode(struct_v, bl);
392411
::encode(nonce, bl);
412+
::encode(have_challenge, bl);
413+
::encode(server_challenge_plus_one, bl);
393414
}
394415
void decode(bufferlist::iterator& bl) {
395416
__u8 struct_v;
396417
::decode(struct_v, bl);
397418
::decode(nonce, bl);
419+
if (struct_v >= 2) {
420+
::decode(have_challenge, bl);
421+
::decode(server_challenge_plus_one, bl);
422+
}
423+
398424
}
399425
};
400426
WRITE_CLASS_ENCODER(CephXAuthorize)
@@ -409,9 +435,12 @@ bool cephx_decode_ticket(CephContext *cct, KeyStore *keys,
409435
/*
410436
* Verify authorizer and generate reply authorizer
411437
*/
412-
extern bool cephx_verify_authorizer(CephContext *cct, KeyStore *keys,
413-
bufferlist::iterator& indata,
414-
CephXServiceTicketInfo& ticket_info, bufferlist& reply_bl);
438+
extern bool cephx_verify_authorizer(
439+
CephContext *cct, KeyStore *keys,
440+
bufferlist::iterator& indata,
441+
CephXServiceTicketInfo& ticket_info,
442+
std::unique_ptr<AuthAuthorizerChallenge> *challenge,
443+
bufferlist& reply_bl);
415444

416445

417446

Diff for: src/auth/cephx/CephxServiceHandler.cc

+3-1
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,9 @@ int CephxServiceHandler::handle_request(bufferlist::iterator& indata, bufferlist
152152

153153
bufferlist tmp_bl;
154154
CephXServiceTicketInfo auth_ticket_info;
155-
if (!cephx_verify_authorizer(cct, key_server, indata, auth_ticket_info, tmp_bl)) {
155+
// note: no challenge here.
156+
if (!cephx_verify_authorizer(cct, key_server, indata, auth_ticket_info, nullptr,
157+
tmp_bl)) {
156158
ret = -EPERM;
157159
break;
158160
}

Diff for: src/auth/none/AuthNoneAuthorizeHandler.cc

+7-4
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717

1818
#define dout_subsys ceph_subsys_auth
1919

20-
bool AuthNoneAuthorizeHandler::verify_authorizer(CephContext *cct, KeyStore *keys,
21-
bufferlist& authorizer_data, bufferlist& authorizer_reply,
22-
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info, CryptoKey& session_key,
23-
uint64_t *auid)
20+
bool AuthNoneAuthorizeHandler::verify_authorizer(
21+
CephContext *cct, KeyStore *keys,
22+
bufferlist& authorizer_data, bufferlist& authorizer_reply,
23+
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info,
24+
CryptoKey& session_key,
25+
uint64_t *auid,
26+
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
2427
{
2528
bufferlist::iterator iter = authorizer_data.begin();
2629

Diff for: src/auth/none/AuthNoneAuthorizeHandler.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ struct AuthNoneAuthorizeHandler : public AuthAuthorizeHandler {
2323
bool verify_authorizer(CephContext *cct, KeyStore *keys,
2424
bufferlist& authorizer_data, bufferlist& authorizer_reply,
2525
EntityName& entity_name, uint64_t& global_id,
26-
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid=NULL) override;
26+
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid,
27+
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
2728
int authorizer_session_crypto() override;
2829
};
2930

Diff for: src/auth/none/AuthNoneProtocol.h

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
#include "auth/Auth.h"
1919

20+
class CephContext;
21+
2022
struct AuthNoneAuthorizer : public AuthAuthorizer {
2123
AuthNoneAuthorizer() : AuthAuthorizer(CEPH_AUTH_NONE) { }
2224
bool build_authorizer(const EntityName &ename, uint64_t global_id) {
@@ -27,6 +29,7 @@ struct AuthNoneAuthorizer : public AuthAuthorizer {
2729
return 0;
2830
}
2931
bool verify_reply(bufferlist::iterator& reply) override { return true; }
32+
bool add_challenge(CephContext *cct, bufferlist& ch) override { return true; }
3033
};
3134

3235
#endif

Diff for: src/auth/unknown/AuthUnknownAuthorizeHandler.cc

+7-4
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@
1414

1515
#include "AuthUnknownAuthorizeHandler.h"
1616

17-
bool AuthUnknownAuthorizeHandler::verify_authorizer(CephContext *cct, KeyStore *keys,
18-
bufferlist& authorizer_data, bufferlist& authorizer_reply,
19-
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info, CryptoKey& session_key,
20-
uint64_t *auid)
17+
bool AuthUnknownAuthorizeHandler::verify_authorizer(
18+
CephContext *cct, KeyStore *keys,
19+
bufferlist& authorizer_data, bufferlist& authorizer_reply,
20+
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info,
21+
CryptoKey& session_key,
22+
uint64_t *auid,
23+
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
2124
{
2225
// For unknown authorizers, there's nothing to verify. They're "OK" by definition. PLR
2326

Diff for: src/auth/unknown/AuthUnknownAuthorizeHandler.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ struct AuthUnknownAuthorizeHandler : public AuthAuthorizeHandler {
2323
bool verify_authorizer(CephContext *cct, KeyStore *keys,
2424
bufferlist& authorizer_data, bufferlist& authorizer_reply,
2525
EntityName& entity_name, uint64_t& global_id,
26-
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid=NULL) override;
26+
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid,
27+
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
2728
int authorizer_session_crypto() override;
2829
};
2930

Diff for: src/include/msgr.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ struct ceph_entity_inst {
9393
#define CEPH_MSGR_TAG_SEQ 13 /* 64-bit int follows with seen seq number */
9494
#define CEPH_MSGR_TAG_KEEPALIVE2 14
9595
#define CEPH_MSGR_TAG_KEEPALIVE2_ACK 15 /* keepalive reply */
96-
96+
#define CEPH_MSGR_TAG_CHALLENGE_AUTHORIZER 16 /* ceph v2 doing server challenge */
9797

9898
/*
9999
* connection negotiation

Diff for: src/mds/MDSDaemon.cc

+3-2
Original file line numberDiff line numberDiff line change
@@ -1262,7 +1262,8 @@ bool MDSDaemon::ms_handle_refused(Connection *con)
12621262

12631263
bool MDSDaemon::ms_verify_authorizer(Connection *con, int peer_type,
12641264
int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply,
1265-
bool& is_valid, CryptoKey& session_key)
1265+
bool& is_valid, CryptoKey& session_key,
1266+
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
12661267
{
12671268
Mutex::Locker l(mds_lock);
12681269
if (stopping) {
@@ -1294,7 +1295,7 @@ bool MDSDaemon::ms_verify_authorizer(Connection *con, int peer_type,
12941295
is_valid = authorize_handler->verify_authorizer(
12951296
cct, keys,
12961297
authorizer_data, authorizer_reply, name, global_id, caps_info,
1297-
session_key);
1298+
session_key, nullptr, challenge);
12981299
} else {
12991300
dout(10) << __func__ << " no rotating_keys (yet), denied" << dendl;
13001301
is_valid = false;

Diff for: src/mds/MDSDaemon.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ class MDSDaemon : public Dispatcher, public md_config_obs_t {
108108
bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new) override;
109109
bool ms_verify_authorizer(Connection *con, int peer_type,
110110
int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply,
111-
bool& isvalid, CryptoKey& session_key) override;
111+
bool& isvalid, CryptoKey& session_key,
112+
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
112113
void ms_handle_accept(Connection *con) override;
113114
void ms_handle_connect(Connection *con) override;
114115
bool ms_handle_reset(Connection *con) override;

Diff for: src/mgr/DaemonServer.cc

+12-8
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,15 @@ entity_addr_t DaemonServer::get_myaddr() const
141141
}
142142

143143

144-
bool DaemonServer::ms_verify_authorizer(Connection *con,
145-
int peer_type,
146-
int protocol,
147-
ceph::bufferlist& authorizer_data,
148-
ceph::bufferlist& authorizer_reply,
149-
bool& is_valid,
150-
CryptoKey& session_key)
144+
bool DaemonServer::ms_verify_authorizer(
145+
Connection *con,
146+
int peer_type,
147+
int protocol,
148+
ceph::bufferlist& authorizer_data,
149+
ceph::bufferlist& authorizer_reply,
150+
bool& is_valid,
151+
CryptoKey& session_key,
152+
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
151153
{
152154
AuthAuthorizeHandler *handler = nullptr;
153155
if (peer_type == CEPH_ENTITY_TYPE_OSD ||
@@ -175,7 +177,9 @@ bool DaemonServer::ms_verify_authorizer(Connection *con,
175177
authorizer_data,
176178
authorizer_reply, s->entity_name,
177179
s->global_id, caps_info,
178-
session_key);
180+
session_key,
181+
nullptr,
182+
challenge);
179183
} else {
180184
dout(10) << __func__ << " no rotating_keys (yet), denied" << dendl;
181185
is_valid = false;

Diff for: src/mgr/DaemonServer.h

+9-7
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,15 @@ class DaemonServer : public Dispatcher, public md_config_obs_t
123123
bool ms_handle_refused(Connection *con) override;
124124
bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer,
125125
bool force_new) override;
126-
bool ms_verify_authorizer(Connection *con,
127-
int peer_type,
128-
int protocol,
129-
ceph::bufferlist& authorizer,
130-
ceph::bufferlist& authorizer_reply,
131-
bool& isvalid,
132-
CryptoKey& session_key) override;
126+
bool ms_verify_authorizer(
127+
Connection *con,
128+
int peer_type,
129+
int protocol,
130+
ceph::bufferlist& authorizer,
131+
ceph::bufferlist& authorizer_reply,
132+
bool& isvalid,
133+
CryptoKey& session_key,
134+
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
133135

134136
bool handle_open(MMgrOpen *m);
135137
bool handle_report(MMgrReport *m);

0 commit comments

Comments
 (0)