diff options
| author | Treeston <treeston.mmoc@gmail.com> | 2019-08-10 21:34:51 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-08-10 21:34:51 +0200 |
| commit | 4211645834c467a03c60248e80818d3607be9ea7 (patch) | |
| tree | 673a1695581503b6ea3e49da5c3e0d06bf5d892e /src/server/authserver | |
| parent | 3d356b97d4cc4c7ec4c641487241eae6dcc0558e (diff) | |
[3.3.5] Core/Authserver: TOTP rewrite: (PR #23633)
- Proper management commands (.account 2fa)
- Secrets can now be encrypted (set TOTPTokenSecret in .conf)
- Secret now stored in binary
- Argon2 and AES primitives
- Base32/64 support
Diffstat (limited to 'src/server/authserver')
| -rw-r--r-- | src/server/authserver/Authentication/TOTP.cpp | 95 | ||||
| -rw-r--r-- | src/server/authserver/Authentication/TOTP.h | 29 | ||||
| -rw-r--r-- | src/server/authserver/Main.cpp | 5 | ||||
| -rw-r--r-- | src/server/authserver/Server/AuthSession.cpp | 63 | ||||
| -rw-r--r-- | src/server/authserver/Server/AuthSession.h | 8 | ||||
| -rw-r--r-- | src/server/authserver/authserver.conf.dist | 19 |
6 files changed, 70 insertions, 149 deletions
diff --git a/src/server/authserver/Authentication/TOTP.cpp b/src/server/authserver/Authentication/TOTP.cpp deleted file mode 100644 index 3f7062d6b7f..00000000000 --- a/src/server/authserver/Authentication/TOTP.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "TOTP.h" -#include <cstring> - -int base32_decode(char const* encoded, char* result, int bufSize) -{ - // Base32 implementation - // Copyright 2010 Google Inc. - // Author: Markus Gutschke - // Licensed under the Apache License, Version 2.0 - int buffer = 0; - int bitsLeft = 0; - int count = 0; - for (const char *ptr = encoded; count < bufSize && *ptr; ++ptr) - { - char ch = *ptr; - if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '-') - continue; - buffer <<= 5; - - // Deal with commonly mistyped characters - if (ch == '0') - ch = 'O'; - else if (ch == '1') - ch = 'L'; - else if (ch == '8') - ch = 'B'; - - // Look up one base32 digit - if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) - ch = (ch & 0x1F) - 1; - else if (ch >= '2' && ch <= '7') - ch -= '2' - 26; - else - return -1; - - buffer |= ch; - bitsLeft += 5; - if (bitsLeft >= 8) - { - result[count++] = buffer >> (bitsLeft - 8); - bitsLeft -= 8; - } - } - - if (count < bufSize) - result[count] = '\000'; - return count; -} - -#define HMAC_RES_SIZE 20 - -namespace TOTP -{ - unsigned int GenerateToken(char const* b32key) - { - size_t keySize = strlen(b32key); - int bufsize = (keySize + 7)/8*5; - char* encoded = new char[bufsize]; - memset(encoded, 0, bufsize); - unsigned int hmacResSize = HMAC_RES_SIZE; - unsigned char hmacRes[HMAC_RES_SIZE]; - unsigned long timestamp = time(nullptr)/30; - unsigned char challenge[8]; - - for (int i = 8; i--;timestamp >>= 8) - challenge[i] = timestamp; - - base32_decode(b32key, encoded, bufsize); - HMAC(EVP_sha1(), encoded, bufsize, challenge, 8, hmacRes, &hmacResSize); - unsigned int offset = hmacRes[19] & 0xF; - unsigned int truncHash = (hmacRes[offset] << 24) | (hmacRes[offset+1] << 16 )| (hmacRes[offset+2] << 8) | (hmacRes[offset+3]); - truncHash &= 0x7FFFFFFF; - - delete[] encoded; - - return truncHash % 1000000; - } -} diff --git a/src/server/authserver/Authentication/TOTP.h b/src/server/authserver/Authentication/TOTP.h deleted file mode 100644 index 0c66820a879..00000000000 --- a/src/server/authserver/Authentication/TOTP.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef _TOTP_H -#define _TOTP_H - -#include "openssl/hmac.h" -#include "openssl/evp.h" - -namespace TOTP -{ - unsigned int GenerateToken(char const* b32key); -} - -#endif diff --git a/src/server/authserver/Main.cpp b/src/server/authserver/Main.cpp index 1b58aa35155..fe9ff9f9b3f 100644 --- a/src/server/authserver/Main.cpp +++ b/src/server/authserver/Main.cpp @@ -37,6 +37,8 @@ #include "MySQLThreading.h" #include "ProcessPriority.h" #include "RealmList.h" +#include "SecretMgr.h" +#include "SharedDefines.h" #include "Util.h" #include <boost/asio/signal_set.hpp> #include <boost/program_options.hpp> @@ -79,6 +81,7 @@ variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, s int main(int argc, char** argv) { + Trinity::Impl::CurrentServerProcessHolder::_type = SERVER_PROCESS_AUTHSERVER; signal(SIGABRT, &Trinity::AbortHandler); auto configFile = fs::absolute(_TRINITY_REALM_CONFIG); @@ -139,6 +142,8 @@ int main(int argc, char** argv) if (!StartDB()) return 1; + sSecretMgr->Initialize(); + // Load IP Location Database sIPLocation->Load(); diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index 78aa977ab92..5c0628334fd 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -17,13 +17,16 @@ */ #include "AuthSession.h" +#include "AES.h" #include "AuthCodes.h" #include "Config.h" +#include "CryptoGenerics.h" +#include "DatabaseEnv.h" #include "Errors.h" #include "IPLocation.h" #include "Log.h" -#include "DatabaseEnv.h" #include "RealmList.h" +#include "SecretMgr.h" #include "SHA1.h" #include "TOTP.h" #include "Util.h" @@ -139,7 +142,7 @@ void AccountInfo::LoadResult(Field* fields) // 0 1 2 3 4 5 6 //SELECT a.id, a.username, a.locked, a.lock_country, a.last_ip, a.failed_logins, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, // 7 8 9 10 11 12 - // ab.unbandate = ab.bandate, aa.gmlevel, a.token_key, a.sha_pass_hash, a.v, a.s + // ab.unbandate = ab.bandate, aa.gmlevel, a.totp_secret, a.sha_pass_hash, a.v, a.s //FROM account a LEFT JOIN account_access aa ON a.id = aa.id LEFT JOIN account_banned ab ON ab.id = a.id AND ab.active = 1 WHERE a.username = ? Id = fields[0].GetUInt32(); @@ -380,6 +383,25 @@ void AuthSession::LogonChallengeCallback(PreparedQueryResult result) } } + uint8 securityFlags = 0; + // Check if a TOTP token is needed + if (!fields[9].IsNull()) + { + securityFlags = 4; + _totpSecret = fields[9].GetBinary(); + if (auto const& secret = sSecretMgr->GetSecret(SECRET_TOTP_MASTER_KEY)) + { + bool success = Trinity::Crypto::AEDecrypt<Trinity::Crypto::AES>(*_totpSecret, *secret); + if (!success) + { + pkt << uint8(WOW_FAIL_DB_BUSY); + TC_LOG_ERROR("server.authserver", "[AuthChallenge] Account '%s' has invalid ciphertext for TOTP token key stored", _accountInfo.Login.c_str()); + SendPacket(pkt); + return; + } + } + } + // Get the password from the account table, upper it, and make the SRP6 calculation std::string rI = fields[10].GetString(); @@ -421,13 +443,6 @@ void AuthSession::LogonChallengeCallback(PreparedQueryResult result) pkt.append(N.AsByteArray(32).get(), 32); pkt.append(s.AsByteArray(int32(BufferSizes::SRP_6_S)).get(), size_t(BufferSizes::SRP_6_S)); // 32 bytes pkt.append(VersionChallenge.data(), VersionChallenge.size()); - uint8 securityFlags = 0; - - // Check if token is used - _tokenKey = fields[9].GetString(); - if (!_tokenKey.empty()) - securityFlags = 4; - pkt << uint8(securityFlags); // security flags (0x0...0x04) if (securityFlags & 0x01) // PIN input @@ -548,23 +563,29 @@ bool AuthSession::HandleLogonProof() if (!memcmp(M.AsByteArray(sha.GetLength()).get(), logonProof->M1, 20)) { // Check auth token - if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty()) + bool tokenSuccess = false; + bool sentToken = (logonProof->securityFlags & 0x04); + if (sentToken && _totpSecret) { uint8 size = *(GetReadBuffer().GetReadPointer() + sizeof(sAuthLogonProof_C)); std::string token(reinterpret_cast<char*>(GetReadBuffer().GetReadPointer() + sizeof(sAuthLogonProof_C) + sizeof(size)), size); GetReadBuffer().ReadCompleted(sizeof(size) + size); - uint32 validToken = TOTP::GenerateToken(_tokenKey.c_str()); - _tokenKey.clear(); + uint32 incomingToken = atoi(token.c_str()); - if (validToken != incomingToken) - { - ByteBuffer packet; - packet << uint8(AUTH_LOGON_PROOF); - packet << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); - packet << uint16(0); // LoginFlags, 1 has account message - SendPacket(packet); - return true; - } + tokenSuccess = Trinity::Crypto::TOTP::ValidateToken(*_totpSecret, incomingToken); + memset(_totpSecret->data(), 0, _totpSecret->size()); + } + else if (!sentToken && !_totpSecret) + tokenSuccess = true; + + if (!tokenSuccess) + { + ByteBuffer packet; + packet << uint8(AUTH_LOGON_PROOF); + packet << uint8(WOW_FAIL_UNKNOWN_ACCOUNT); + packet << uint16(0); // LoginFlags, 1 has account message + SendPacket(packet); + return true; } if (!VerifyVersion(logonProof->A, sizeof(logonProof->A), logonProof->crc_hash, false)) diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h index 9c603616225..cac1450b401 100644 --- a/src/server/authserver/Server/AuthSession.h +++ b/src/server/authserver/Server/AuthSession.h @@ -19,10 +19,11 @@ #ifndef __AUTHSESSION_H__ #define __AUTHSESSION_H__ -#include "Common.h" +#include "BigNumber.h" #include "ByteBuffer.h" +#include "Common.h" +#include "Optional.h" #include "Socket.h" -#include "BigNumber.h" #include "QueryResult.h" #include "QueryCallbackProcessor.h" #include <memory> @@ -56,7 +57,6 @@ struct AccountInfo bool IsBanned = false; bool IsPermanenetlyBanned = false; AccountTypes SecurityLevel = SEC_PLAYER; - std::string TokenKey; }; class AuthSession : public Socket<AuthSession> @@ -99,7 +99,7 @@ private: AuthStatus _status; AccountInfo _accountInfo; - std::string _tokenKey; + Optional<std::vector<uint8>> _totpSecret; std::string _localizationName; std::string _os; std::string _ipCountry; diff --git a/src/server/authserver/authserver.conf.dist b/src/server/authserver/authserver.conf.dist index f3aa6f6e67e..480a49eca8e 100644 --- a/src/server/authserver/authserver.conf.dist +++ b/src/server/authserver/authserver.conf.dist @@ -9,6 +9,7 @@ # EXAMPLE CONFIG # AUTH SERVER SETTINGS # MYSQL SETTINGS +# CRYPTOGRAPHY # UPDATE SETTINGS # LOGGING SYSTEM SETTINGS # @@ -213,6 +214,24 @@ LoginDatabase.SynchThreads = 1 ################################################################################################### ################################################################################################### +# CRYPTOGRAPHY +# +# TOTPMasterSecret +# Description: The master key used to encrypt TOTP secrets for database storage. +# If you want to change this, uncomment TOTPOldMasterSecret, then copy +# your old secret there and startup authserver once. Afterwards, you can re- +# comment that line and get rid of your old secret. +# +# Default: <blank> - (Store TOTP secrets unencrypted) +# Example: 000102030405060708090A0B0C0D0E0F + +TOTPMasterSecret = +# TOTPOldMasterSecret = + +# +################################################################################################### + +################################################################################################### # UPDATE SETTINGS # # Updates.EnableDatabases |
