Skip to content

Commit

Permalink
auth/cephx: add authorizer challenge
Browse files Browse the repository at this point in the history
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()

(cherry picked from commit 5ead971)

# Conflicts:
#	src/auth/cephx/CephxAuthorizeHandler.h
#	src/auth/cephx/CephxProtocol.h
#	src/auth/none/AuthNoneAuthorizeHandler.h
#	src/auth/none/AuthNoneProtocol.h
#	src/auth/unknown/AuthUnknownAuthorizeHandler.h
#	src/mds/MDSDaemon.cc
#	src/mds/MDSDaemon.h
#	src/mgr/DaemonServer.cc
#	src/mgr/DaemonServer.h
#	src/mon/Monitor.cc
#	src/mon/Monitor.h
#	src/msg/async/AsyncConnection.cc
#	src/osd/OSD.cc
#	src/osd/OSD.h
#	src/test/messenger/simple_dispatcher.h
#	src/test/msgr/perf_msgr_client.cc
#	src/test/msgr/perf_msgr_server.cc
#	src/test/msgr/test_msgr.cc

- lots of override annotation conflicts
  - _refused() callbacks no present in jewel
- lots of msg/async conflicts (code has changed a fair bit)
- we inherited some upstream rotating keys checks, see
  f159a09
  • Loading branch information
liewegas committed May 25, 2018
1 parent 9a88a7c commit 26816cd
Show file tree
Hide file tree
Showing 32 changed files with 288 additions and 86 deletions.
5 changes: 5 additions & 0 deletions src/auth/Auth.h
Expand Up @@ -139,6 +139,11 @@ struct AuthAuthorizer {
explicit AuthAuthorizer(__u32 p) : protocol(p) {}
virtual ~AuthAuthorizer() {}
virtual bool verify_reply(bufferlist::iterator& reply) = 0;
virtual bool add_challenge(CephContext *cct, bufferlist& challenge) = 0;
};

struct AuthAuthorizerChallenge {
virtual ~AuthAuthorizerChallenge() {}
};


Expand Down
4 changes: 3 additions & 1 deletion src/auth/AuthAuthorizeHandler.h
Expand Up @@ -34,7 +34,9 @@ struct AuthAuthorizeHandler {
virtual bool verify_authorizer(CephContext *cct, KeyStore *keys,
bufferlist& authorizer_data, bufferlist& authorizer_reply,
EntityName& entity_name, uint64_t& global_id,
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid = NULL) = 0;
AuthCapsInfo& caps_info, CryptoKey& session_key,
uint64_t *auid,
std::unique_ptr<AuthAuthorizerChallenge> *challenge) = 0;
virtual int authorizer_session_crypto() = 0;
};

Expand Down
12 changes: 8 additions & 4 deletions src/auth/cephx/CephxAuthorizeHandler.cc
Expand Up @@ -8,9 +8,12 @@



bool CephxAuthorizeHandler::verify_authorizer(CephContext *cct, KeyStore *keys,
bufferlist& authorizer_data, bufferlist& authorizer_reply,
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid)
bool CephxAuthorizeHandler::verify_authorizer(
CephContext *cct, KeyStore *keys,
bufferlist& authorizer_data, bufferlist& authorizer_reply,
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info,
CryptoKey& session_key, uint64_t *auid,
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
{
bufferlist::iterator iter = authorizer_data.begin();

Expand All @@ -21,7 +24,8 @@ bool CephxAuthorizeHandler::verify_authorizer(CephContext *cct, KeyStore *keys,

CephXServiceTicketInfo auth_ticket_info;

bool isvalid = cephx_verify_authorizer(cct, keys, iter, auth_ticket_info, authorizer_reply);
bool isvalid = cephx_verify_authorizer(cct, keys, iter, auth_ticket_info, challenge,
authorizer_reply);

if (isvalid) {
caps_info = auth_ticket_info.ticket.caps;
Expand Down
5 changes: 3 additions & 2 deletions src/auth/cephx/CephxAuthorizeHandler.h
Expand Up @@ -23,8 +23,9 @@ struct CephxAuthorizeHandler : public AuthAuthorizeHandler {
bool verify_authorizer(CephContext *cct, KeyStore *keys,
bufferlist& authorizer_data, bufferlist& authorizer_reply,
EntityName& entity_name, uint64_t& global_id,
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid = NULL);
int authorizer_session_crypto();
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid,
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
int authorizer_session_crypto() override;
};


Expand Down
57 changes: 56 additions & 1 deletion src/auth/cephx/CephxProtocol.cc
Expand Up @@ -304,6 +304,7 @@ CephXAuthorizer *CephXTicketHandler::build_authorizer(uint64_t global_id) const
::encode(service_id, a->bl);

::encode(ticket, a->bl);
a->base_bl = a->bl;

CephXAuthorize msg;
msg.nonce = a->nonce;
Expand Down Expand Up @@ -390,7 +391,9 @@ bool cephx_decode_ticket(CephContext *cct, KeyStore *keys, uint32_t service_id,
*/
bool cephx_verify_authorizer(CephContext *cct, KeyStore *keys,
bufferlist::iterator& indata,
CephXServiceTicketInfo& ticket_info, bufferlist& reply_bl)
CephXServiceTicketInfo& ticket_info,
std::unique_ptr<AuthAuthorizerChallenge> *challenge,
bufferlist& reply_bl)
{
__u8 authorizer_v;
uint32_t service_id;
Expand Down Expand Up @@ -457,6 +460,30 @@ bool cephx_verify_authorizer(CephContext *cct, KeyStore *keys,
return false;
}

if (challenge) {
auto *c = static_cast<CephXAuthorizeChallenge*>(challenge->get());
if (!auth_msg.have_challenge || !c) {
c = new CephXAuthorizeChallenge;
challenge->reset(c);
get_random_bytes((char*)&c->server_challenge, sizeof(c->server_challenge));
ldout(cct,10) << __func__ << " adding server_challenge " << c->server_challenge
<< dendl;

encode_encrypt_enc_bl(cct, *c, ticket_info.session_key, reply_bl, error);
if (!error.empty()) {
ldout(cct, 10) << "verify_authorizer: encode_encrypt error: " << error << dendl;
return false;
}
return false;
}
ldout(cct, 10) << __func__ << " got server_challenge+1 "
<< auth_msg.server_challenge_plus_one
<< " expecting " << c->server_challenge + 1 << dendl;
if (c->server_challenge + 1 != auth_msg.server_challenge_plus_one) {
return false;
}
}

/*
* Reply authorizer:
* {timestamp + 1}^session_key
Expand Down Expand Up @@ -493,3 +520,31 @@ bool CephXAuthorizer::verify_reply(bufferlist::iterator& indata)
return true;
}

bool CephXAuthorizer::add_challenge(CephContext *cct, bufferlist& challenge)
{
bl = base_bl;

CephXAuthorize msg;
msg.nonce = nonce;

auto p = challenge.begin();
if (!p.end()) {
std::string error;
CephXAuthorizeChallenge ch;
decode_decrypt_enc_bl(cct, ch, session_key, challenge, error);
if (!error.empty()) {
ldout(cct, 0) << "failed to decrypt challenge (" << challenge.length() << " bytes): "
<< error << dendl;
return false;
}
msg.have_challenge = true;
msg.server_challenge_plus_one = ch.server_challenge + 1;
}

std::string error;
if (encode_encrypt(cct, msg, session_key, bl, error)) {
ldout(cct, 0) << __func__ << " failed to encrypt authorizer: " << error << dendl;
return false;
}
return true;
}
39 changes: 34 additions & 5 deletions src/auth/cephx/CephxProtocol.h
Expand Up @@ -276,12 +276,14 @@ struct CephXAuthorizer : public AuthAuthorizer {
CephContext *cct;
public:
uint64_t nonce;
bufferlist base_bl;

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

bool build_authorizer();
bool verify_reply(bufferlist::iterator& reply);
bool verify_reply(bufferlist::iterator& reply) override;
bool add_challenge(CephContext *cct, bufferlist& challenge) override;
};


Expand Down Expand Up @@ -387,17 +389,41 @@ struct CephXServiceTicketInfo {
};
WRITE_CLASS_ENCODER(CephXServiceTicketInfo)

struct CephXAuthorizeChallenge : public AuthAuthorizerChallenge {
uint64_t server_challenge;
void encode(bufferlist& bl) const {
__u8 struct_v = 1;
::encode(struct_v, bl);
::encode(server_challenge, bl);
}
void decode(bufferlist::iterator& bl) {
__u8 struct_v;
::decode(struct_v, bl);
::decode(server_challenge, bl);
}
};
WRITE_CLASS_ENCODER(CephXAuthorizeChallenge)

struct CephXAuthorize {
uint64_t nonce;
bool have_challenge = false;
uint64_t server_challenge_plus_one = 0;
void encode(bufferlist& bl) const {
__u8 struct_v = 1;
__u8 struct_v = 2;
::encode(struct_v, bl);
::encode(nonce, bl);
::encode(have_challenge, bl);
::encode(server_challenge_plus_one, bl);
}
void decode(bufferlist::iterator& bl) {
__u8 struct_v;
::decode(struct_v, bl);
::decode(nonce, bl);
if (struct_v >= 2) {
::decode(have_challenge, bl);
::decode(server_challenge_plus_one, bl);
}

}
};
WRITE_CLASS_ENCODER(CephXAuthorize)
Expand All @@ -412,9 +438,12 @@ bool cephx_decode_ticket(CephContext *cct, KeyStore *keys,
/*
* Verify authorizer and generate reply authorizer
*/
extern bool cephx_verify_authorizer(CephContext *cct, KeyStore *keys,
bufferlist::iterator& indata,
CephXServiceTicketInfo& ticket_info, bufferlist& reply_bl);
extern bool cephx_verify_authorizer(
CephContext *cct, KeyStore *keys,
bufferlist::iterator& indata,
CephXServiceTicketInfo& ticket_info,
std::unique_ptr<AuthAuthorizerChallenge> *challenge,
bufferlist& reply_bl);



Expand Down
4 changes: 3 additions & 1 deletion src/auth/cephx/CephxServiceHandler.cc
Expand Up @@ -156,7 +156,9 @@ int CephxServiceHandler::handle_request(bufferlist::iterator& indata, bufferlist

bufferlist tmp_bl;
CephXServiceTicketInfo auth_ticket_info;
if (!cephx_verify_authorizer(cct, key_server, indata, auth_ticket_info, tmp_bl)) {
// note: no challenge here.
if (!cephx_verify_authorizer(cct, key_server, indata, auth_ticket_info, nullptr,
tmp_bl)) {
ret = -EPERM;
break;
}
Expand Down
11 changes: 7 additions & 4 deletions src/auth/none/AuthNoneAuthorizeHandler.cc
Expand Up @@ -17,10 +17,13 @@

#define dout_subsys ceph_subsys_auth

bool AuthNoneAuthorizeHandler::verify_authorizer(CephContext *cct, KeyStore *keys,
bufferlist& authorizer_data, bufferlist& authorizer_reply,
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info, CryptoKey& session_key,
uint64_t *auid)
bool AuthNoneAuthorizeHandler::verify_authorizer(
CephContext *cct, KeyStore *keys,
bufferlist& authorizer_data, bufferlist& authorizer_reply,
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info,
CryptoKey& session_key,
uint64_t *auid,
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
{
bufferlist::iterator iter = authorizer_data.begin();

Expand Down
5 changes: 3 additions & 2 deletions src/auth/none/AuthNoneAuthorizeHandler.h
Expand Up @@ -23,8 +23,9 @@ struct AuthNoneAuthorizeHandler : public AuthAuthorizeHandler {
bool verify_authorizer(CephContext *cct, KeyStore *keys,
bufferlist& authorizer_data, bufferlist& authorizer_reply,
EntityName& entity_name, uint64_t& global_id,
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid=NULL);
int authorizer_session_crypto();
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid,
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
int authorizer_session_crypto() override;
};


Expand Down
5 changes: 4 additions & 1 deletion src/auth/none/AuthNoneProtocol.h
Expand Up @@ -17,6 +17,8 @@

#include "../Auth.h"

class CephContext;

struct AuthNoneAuthorizer : public AuthAuthorizer {
AuthNoneAuthorizer() : AuthAuthorizer(CEPH_AUTH_NONE) { }
bool build_authorizer(const EntityName &ename, uint64_t global_id) {
Expand All @@ -26,7 +28,8 @@ struct AuthNoneAuthorizer : public AuthAuthorizer {
::encode(global_id, bl);
return 0;
}
bool verify_reply(bufferlist::iterator& reply) { return true; }
bool verify_reply(bufferlist::iterator& reply) override { return true; }
bool add_challenge(CephContext *cct, bufferlist& ch) override { return true; }
};

#endif
11 changes: 7 additions & 4 deletions src/auth/unknown/AuthUnknownAuthorizeHandler.cc
Expand Up @@ -17,10 +17,13 @@

#define dout_subsys ceph_subsys_auth

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

Expand Down
5 changes: 3 additions & 2 deletions src/auth/unknown/AuthUnknownAuthorizeHandler.h
Expand Up @@ -23,8 +23,9 @@ struct AuthUnknownAuthorizeHandler : public AuthAuthorizeHandler {
bool verify_authorizer(CephContext *cct, KeyStore *keys,
bufferlist& authorizer_data, bufferlist& authorizer_reply,
EntityName& entity_name, uint64_t& global_id,
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid=NULL);
int authorizer_session_crypto();
AuthCapsInfo& caps_info, CryptoKey& session_key, uint64_t *auid,
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
int authorizer_session_crypto() override;
};


Expand Down
2 changes: 1 addition & 1 deletion src/include/msgr.h
Expand Up @@ -92,7 +92,7 @@ struct ceph_entity_inst {
#define CEPH_MSGR_TAG_SEQ 13 /* 64-bit int follows with seen seq number */
#define CEPH_MSGR_TAG_KEEPALIVE2 14
#define CEPH_MSGR_TAG_KEEPALIVE2_ACK 15 /* keepalive reply */

#define CEPH_MSGR_TAG_CHALLENGE_AUTHORIZER 16 /* ceph v2 doing server challenge */

/*
* connection negotiation
Expand Down
15 changes: 12 additions & 3 deletions src/mds/MDSDaemon.cc
Expand Up @@ -1295,7 +1295,8 @@ void MDSDaemon::ms_handle_remote_reset(Connection *con)

bool MDSDaemon::ms_verify_authorizer(Connection *con, int peer_type,
int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply,
bool& is_valid, CryptoKey& session_key)
bool& is_valid, CryptoKey& session_key,
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
{
Mutex::Locker l(mds_lock);
if (stopping) {
Expand All @@ -1322,8 +1323,16 @@ bool MDSDaemon::ms_verify_authorizer(Connection *con, int peer_type,
EntityName name;
uint64_t global_id;

is_valid = authorize_handler->verify_authorizer(cct, monc->rotating_secrets,
authorizer_data, authorizer_reply, name, global_id, caps_info, session_key);
RotatingKeyRing *keys = monc->rotating_secrets;
if (keys) {
is_valid = authorize_handler->verify_authorizer(
cct, keys,
authorizer_data, authorizer_reply, name, global_id, caps_info,
session_key, nullptr, challenge);
} else {
dout(10) << __func__ << " no rotating_keys (yet), denied" << dendl;
is_valid = false;
}

if (is_valid) {
entity_name_t n(con->get_peer_type(), global_id);
Expand Down
11 changes: 6 additions & 5 deletions src/mds/MDSDaemon.h
Expand Up @@ -146,11 +146,12 @@ class MDSDaemon : public Dispatcher, public md_config_obs_t {
bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new);
bool ms_verify_authorizer(Connection *con, int peer_type,
int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply,
bool& isvalid, CryptoKey& session_key);
void ms_handle_accept(Connection *con);
void ms_handle_connect(Connection *con);
bool ms_handle_reset(Connection *con);
void ms_handle_remote_reset(Connection *con);
bool& isvalid, CryptoKey& session_key,
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
void ms_handle_accept(Connection *con) override;
void ms_handle_connect(Connection *con) override;
bool ms_handle_reset(Connection *con) override;
void ms_handle_remote_reset(Connection *con) override;

protected:
// admin socket handling
Expand Down
8 changes: 5 additions & 3 deletions src/mon/Monitor.cc
Expand Up @@ -5115,8 +5115,10 @@ bool Monitor::ms_get_authorizer(int service_id, AuthAuthorizer **authorizer, boo
}

bool Monitor::ms_verify_authorizer(Connection *con, int peer_type,
int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply,
bool& isvalid, CryptoKey& session_key)
int protocol, bufferlist& authorizer_data,
bufferlist& authorizer_reply,
bool& isvalid, CryptoKey& session_key,
std::unique_ptr<AuthAuthorizerChallenge> *challenge)
{
dout(10) << "ms_verify_authorizer " << con->get_peer_addr()
<< " " << ceph_entity_type_name(peer_type)
Expand All @@ -5135,7 +5137,7 @@ bool Monitor::ms_verify_authorizer(Connection *con, int peer_type,

if (authorizer_data.length()) {
bool ret = cephx_verify_authorizer(g_ceph_context, &keyring, iter,
auth_ticket_info, authorizer_reply);
auth_ticket_info, challenge, authorizer_reply);
if (ret) {
session_key = auth_ticket_info.session_key;
isvalid = true;
Expand Down
7 changes: 4 additions & 3 deletions src/mon/Monitor.h
Expand Up @@ -857,9 +857,10 @@ class Monitor : public Dispatcher,
bool ms_get_authorizer(int dest_type, AuthAuthorizer **authorizer, bool force_new);
bool ms_verify_authorizer(Connection *con, int peer_type,
int protocol, bufferlist& authorizer_data, bufferlist& authorizer_reply,
bool& isvalid, CryptoKey& session_key);
bool ms_handle_reset(Connection *con);
void ms_handle_remote_reset(Connection *con) {}
bool& isvalid, CryptoKey& session_key,
std::unique_ptr<AuthAuthorizerChallenge> *challenge) override;
bool ms_handle_reset(Connection *con) override;
void ms_handle_remote_reset(Connection *con) override {}

int write_default_keyring(bufferlist& bl);
void extract_save_mon_key(KeyRing& keyring);
Expand Down

0 comments on commit 26816cd

Please sign in to comment.