From 86bb678eed1bca92719202b8f37b41d0e219ee66 Mon Sep 17 00:00:00 2001 From: Frank Ueberschar Date: Fri, 1 Jun 2018 21:58:15 +0200 Subject: [PATCH] cram-md5: moved stuff into separate class moved md5 challenge and respond from bsocket::two_way_authenticate int separate class CramMd5Handshake --- core/src/dird/backup.cc | 4 +- core/src/dird/migrate.cc | 2 +- core/src/dird/restore.cc | 4 +- core/src/dird/verify.cc | 4 +- core/src/lib/bsock.cc | 75 ++++----------------- core/src/lib/bsock.h | 2 +- core/src/lib/cram-md5.cc | 142 ++++++++++++++++++++++++--------------- core/src/lib/cram_md5.h | 19 ++++++ 8 files changed, 127 insertions(+), 125 deletions(-) diff --git a/core/src/dird/backup.cc b/core/src/dird/backup.cc index 8fe15338b9a..ab2afcb2ce9 100644 --- a/core/src/dird/backup.cc +++ b/core/src/dird/backup.cc @@ -554,7 +554,7 @@ bool DoNativeBackup(JobControlRecord *jcr) * TLS Requirement */ - tls_need = GetNeedFromConfiguration(client); + tls_need = GetLocalTlsPolicyFromConfiguration(client); connection_target_address = StorageAddressToContact(client, store); @@ -568,7 +568,7 @@ bool DoNativeBackup(JobControlRecord *jcr) * TLS Requirement */ - tls_need = GetNeedFromConfiguration(me); + tls_need = GetLocalTlsPolicyFromConfiguration(me); connection_target_address = ClientAddressToContact(client, store); diff --git a/core/src/dird/migrate.cc b/core/src/dird/migrate.cc index 422931c3ec8..ed8f2c6f81b 100644 --- a/core/src/dird/migrate.cc +++ b/core/src/dird/migrate.cc @@ -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); diff --git a/core/src/dird/restore.cc b/core/src/dird/restore.cc index fba50510d41..058a9a809fc 100644 --- a/core/src/dird/restore.cc +++ b/core/src/dird/restore.cc @@ -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); @@ -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); /* diff --git a/core/src/dird/verify.cc b/core/src/dird/verify.cc index 27dba780327..5e295d1b5dd 100644 --- a/core/src/dird/verify.cc +++ b/core/src/dird/verify.cc @@ -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)) { @@ -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. diff --git a/core/src/lib/bsock.cc b/core/src/lib/bsock.cc index cd855b6b183..6af00395424 100644 --- a/core/src/lib/bsock.cc +++ b/core/src/lib/bsock.cc @@ -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 @@ -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; } @@ -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, @@ -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_ctx = selected_local_tls->CreateServerContext( std::make_shared(identity, password.value)); diff --git a/core/src/lib/bsock.h b/core/src/lib/bsock.h index b9ac7eb39a1..47773680b5a 100644 --- a/core/src/lib/bsock.h +++ b/core/src/lib/bsock.h @@ -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); diff --git a/core/src/lib/cram-md5.cc b/core/src/lib/cram-md5.cc index 641e398544a..17e004d11db 100644 --- a/core/src/lib/cram-md5.cc +++ b/core/src/lib/cram-md5.cc @@ -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: @@ -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)) { @@ -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)); +} diff --git a/core/src/lib/cram_md5.h b/core/src/lib/cram_md5.h index 29ed5ffbed4..8ed40e251e8 100644 --- a/core/src/lib/cram_md5.h +++ b/core/src/lib/cram_md5.h @@ -21,6 +21,25 @@ #ifndef LIB_CRAM_MD5_H_ #define LIB_CRAM_MD5_H_ +class CramMd5Handshake +{ +public: + CramMd5Handshake(BareosSocket *bs, const char *passwort, uint32_t local_tls_policy); + bool DoHandshake(bool initiated_by_remote); + uint32_t RemoteTlsPolicy() const { return remote_tls_policy_; } + +private: + static constexpr int debuglevel_ = 50; + bool compatible_ = false; + BareosSocket *bs_; + const char *password_; + uint32_t local_tls_policy_; + uint32_t remote_tls_policy_; + bool CramMd5Challange(); + bool CramMd5Response(); + void InitRandom() const; +}; + DLL_IMP_EXP bool cram_md5_respond(BareosSocket *bs, const char *password, uint32_t *remote_tls_policy, bool *compatible); DLL_IMP_EXP bool cram_md5_challenge(BareosSocket *bs, const char *password, uint32_t local_tls_policy, bool compatible); DLL_IMP_EXP void hmac_md5(uint8_t *text, int text_len, uint8_t *key, int key_len, uint8_t *hmac);