From 0bb6332a13b5988a2b36b39c7d5c227994e3f5ca Mon Sep 17 00:00:00 2001 From: Dario Date: Sun, 3 Nov 2019 19:48:26 +0100 Subject: [PATCH] Transaction Roundtrip success --- src/cpp/ServerConfig.cpp | 2 + src/cpp/ServerConfig.h | 1 + src/cpp/model/TransactionBase.h | 1 + src/cpp/model/TransactionCreation.cpp | 3 +- src/cpp/model/TransactionTransfer.cpp | 2 +- src/cpp/model/TransactionTransfer.h | 2 +- src/cpp/model/User.cpp | 35 +++++- src/cpp/model/User.h | 3 + src/cpp/tasks/ProcessingTransaction.cpp | 19 +++ src/cpp/tasks/ProcessingTransaction.h | 1 + src/cpp/tasks/SigningTransaction.cpp | 155 +++++++++++++++++++++--- 11 files changed, 201 insertions(+), 23 deletions(-) diff --git a/src/cpp/ServerConfig.cpp b/src/cpp/ServerConfig.cpp index 770067cf2..8018b531a 100644 --- a/src/cpp/ServerConfig.cpp +++ b/src/cpp/ServerConfig.cpp @@ -39,6 +39,7 @@ namespace ServerConfig { int g_SessionTimeout = SESSION_TIMEOUT_DEFAULT; std::string g_serverPath; std::string g_php_serverPath; + std::string g_php_serverHost; Poco::Mutex g_TimeMutex; bool loadMnemonicWordLists() @@ -93,6 +94,7 @@ namespace ServerConfig { g_SessionTimeout = cfg.getInt("session.timeout", SESSION_TIMEOUT_DEFAULT); g_serverPath = cfg.getString("loginServer.path", ""); g_php_serverPath = cfg.getString("phpServer.url", ""); + g_php_serverHost = cfg.getString("phpServer.host", ""); return true; } diff --git a/src/cpp/ServerConfig.h b/src/cpp/ServerConfig.h index bd29d95a2..cdf4dd6c3 100644 --- a/src/cpp/ServerConfig.h +++ b/src/cpp/ServerConfig.h @@ -38,6 +38,7 @@ namespace ServerConfig { extern int g_SessionTimeout; extern std::string g_serverPath; extern std::string g_php_serverPath; + extern std::string g_php_serverHost; extern Poco::Mutex g_TimeMutex; diff --git a/src/cpp/model/TransactionBase.h b/src/cpp/model/TransactionBase.h index 75318829e..cd4999fff 100644 --- a/src/cpp/model/TransactionBase.h +++ b/src/cpp/model/TransactionBase.h @@ -11,6 +11,7 @@ #include "../lib/ErrorList.h" #include "../proto/gradido/BasicTypes.pb.h" +#include "../SingletonManager/MemoryManager.h" class TransactionBase : public ErrorList { diff --git a/src/cpp/model/TransactionCreation.cpp b/src/cpp/model/TransactionCreation.cpp index 6d7a12fd7..d26af84cd 100644 --- a/src/cpp/model/TransactionCreation.cpp +++ b/src/cpp/model/TransactionCreation.cpp @@ -47,4 +47,5 @@ int TransactionCreation::prepare() return 0; -} \ No newline at end of file +} + diff --git a/src/cpp/model/TransactionTransfer.cpp b/src/cpp/model/TransactionTransfer.cpp index ca2c405bc..a5c1fcbf1 100644 --- a/src/cpp/model/TransactionTransfer.cpp +++ b/src/cpp/model/TransactionTransfer.cpp @@ -11,4 +11,4 @@ int TransactionTransfer::prepare() { return 0; -} \ No newline at end of file +} diff --git a/src/cpp/model/TransactionTransfer.h b/src/cpp/model/TransactionTransfer.h index 22363ef03..ec10883e2 100644 --- a/src/cpp/model/TransactionTransfer.h +++ b/src/cpp/model/TransactionTransfer.h @@ -17,7 +17,7 @@ class TransactionTransfer : public TransactionBase public: TransactionTransfer(const std::string& memo, const model::messages::gradido::Transfer& protoTransfer); - int prepare(); + int prepare(); protected: const model::messages::gradido::Transfer& mProtoTransfer; diff --git a/src/cpp/model/User.cpp b/src/cpp/model/User.cpp index 1f359e54a..bf1d127b6 100644 --- a/src/cpp/model/User.cpp +++ b/src/cpp/model/User.cpp @@ -49,6 +49,7 @@ int UserGenerateKeys::run() mKeys.generateFromPassphrase(mPassphrase.data(), &ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]); mUser->setPublicKeyHex(mKeys.getPubkeyHex()); + mUser->setPublicKey(mKeys.getPublicKey()); if (mUser->hasCryptoKey()) { mUser->setPrivKey(mKeys.getPrivateKey()); } @@ -176,7 +177,7 @@ User::User(const char* email, const char* first_name, const char* last_name) : mState(USER_EMPTY), mDBId(0), mEmail(email), mFirstName(first_name), mLastName(last_name), mPasswordHashed(0), mPrivateKey(nullptr), mEmailChecked(false), mCryptoKey(nullptr), mReferenceCount(1) { - + memset(mPublicKey, 0, crypto_sign_PUBLICKEYBYTES); } // load from db User::User(const char* email) @@ -187,6 +188,8 @@ User::User(const char* email) auto cm = ConnectionManager::getInstance(); auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + memset(mPublicKey, 0, crypto_sign_PUBLICKEYBYTES); + Poco::Nullable pubkey; Poco::Nullable privkey; @@ -207,6 +210,12 @@ User::User(const char* email) if (!pubkey.isNull()) { auto pubkey_value = pubkey.value(); + if (pubkey_value.size() == crypto_sign_PUBLICKEYBYTES) { + memcpy(mPublicKey, pubkey_value.content().data(), crypto_sign_PUBLICKEYBYTES); + } + else { + addError(new Error("User", "pubkey from db has other size as expected")); + } size_t hexSize = pubkey_value.size() * 2 + 1; char* hexString = (char*)malloc(hexSize); memset(hexString, 0, hexSize); @@ -234,6 +243,8 @@ User::User(int user_id) auto cm = ConnectionManager::getInstance(); auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + memset(mPublicKey, 0, crypto_sign_PUBLICKEYBYTES); + Poco::Nullable pubkey; Poco::Nullable privkey; @@ -254,6 +265,12 @@ User::User(int user_id) if (!pubkey.isNull()) { auto pubkey_value = pubkey.value(); + if (pubkey_value.size() == crypto_sign_PUBLICKEYBYTES) { + memcpy(mPublicKey, pubkey_value.content().data(), crypto_sign_PUBLICKEYBYTES); + } + else { + addError(new Error("User", "pubkey from db has other size as expected")); + } size_t hexSize = pubkey_value.size() * 2 + 1; char* hexString = (char*)malloc(hexSize); memset(hexString, 0, hexSize); @@ -283,6 +300,8 @@ User::User(const unsigned char* pubkey_array) auto cm = ConnectionManager::getInstance(); auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + memcpy(mPublicKey, pubkey_array, crypto_sign_PUBLICKEYBYTES); + Poco::Data::BLOB pubkey(pubkey_array, 32); Poco::Nullable privkey; @@ -769,15 +788,19 @@ MemoryBin* User::sign(const unsigned char* message, size_t messageSize) //auto signBinBuffer = (unsigned char*)malloc(crypto_sign_BYTES); auto signBinBuffer = mm->getFreeMemory(crypto_sign_BYTES); auto privKey = getPrivKey(); + size_t actualSignLength = 0; - crypto_sign_detached(*signBinBuffer, NULL, message, messageSize, *privKey); + if (crypto_sign_detached(*signBinBuffer, &actualSignLength, message, messageSize, *privKey)) { + addError(new Error("User::sign", "sign failed")); + mm->releaseMemory(privKey); + mm->releaseMemory(signBinBuffer); + return nullptr; + } - if (crypto_sign_verify_detached(*signBinBuffer, message, messageSize, *privKey) != 0) { + if (crypto_sign_verify_detached(*signBinBuffer, message, messageSize, mPublicKey) != 0) { // Incorrect signature! //printf("c[KeyBuffer::%s] sign verify failed\n", __FUNCTION__); - auto em = ErrorManager::getInstance(); - em->addError(new Error("User::sign", "sign verify failed")); - em->sendErrorsAsEmail(); + addError(new Error("User::sign", "sign verify failed")); mm->releaseMemory(privKey); mm->releaseMemory(signBinBuffer); return nullptr; diff --git a/src/cpp/model/User.h b/src/cpp/model/User.h index 94145f338..4eb8d58ab 100644 --- a/src/cpp/model/User.h +++ b/src/cpp/model/User.h @@ -80,7 +80,9 @@ public: inline const char* getLastName() const { return mLastName.data(); } inline int getDBId() const { return mDBId; } inline std::string getPublicKeyHex() { lock(); std::string pubkeyHex = mPublicHex; unlock(); return pubkeyHex; } + inline const unsigned char* getPublicKey() { return mPublicKey; } inline void setPublicKeyHex(const std::string& publicKeyHex) { lock(); mPublicHex = publicKeyHex; unlock(); } + inline void setPublicKey(const unsigned char* key) { lock(); memcpy(mPublicKey, key, crypto_sign_PUBLICKEYBYTES); unlock();} UserStates getUserState(); @@ -134,6 +136,7 @@ private: passwordHashed mPasswordHashed; std::string mPublicHex; + unsigned char mPublicKey[crypto_sign_PUBLICKEYBYTES]; MemoryBin* mPrivateKey; // TODO: insert created if necessary diff --git a/src/cpp/tasks/ProcessingTransaction.cpp b/src/cpp/tasks/ProcessingTransaction.cpp index 927c94d48..c54ce3d23 100644 --- a/src/cpp/tasks/ProcessingTransaction.cpp +++ b/src/cpp/tasks/ProcessingTransaction.cpp @@ -87,6 +87,25 @@ std::string ProcessingTransaction::getMemo() return ""; } +std::string ProcessingTransaction::getBodyBytes() +{ + lock(); + if (mTransactionBody.IsInitialized()) { + auto size = mTransactionBody.ByteSize(); + //auto bodyBytesSize = MemoryManager::getInstance()->getFreeMemory(mProtoCreation.ByteSizeLong()); + std::string resultString(size, 0); + if (!mTransactionBody.SerializeToString(&resultString)) { + addError(new Error("TransactionCreation::getBodyBytes", "error serializing string")); + unlock(); + return ""; + } + unlock(); + return resultString; + } + unlock(); + return ""; +} + TransactionCreation* ProcessingTransaction::getCreationTransaction() { return dynamic_cast(mTransactionSpecific); diff --git a/src/cpp/tasks/ProcessingTransaction.h b/src/cpp/tasks/ProcessingTransaction.h index 715edbb42..a7c584ff3 100644 --- a/src/cpp/tasks/ProcessingTransaction.h +++ b/src/cpp/tasks/ProcessingTransaction.h @@ -50,6 +50,7 @@ public: static HASH calculateHash(const std::string& proto_message_base64); inline HASH getHash() { mHashMutex.lock(); HASH hs = mHash; mHashMutex.unlock(); return hs; } + std::string ProcessingTransaction::getBodyBytes(); protected: TransactionType mType; diff --git a/src/cpp/tasks/SigningTransaction.cpp b/src/cpp/tasks/SigningTransaction.cpp index 0bf41a6c2..bf6eeb123 100644 --- a/src/cpp/tasks/SigningTransaction.cpp +++ b/src/cpp/tasks/SigningTransaction.cpp @@ -3,6 +3,18 @@ #include "../SingletonManager/ErrorManager.h" #include "../SingletonManager/MemoryManager.h" +#include "../proto/gradido/Transaction.pb.h" + +#include "sodium.h" + +#include "../ServerConfig.h" +#include "Poco/JSON/Object.h" +#include "Poco/JSON/Parser.h" +#include "Poco/StreamCopier.h" +#include "Poco/Net/HTTPSClientSession.h" +#include "Poco/Net/HTTPRequest.h" +#include "Poco/Net/HTTPResponse.h" + SigningTransaction::SigningTransaction(Poco::AutoPtr processingeTransaction, Poco::AutoPtr user) : mProcessingeTransaction(processingeTransaction), mUser(user) { @@ -15,33 +27,148 @@ SigningTransaction::~SigningTransaction() } int SigningTransaction::run() { - auto em = ErrorManager::getInstance(); auto mm = MemoryManager::getInstance(); - Error* transactionError = new Error("SigningTransaction start", mProcessingeTransaction->mProtoMessageBase64.data()); - + Error* transactionError = new Error("SigningTransaction", mProcessingeTransaction->mProtoMessageBase64.data()); + addError(transactionError); //= new Error("SigningTransaction start", mProcessingeTransaction->g) if (mUser.isNull() || !mUser->hasCryptoKey()) { - em->addError(transactionError); - em->addError(new Error("SigningTransaction", "user hasn't crypto key or is null")); - em->sendErrorsAsEmail(); + addError(new Error("SigningTransaction", "user hasn't crypto key or is null")); + sendErrorsAsEmail(); return -1; } //auto privKey = mUser->getPrivKey(); if (!mUser->hasPrivKey()) { - em->addError(transactionError); - em->getErrors(mUser); - em->addError(new Error("SigningTransaction", "couldn't get user priv key")); - em->sendErrorsAsEmail(); + getErrors(mUser); + addError(new Error("SigningTransaction", "couldn't get user priv key")); + sendErrorsAsEmail(); return -2; } + // get body bytes + model::messages::gradido::Transaction transaction; + auto bodyBytes = transaction.mutable_bodybytes(); + *bodyBytes = mProcessingeTransaction->getBodyBytes(); + if (*bodyBytes == "") { + getErrors(mProcessingeTransaction); + sendErrorsAsEmail(); + return -3; + } + // sign + auto sign = mUser->sign((const unsigned char*)bodyBytes->data(), bodyBytes->size()); + if (!sign) { + getErrors(mUser); + sendErrorsAsEmail(); + mm->releaseMemory(sign); + return -4; + } + auto pubkeyHex = mUser->getPublicKeyHex(); + + // pubkey for signature + /*auto pubkeyBin = mm->getFreeMemory(ed25519_pubkey_SIZE); + size_t realBin = 0; + if (sodium_hex2bin(*pubkeyBin, *pubkeyBin, pubkeyHex.data(), pubkeyHex.size(), nullptr, &realBin, nullptr)) { + addError(new Error("SigningTransaction", "error in sodium_hex2bin")); + sendErrorsAsEmail(); + mm->releaseMemory(pubkeyBin); + mm->releaseMemory(sign); + return -5; + } + */ + // add to message + auto sigMap = transaction.mutable_sigmap(); + auto sigPair = sigMap->add_sigpair(); - //auto sign = mUser->sign(mProcessingeTransaction->) - delete transactionError; - //delete privKey; - //mm->releaseMemory(privKey); + auto pubkeyBytes = sigPair->mutable_pubkey(); + auto pubkeyBin = mUser->getPublicKey(); + *pubkeyBytes = std::string((const char*)pubkeyBin, crypto_sign_PUBLICKEYBYTES); + + + auto sigBytes = sigPair->mutable_ed25519(); + *sigBytes = std::string((char*)*sign, sign->size()); + mm->releaseMemory(sign); + + + // finalize + std::string finalTransactionBin = transaction.SerializeAsString(); + if (finalTransactionBin == "") { + addError(new Error("SigningTransaction", "error serializing final transaction")); + sendErrorsAsEmail(); + return -6; + } + + // finale to base64 + auto finalBase64Size = sodium_base64_encoded_len(finalTransactionBin.size(), sodium_base64_VARIANT_ORIGINAL); + auto finalBase64Bin = mm->getFreeMemory(finalBase64Size); + if (!sodium_bin2base64(*finalBase64Bin, finalBase64Size, (const unsigned char*)finalTransactionBin.data(), finalTransactionBin.size(), sodium_base64_VARIANT_ORIGINAL)) { + addError(new Error("SigningTransaction", "error convert final transaction to base64")); + sendErrorsAsEmail(); + mm->releaseMemory(finalBase64Bin); + return -7; + } + + // create json request + + Poco::JSON::Object requestJson; + requestJson.set("method", "putTransaction"); + requestJson.set("transaction", std::string((char*)*finalBase64Bin, finalBase64Size)); + printf("base64 transaction: %s\n", (char*)*finalBase64Bin); + mm->releaseMemory(finalBase64Bin); + + + //std::string request = requestJson.stringify(); + + // send post request via https + // 443 = HTTPS Default + // TODO: adding port into ServerConfig + try { + Poco::Net::HTTPSClientSession httpsClientSession(ServerConfig::g_php_serverHost, 443); + Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/TransactionJsonRequestHandler"); + + request.setChunkedTransferEncoding(true); + std::ostream& requestStream = httpsClientSession.sendRequest(request); + requestJson.stringify(requestStream); + + Poco::Net::HTTPResponse response; + std::istream& request_stream = httpsClientSession.receiveResponse(response); + + // debugging answer + std::stringstream responseStringStream; + for (std::string line; std::getline(request_stream, line); ) { + responseStringStream << line << std::endl; + } + //printf("server response: %s\n", responseStringStream.str().data()); + FILE* f = fopen("response.html", "wt"); + std::string responseString = responseStringStream.str(); + fwrite(responseString.data(), 1, responseString.size(), f); + fclose(f); + + // extract parameter from request + Poco::JSON::Parser jsonParser; + Poco::Dynamic::Var parsedJson; + try { + parsedJson = jsonParser.parse(request_stream); + } + catch (Poco::Exception& ex) { + //printf("[JsonRequestHandler::handleRequest] Exception: %s\n", ex.displayText().data()); + addError(new ParamError("SigningTransaction", "error parsing request answer", ex.displayText().data())); + sendErrorsAsEmail(); + return -9; + } + + if (parsedJson.isStruct()) { + + } + int zahl = 1; + } + catch (Poco::Exception& e) { + addError(new ParamError("SigningTransaction", "connect error to php server", e.displayText().data())); + sendErrorsAsEmail(); + return -8; + } + + return 0; } \ No newline at end of file