Skip to content

Commit

Permalink
cram-md5: moved stuff into separate class
Browse files Browse the repository at this point in the history
moved md5 challenge and respond from bsocket::two_way_authenticate
int separate class CramMd5Handshake
  • Loading branch information
franku committed Jul 20, 2018
1 parent 169404a commit f277d7c
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 125 deletions.
4 changes: 2 additions & 2 deletions core/src/dird/backup.cc
Expand Up @@ -554,7 +554,7 @@ bool DoNativeBackup(JobControlRecord *jcr)
* TLS Requirement
*/

tls_need = GetNeedFromConfiguration(client);
tls_need = GetLocalTlsPolicyFromConfiguration(client);

connection_target_address = StorageAddressToContact(client, store);

Expand All @@ -568,7 +568,7 @@ bool DoNativeBackup(JobControlRecord *jcr)
* TLS Requirement
*/

tls_need = GetNeedFromConfiguration(me);
tls_need = GetLocalTlsPolicyFromConfiguration(me);

connection_target_address = ClientAddressToContact(client, store);

Expand Down
2 changes: 1 addition & 1 deletion core/src/dird/migrate.cc
Expand Up @@ -1542,7 +1542,7 @@ static inline bool DoActualMigration(JobControlRecord *jcr)
/*
* TLS Requirement
*/
tls_need = GetNeedFromConfiguration(wstore);
tls_need = GetLocalTlsPolicyFromConfiguration(wstore);

char *connection_target_address = StorageAddressToContact(rstore, wstore);

Expand Down
4 changes: 2 additions & 2 deletions core/src/dird/restore.cc
Expand Up @@ -260,7 +260,7 @@ static inline bool DoNativeRestoreBootstrap(JobControlRecord *jcr)
/*
* TLS Requirement
*/
tls_need = GetNeedFromConfiguration(store);
tls_need = GetLocalTlsPolicyFromConfiguration(store);

connection_target_address = StorageAddressToContact(client, store);

Expand Down Expand Up @@ -289,7 +289,7 @@ static inline bool DoNativeRestoreBootstrap(JobControlRecord *jcr)
/*
* TLS Requirement
*/
tls_need = GetNeedFromConfiguration(client);
tls_need = GetLocalTlsPolicyFromConfiguration(client);

connection_target_address = ClientAddressToContact(client, store);
/*
Expand Down
4 changes: 2 additions & 2 deletions core/src/dird/verify.cc
Expand Up @@ -347,7 +347,7 @@ bool DoVerify(JobControlRecord *jcr)
* TLS Requirement
*/

tls_need = GetNeedFromConfiguration(store);
tls_need = GetLocalTlsPolicyFromConfiguration(store);

fd->fsend(storaddrcmd, store->address, store->SDDport, tls_need, jcr->sd_auth_key);
if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
Expand All @@ -360,7 +360,7 @@ bool DoVerify(JobControlRecord *jcr)
/*
* TLS Requirement
*/
tls_need = GetNeedFromConfiguration(client);
tls_need = GetLocalTlsPolicyFromConfiguration(client);

/*
* Tell the SD to connect to the FD.
Expand Down
75 changes: 13 additions & 62 deletions core/src/lib/bsock.cc
Expand Up @@ -33,12 +33,12 @@
#include "lib/util.h"
#include "lib/tls_openssl.h"

DLL_IMP_EXP uint32_t GetNeedFromConfiguration(TlsResource *tls_configuration) {
DLL_IMP_EXP uint32_t GetLocalTlsPolicyFromConfiguration(TlsResource *tls_configuration) {
uint32_t merged_policy = 0;

#if defined(HAVE_TLS)
merged_policy = tls_configuration->tls_cert.GetPolicy() | tls_configuration->tls_psk.GetPolicy();
Dmsg1(100, "GetNeedFromConfiguration: %u\n", merged_policy);
Dmsg1(100, "GetLocalTlsPolicyFromConfiguration: %u\n", merged_policy);
#else
Dmsg1(100, "Ignore configuration no tls compiled in: %u\n", merged_policy);
#endif
Expand Down Expand Up @@ -357,20 +357,18 @@ bool BareosSocket::two_way_authenticate(JobControlRecord *jcr,
const char *identity,
s_password &password,
TlsResource *tls_configuration,
bool initiated_by_remote) {

btimer_t *tid = NULL;
bool initiated_by_remote)
{
const int debuglevel = 50;
bool compatible = true;
bool auth_success = false;
uint32_t local_tls_policy = GetNeedFromConfiguration(tls_configuration);
uint32_t remote_tls_policy = 0;
alist *verify_list = NULL;
TlsBase * selected_local_tls = nullptr;
bool auth_success = false;

btimer_t *tid = nullptr;
TlsBase *selected_local_tls = nullptr;
uint32_t local_tls_policy = GetLocalTlsPolicyFromConfiguration(tls_configuration);
CramMd5Handshake cram_md5_handshake(this, password.value, local_tls_policy);

if (jcr && JobCanceled(jcr)) {
Dmsg0(debuglevel, "Failed, because job is canceled.\n");
auth_success = false; /* force quick exit */
goto auth_fatal;
}

Expand All @@ -380,51 +378,9 @@ bool BareosSocket::two_way_authenticate(JobControlRecord *jcr,
goto auth_fatal;
}

/*
* get local tls need
*/

/*
* Timeout Hello after 10 min
*/
tid = StartBsockTimer(this, AUTH_TIMEOUT);

/*
* See if we initiate the challenge or respond to a challenge.
*/
if (initiated_by_remote) {
/*
* Challenge Remote.
*/
auth_success = cram_md5_challenge(this, password.value, local_tls_policy, compatible);
if (auth_success) {
/*
* Respond to remote challenge
*/
auth_success = cram_md5_respond(this, password.value, &remote_tls_policy, &compatible);
if (!auth_success) {
Dmsg1(debuglevel, "Respond cram-get-auth failed with %s\n", who());
}
} else {
Dmsg1(debuglevel, "Challenge cram-auth failed with %s\n", who());
}
} else {
/*
* Respond to remote challenge
*/
auth_success = cram_md5_respond(this, password.value, &remote_tls_policy, &compatible);
if (!auth_success) {
Dmsg1(debuglevel, "cram_respond failed for %s\n", who());
} else {
/*
* Challenge Remote.
*/
auth_success = cram_md5_challenge(this, password.value, local_tls_policy, compatible);
if (!auth_success) {
Dmsg1(debuglevel, "cram_challenge failed for %s\n", who());
}
}
}
auth_success = cram_md5_handshake.DoHandshake(initiated_by_remote);

if (!auth_success) {
Jmsg(jcr,
Expand All @@ -444,18 +400,13 @@ bool BareosSocket::two_way_authenticate(JobControlRecord *jcr,
goto auth_fatal;
}

/*
* Verify that the remote host is willing to meet our TLS requirements
*/
selected_local_tls = SelectTlsFromPolicy(tls_configuration, remote_tls_policy);
selected_local_tls = SelectTlsFromPolicy(tls_configuration, cram_md5_handshake.RemoteTlsPolicy());
if (selected_local_tls != nullptr) {
alist *verify_list = NULL;
if (selected_local_tls->GetVerifyPeer()) {
verify_list = selected_local_tls->GetVerifyList();
}

/*
* See if we are handshaking a passive client connection.
*/
if (initiated_by_remote) {
std::shared_ptr<TLS_CONTEXT> tls_ctx = selected_local_tls->CreateServerContext(
std::make_shared<PskCredentials>(identity, password.value));
Expand Down
2 changes: 1 addition & 1 deletion core/src/lib/bsock.h
Expand Up @@ -45,7 +45,7 @@ class BareosSocket;
btimer_t *StartBsockTimer(BareosSocket *bs, uint32_t wait);
void StopBsockTimer(btimer_t *wid);

uint32_t GetNeedFromConfiguration(TlsResource *tls_configuration);
uint32_t GetLocalTlsPolicyFromConfiguration(TlsResource *tls_configuration);


TlsBase *SelectTlsFromPolicy(TlsResource *tls_configuration, uint32_t remote_policy);
Expand Down
142 changes: 87 additions & 55 deletions core/src/lib/cram-md5.cc
Expand Up @@ -29,7 +29,17 @@
#include "include/bareos.h"
#include "lib/cram_md5.h"

const int debuglevel = 50;

CramMd5Handshake::CramMd5Handshake(BareosSocket *bs,
const char *password,
uint32_t local_tls_policy)
: bs_(bs)
, password_(password)
, local_tls_policy_(local_tls_policy)
{
return;
}


/* Authorize other end
* Codes that tls_local_need and tls_remote_need can take:
Expand All @@ -41,22 +51,12 @@ const int debuglevel = 50;
* Returns: false if authentication failed
* true if OK
*/
bool cram_md5_challenge(BareosSocket *bs, const char *password, uint32_t tls_local_need, bool compatible)
bool CramMd5Handshake::CramMd5Challange()
{
struct timeval t1;
struct timeval t2;
struct timezone tz;
int i;
bool ok;
PoolMem chal(PM_NAME),
host(PM_NAME);
uint8_t hmac[20];
host(PM_NAME);

gettimeofday(&t1, &tz);
for (i=0; i<4; i++) {
gettimeofday(&t2, &tz);
}
srandom((t1.tv_sec & 0xffff) * (t2.tv_usec & 0xff));
InitRandom();

host.check_size(MAXHOSTNAMELEN);
if (!gethostname(host.c_str(), MAXHOSTNAMELEN)) {
Expand All @@ -66,83 +66,115 @@ bool cram_md5_challenge(BareosSocket *bs, const char *password, uint32_t tls_loc
/* Send challenge -- no hashing yet */
Mmsg(chal, "<%u.%u@%s>", (uint32_t)random(), (uint32_t)time(NULL), host.c_str());

Dmsg2(debuglevel, "send: auth cram-md5 %s ssl=%d\n", chal.c_str(), tls_local_need);
if (!bs->fsend("auth cram-md5 %s ssl=%d\n", chal.c_str(), tls_local_need)) {
Dmsg1(debuglevel, "Bnet send challenge comm error. ERR=%s\n", bs->bstrerror());
Dmsg2(debuglevel_, "send: auth cram-md5 %s ssl=%d\n", chal.c_str(), local_tls_policy_);
if (!bs_->fsend("auth cram-md5 %s ssl=%d\n", chal.c_str(), local_tls_policy_)) {
Dmsg1(debuglevel_, "Bnet send challenge comm error. ERR=%s\n", bs_->bstrerror());
return false;
}

/* Read hashed response to challenge */
if (bs->WaitData(180) <= 0 || bs->recv() <= 0) {
Dmsg1(debuglevel, "Bnet receive challenge response comm error. ERR=%s\n", bs->bstrerror());
Bmicrosleep(bs->sleep_time_after_authentication_error, 0);
if (bs_->WaitData(180) <= 0 || bs_->recv() <= 0) {
Dmsg1(debuglevel_, "Bnet receive challenge response comm error. ERR=%s\n", bs_->bstrerror());
Bmicrosleep(bs_->sleep_time_after_authentication_error, 0);
return false;
}

uint8_t hmac[20];
/* Attempt to duplicate hash with our password */
hmac_md5((uint8_t *)chal.c_str(), strlen(chal.c_str()), (uint8_t *)password, strlen(password), hmac);
BinToBase64(host.c_str(), MAXHOSTNAMELEN, (char *)hmac, 16, compatible);
ok = bstrcmp(bs->msg, host.c_str());
hmac_md5((uint8_t *)chal.c_str(), strlen(chal.c_str()), (uint8_t *)password_, strlen(password_), hmac);
BinToBase64(host.c_str(), MAXHOSTNAMELEN, (char *)hmac, 16, compatible_);
bool ok = bstrcmp(bs_->msg, host.c_str());
if (ok) {
Dmsg1(debuglevel, "Authenticate OK %s\n", host.c_str());
Dmsg1(debuglevel_, "Authenticate OK %s\n", host.c_str());
} else {
BinToBase64(host.c_str(), MAXHOSTNAMELEN, (char *)hmac, 16, false);
ok = bstrcmp(bs->msg, host.c_str());
ok = bstrcmp(bs_->msg, host.c_str());
if (!ok) {
Dmsg2(debuglevel, "Authenticate NOT OK: wanted %s, got %s\n", host.c_str(), bs->msg);
Dmsg2(debuglevel_, "Authenticate NOT OK: wanted %s, got %s\n", host.c_str(), bs_->msg);
}
}
if (ok) {
bs->fsend("1000 OK auth\n");
bs_->fsend("1000 OK auth\n");
} else {
bs->fsend(_("1999 Authorization failed.\n"));
Bmicrosleep(bs->sleep_time_after_authentication_error, 0);
bs_->fsend(_("1999 Authorization failed.\n"));
Bmicrosleep(bs_->sleep_time_after_authentication_error, 0);
}
return ok;
}

/* Respond to challenge from other end */
bool cram_md5_respond(BareosSocket *bs, const char *password, uint32_t *tls_remote_need, bool *compatible)
bool CramMd5Handshake::CramMd5Response()
{
PoolMem chal(PM_NAME);
uint8_t hmac[20];

*compatible = false;
if (bs->recv() <= 0) {
Bmicrosleep(bs->sleep_time_after_authentication_error, 0);
compatible_ = false;
if (bs_->recv() <= 0) {
Bmicrosleep(bs_->sleep_time_after_authentication_error, 0);
return false;
}

Dmsg1(100, "cram-get received: %s", bs->msg);
chal.check_size(bs->message_length);
if (sscanf(bs->msg, "auth cram-md5c %s ssl=%d", chal.c_str(), tls_remote_need) == 2) {
*compatible = true;
} else if (sscanf(bs->msg, "auth cram-md5 %s ssl=%d", chal.c_str(), tls_remote_need) != 2) {
if (sscanf(bs->msg, "auth cram-md5 %s\n", chal.c_str()) != 1) {
Dmsg1(debuglevel, "Cannot scan challenge: %s", bs->msg);
bs->fsend(_("1999 Authorization failed.\n"));
Bmicrosleep(bs->sleep_time_after_authentication_error, 0);
Dmsg1(100, "cram-get received: %s", bs_->msg);
chal.check_size(bs_->message_length);
if (sscanf(bs_->msg, "auth cram-md5c %s ssl=%d", chal.c_str(), &remote_tls_policy_) == 2) {
compatible_ = true;
} else if (sscanf(bs_->msg, "auth cram-md5 %s ssl=%d", chal.c_str(), &remote_tls_policy_) != 2) {
if (sscanf(bs_->msg, "auth cram-md5 %s\n", chal.c_str()) != 1) {
Dmsg1(debuglevel_, "Cannot scan challenge: %s", bs_->msg);
bs_->fsend(_("1999 Authorization failed.\n"));
Bmicrosleep(bs_->sleep_time_after_authentication_error, 0);
return false;
}
}

hmac_md5((uint8_t *)chal.c_str(), strlen(chal.c_str()), (uint8_t *)password, strlen(password), hmac);
bs->message_length = BinToBase64(bs->msg, 50, (char *)hmac, 16, *compatible) + 1;
// Dmsg3(100, "get_auth: chal=%s pw=%s hmac=%s\n", chal.c_str(), password, bs->msg);
if (!bs->send()) {
Dmsg1(debuglevel, "Send challenge failed. ERR=%s\n", bs->bstrerror());
hmac_md5((uint8_t *)chal.c_str(), strlen(chal.c_str()), (uint8_t *)password_, strlen(password_), hmac);
bs_->message_length = BinToBase64(bs_->msg, 50, (char *)hmac, 16, compatible_) + 1;
if (!bs_->send()) {
Dmsg1(debuglevel_, "Send challenge failed. ERR=%s\n", bs_->bstrerror());
return false;
}
Dmsg1(99, "sending resp to challenge: %s\n", bs->msg);
if (bs->WaitData(180) <= 0 || bs->recv() <= 0) {
Dmsg1(debuglevel, "Receive challenge response failed. ERR=%s\n", bs->bstrerror());
Bmicrosleep(bs->sleep_time_after_authentication_error, 0);
Dmsg1(99, "sending resp to challenge: %s\n", bs_->msg);
if (bs_->WaitData(180) <= 0 || bs_->recv() <= 0) {
Dmsg1(debuglevel_, "Receive challenge response failed. ERR=%s\n", bs_->bstrerror());
Bmicrosleep(bs_->sleep_time_after_authentication_error, 0);
return false;
}
if (bstrcmp(bs->msg, "1000 OK auth\n")) {
if (bstrcmp(bs_->msg, "1000 OK auth\n")) {
return true;
}
Dmsg1(debuglevel, "Received bad response: %s\n", bs->msg);
Bmicrosleep(bs->sleep_time_after_authentication_error, 0);
Dmsg1(debuglevel_, "Received bad response: %s\n", bs_->msg);
Bmicrosleep(bs_->sleep_time_after_authentication_error, 0);
return false;
}

bool CramMd5Handshake::DoHandshake(bool initiated_by_remote)
{
if (initiated_by_remote) {
if (CramMd5Challange()) {
if (CramMd5Response()) {
return true;
}
}
} else {
if (CramMd5Response()) {
if (CramMd5Challange()) {
return true;
}
}
}

Dmsg1(debuglevel_, "cram-auth failed with %s\n", bs_->who());
return false;
}

void CramMd5Handshake::InitRandom() const
{
struct timeval t1;
struct timeval t2;
struct timezone tz;

gettimeofday(&t1, &tz);
for (int i=0; i<4; i++) {
gettimeofday(&t2, &tz);
}
srandom((t1.tv_sec & 0xffff) * (t2.tv_usec & 0xff));
}

0 comments on commit f277d7c

Please sign in to comment.