diff --git a/src/cpp/Crypto/AuthenticatedEncryption.h b/src/cpp/Crypto/AuthenticatedEncryption.h index 735ed589d..e3a920ec9 100644 --- a/src/cpp/Crypto/AuthenticatedEncryption.h +++ b/src/cpp/Crypto/AuthenticatedEncryption.h @@ -47,6 +47,9 @@ public: std::shared_lock _lock(mWorkingMutex); return mEncryptionKeyHash == b.getKeyHashed(); } + inline bool operator == (const KeyHashed& hash) const { + return mEncryptionKeyHash == hash; + } inline bool hasKey() const { std::shared_lock _lock(mWorkingMutex); return mEncryptionKey != nullptr; } diff --git a/src/cpp/Crypto/KeyPairEd25519.cpp b/src/cpp/Crypto/KeyPairEd25519.cpp index bb2235291..e06ff02d8 100644 --- a/src/cpp/Crypto/KeyPairEd25519.cpp +++ b/src/cpp/Crypto/KeyPairEd25519.cpp @@ -13,7 +13,8 @@ KeyPairEd25519::KeyPairEd25519(MemoryBin* privateKey) { //memcpy(mSodiumPublic, publicKey, crypto_sign_PUBLICKEYBYTES); // read pubkey from private key, so we are sure it is the correct pubkey for the private key - crypto_sign_ed25519_sk_to_pk(*privateKey, mSodiumPublic); + + crypto_sign_ed25519_sk_to_pk(mSodiumPublic, *privateKey); } KeyPairEd25519::KeyPairEd25519(const unsigned char* publicKey) @@ -95,6 +96,7 @@ KeyPairEd25519* KeyPairEd25519::create(const Passphrase* passphrase) } crypto_sign_seed_keypair(key_pair->mSodiumPublic, *key_pair->mSodiumSecret, hash); + return key_pair; // print hex for all keys for debugging diff --git a/src/cpp/HTTPInterface/LoginPage.cpp b/src/cpp/HTTPInterface/LoginPage.cpp index 7d5b4d73f..756cb2c61 100644 --- a/src/cpp/HTTPInterface/LoginPage.cpp +++ b/src/cpp/HTTPInterface/LoginPage.cpp @@ -121,6 +121,9 @@ void LoginPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net:: } response.redirect(ServerConfig::g_serverPath + "/passphrase"); return; + case USER_KEYS_DONT_MATCH: + addError(new Error(langCatalog->gettext("User"), langCatalog->gettext("Error in saved data, the server admin will look at it."))); + break; case USER_NO_PRIVATE_KEY: case USER_COMPLETE: auto referer = request.find("Referer"); @@ -222,20 +225,20 @@ void LoginPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net:: responseStream << "
\n"; responseStream << "
\n"; responseStream << " \n"; responseStream << "\t\t\t\n"; responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t\t \n"; responseStream << "\t\t\t\t\"logo\"\n"; responseStream << "\t\t\t\n"; @@ -247,14 +250,14 @@ void LoginPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net:: responseStream << "
\n"; responseStream << "\t\t\t
\n"; responseStream << "\t\t\t\t"; -#line 165 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp" +#line 168 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp" responseStream << ( getErrorsHtml() ); responseStream << "\t \n"; responseStream << "\t\t\t
\n"; responseStream << "
\n"; responseStream << " \n"; responseStream << "\t\t\t \n"; responseStream << "\t\t\t "; @@ -294,46 +297,46 @@ void LoginPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net:: // end include flags.cpsp responseStream << "\n"; responseStream << "\t\t\t
\n"; responseStream << "
\n"; responseStream << "
\n"; responseStream << "
\n"; responseStream << " gettext("E-Mail") ); responseStream << "\" value=\""; -#line 175 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp" +#line 178 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp" responseStream << ( presetEmail ); responseStream << "\"/>\n"; responseStream << "
\n"; responseStream << "
\n"; responseStream << " gettext("Password") ); responseStream << "\" />\n"; responseStream << "
\n"; responseStream << " \n"; responseStream << "
\n"; responseStream << "\t\t\t\t\t\n"; diff --git a/src/cpp/controller/User.cpp b/src/cpp/controller/User.cpp index 59e2d57dd..719f13382 100644 --- a/src/cpp/controller/User.cpp +++ b/src/cpp/controller/User.cpp @@ -122,6 +122,42 @@ namespace controller { return json; } + int User::login(const std::string& password) + { + if (mPassword && mPassword->hasKey()) { + return 2; + } + std::unique_lock _lock(mSharedMutex); + auto authenticated_encryption = new AuthenticatedEncryption(); + auto model = getModel(); + assert(authenticated_encryption && model); + + authenticated_encryption->createKey(model->getEmail(), password); + if (authenticated_encryption->getKeyHashed() == model->getPasswordHashed()) { + MemoryBin* clear_private_key = nullptr; + auto priv_key_encrypted = model->getPrivateKeyEncrypted(); + auto priv_key_bin = MemoryManager::getInstance()->getFreeMemory(priv_key_encrypted.size()); + memcpy(*priv_key_bin, priv_key_encrypted.data(), priv_key_encrypted.size()); + if (AuthenticatedEncryption::AUTH_DECRYPT_OK == authenticated_encryption->decrypt(priv_key_bin, &clear_private_key)) { + auto gradido_key_pair = new KeyPairEd25519(clear_private_key); + if (*gradido_key_pair != model->getPublicKey()) { + delete authenticated_encryption; + delete gradido_key_pair; + return -1; + } + if (mGradidoKeyPair) delete mGradidoKeyPair; + mGradidoKeyPair = gradido_key_pair; + if (mPassword) delete mPassword; + mPassword = authenticated_encryption; + return 1; + } + } + delete authenticated_encryption; + + // password didn't match + return 0; + } + int User::setPassword(AuthenticatedEncryption* passwd) { std::unique_lock _lock(mSharedMutex); @@ -130,7 +166,14 @@ namespace controller { if (mPassword) { - if (mPassword == passwd) return 0; + // if keys matched + if (*mPassword == *passwd) { + // but separate objects + if (mPassword != passwd) { + delete passwd; + } + return 0; + } // if password exist but gradido key pair not, try to load key pair if ((!mGradidoKeyPair || !mGradidoKeyPair->hasPrivateKey()) && model->hasPrivateKeyEncrypted()) { //if (!mGradidoKeyPair) mGradidoKeyPair = new KeyPairEd25519; @@ -143,24 +186,33 @@ namespace controller { if (*mGradidoKeyPair != model->getPublicKey()) { delete mGradidoKeyPair; mGradidoKeyPair = nullptr; + delete passwd; return -1; } } } - - delete passwd; } // replace old password with new + if (mPassword && mPassword != passwd) { + delete mPassword; + } mPassword = passwd; // set new encrypted password and hash model->setPasswordHashed(mPassword->getKeyHashed()); - auto encryptedPrivateKey = mGradidoKeyPair->getCryptedPrivKey(mPassword); - model->setPrivateKey(encryptedPrivateKey); - MemoryManager::getInstance()->releaseMemory(encryptedPrivateKey); + int result = 2; + if (mGradidoKeyPair && mGradidoKeyPair->hasPrivateKey()) { + auto encryptedPrivateKey = mGradidoKeyPair->getCryptedPrivKey(mPassword); + model->setPrivateKey(encryptedPrivateKey); + MemoryManager::getInstance()->releaseMemory(encryptedPrivateKey); + result = model->updatePrivkeyAndPasswordHash(); + } + else { + model->updateIntoDB("password", mPassword->getKeyHashed()); + } // save changes to db - return model->updatePrivkeyAndPasswordHash(); + return result; } } \ No newline at end of file diff --git a/src/cpp/controller/User.h b/src/cpp/controller/User.h index 06a62ca14..424f8d5a8 100644 --- a/src/cpp/controller/User.h +++ b/src/cpp/controller/User.h @@ -40,13 +40,23 @@ namespace controller { std::string getEmailWithNames(); const std::string& getPublicHex(); + //! \brief check if password match saved password, long duration + //! \return 1 logged in + //! \return 2 already logged in + //! \return 0 password didn't match + //! \return -1 error saved public key didn't match with private key + //! - create authenticated encryption key from password and email + //! - compare hash with in db saved hash + + int login(const std::string& password); // *********************************************************************************** // password related - //! \brief set authenticated encryption and save hash in db, should also re encrypt private key if exist + //! \brief set authenticated encryption and save hash in db, also re encrypt private key if exist //! \param passwd take owner ship //! \return 0 = new and current passwords are the same //! \return 1 = password changed, private key re-encrypted and saved into db + //! \return 2 = password changed, only hash stored in db, couldn't load private key for re-encryption //! \return -1 = stored pubkey and private key didn't match int setPassword(AuthenticatedEncryption* passwd); @@ -54,8 +64,14 @@ namespace controller { std::shared_lock _lock(mSharedMutex); return mPassword; } + inline const KeyPairEd25519* getGradidoKeyPair() { + std::shared_lock _lock(mSharedMutex); + return mGradidoKeyPair; + } protected: User(model::table::User* dbModel); + + std::string mPublicHex; diff --git a/src/cpp/model/Session.cpp b/src/cpp/model/Session.cpp index 9c4a44650..33784c7fc 100644 --- a/src/cpp/model/Session.cpp +++ b/src/cpp/model/Session.cpp @@ -631,6 +631,7 @@ bool Session::isPwdValid(const std::string& pwd) UserStates Session::loadUser(const std::string& email, const std::string& password) { + static const char* functionName = "Session::loadUser"; auto observer = SingletonTaskObserver::getInstance(); if (email != "") { if (observer->getTaskCount(email, TASK_OBSERVER_PASSWORD_CREATION) > 0) { @@ -638,7 +639,7 @@ UserStates Session::loadUser(const std::string& email, const std::string& passwo } } //Profiler usedTime; - lock("Session::loadUser"); + lock(functionName); if (mSessionUser && mSessionUser->getEmail() != email) { mSessionUser.assign(nullptr); mNewUser.assign(nullptr); @@ -653,6 +654,20 @@ UserStates Session::loadUser(const std::string& email, const std::string& passwo //mSessionUser = new User(email.data()); } if (mSessionUser->getUserState() >= USER_LOADED_FROM_DB) { + int loginResult = mNewUser->login(password); + + if (-1 == loginResult) { + addError(new Error(functionName, "error in user data set, saved pubkey didn't match extracted pubkey from private key")); + addError(new ParamError(functionName, "user email", mNewUser->getModel()->getEmail())); + sendErrorsAsEmail(); + //unlock(); + //return USER_KEYS_DONT_MATCH; + } + if (0 == loginResult) { + unlock(); + return USER_PASSWORD_INCORRECT; + } + // can be removed if session user isn't used any more if (mNewUser->getModel()->getPasswordHashed() && !mSessionUser->validatePwd(password, this)) { unlock(); return USER_PASSWORD_INCORRECT; diff --git a/src/cpp/model/User.h b/src/cpp/model/User.h index 54effae90..698abd44c 100644 --- a/src/cpp/model/User.h +++ b/src/cpp/model/User.h @@ -35,6 +35,7 @@ enum UserStates USER_EMAIL_NOT_ACTIVATED, USER_NO_KEYS, USER_NO_PRIVATE_KEY, + USER_KEYS_DONT_MATCH, USER_COMPLETE }; diff --git a/src/cpp/test/controller/TestUser.cpp b/src/cpp/test/controller/TestUser.cpp index e69de29bb..fc8f8389b 100644 --- a/src/cpp/test/controller/TestUser.cpp +++ b/src/cpp/test/controller/TestUser.cpp @@ -0,0 +1,10 @@ +#include "TestUser.h" + +namespace controller { + void TestUser::SetUp() + { + + } + + //TEST_F(TestUser, ) +} \ No newline at end of file diff --git a/src/cpp/test/controller/TestUser.h b/src/cpp/test/controller/TestUser.h index e69de29bb..8abe23e7a 100644 --- a/src/cpp/test/controller/TestUser.h +++ b/src/cpp/test/controller/TestUser.h @@ -0,0 +1,16 @@ +#ifndef __GRADIDO_LOGIN_SERVER_TEST_CONTROLLER_USER_H +#define __GRADIDO_LOGIN_SERVER_TEST_CONTROLLER_USER_H + + +#include "gtest/gtest.h" + +namespace controller { + + class TestUser : public ::testing::Test { + protected: + void SetUp() override; + }; +} + + +#endif //__GRADIDO_LOGIN_SERVER_TEST_CONTROLLER_USER_H \ No newline at end of file diff --git a/src/cpp/test/main.cpp b/src/cpp/test/main.cpp index c7fe97240..5fcab4163 100644 --- a/src/cpp/test/main.cpp +++ b/src/cpp/test/main.cpp @@ -4,7 +4,9 @@ #include "gtest/gtest.h" #include "Poco/Util/PropertyFileConfiguration.h" +#include "Poco/Environment.h" +#include "../SingletonManager/ConnectionManager.h" std::list gTests; @@ -35,6 +37,24 @@ int load() { return -2; } + // start cpu scheduler + uint8_t worker_count = Poco::Environment::processorCount(); + + ServerConfig::g_CPUScheduler = new UniLib::controller::CPUSheduler(worker_count, "Default Worker"); + ServerConfig::g_CryptoCPUScheduler = new UniLib::controller::CPUSheduler(2, "Crypto Worker"); + + // load up connection configs + // register MySQL connector + Poco::Data::MySQL::Connector::registerConnector(); + //Poco::Data::MySQL::Connector::KEY; + auto conn = ConnectionManager::getInstance(); + //conn->setConnection() + //printf("try connect login server mysql db\n"); + conn->setConnectionsFromConfig(*test_config, CONNECTION_MYSQL_LOGIN_SERVER); + //printf("try connect php server mysql \n"); + conn->setConnectionsFromConfig(*test_config, CONNECTION_MYSQL_PHP_SERVER); + + fillTests(); for (std::list::iterator it = gTests.begin(); it != gTests.end(); it++) { diff --git a/src/cpsp/login.cpsp b/src/cpsp/login.cpsp index b93b79464..c32381745 100644 --- a/src/cpsp/login.cpsp +++ b/src/cpsp/login.cpsp @@ -100,6 +100,9 @@ } response.redirect(ServerConfig::g_serverPath + "/passphrase"); return; + case USER_KEYS_DONT_MATCH: + addError(new Error(langCatalog->gettext("User"), langCatalog->gettext("Error in saved data, the server admin will look at it."))); + break; case USER_NO_PRIVATE_KEY: case USER_COMPLETE: auto referer = request.find("Referer");