diff --git a/TODO b/TODO index bd6640a7..90a2d733 100644 --- a/TODO +++ b/TODO @@ -66,10 +66,6 @@ of his own torrent) - Estimate number of online followers by quering the "tracker" resource (implement a value within this resource to report the number of torrent peers) -- Properly implement spam signing and checking to prevent it from been used to impersonate users. -"nobody" might be an exception so default client could still send unauthenticated/anonymous spam -messages. - - Define and enforce html directory to serve from. Do installation scripts. - Don't accept dht "post"+k if k violates the validatePostNumberForUser() rule. diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index f9715a88..905e980a 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -124,64 +124,6 @@ bool AppInit(int argc, char* argv[]) } -static const string strSecret1C ("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw"); - -static bool TestCreateSpamMsgTx() -{ - CTransaction txNew; - - txNew.message = CScript() << strSpamMessage; - - CBitcoinSecret bsecret1; - bsecret1.SetString (strSecret1C); - - CKey key; - key.MakeNewKey(true); - //CKey key = bsecret1.GetKey(); - CPubKey pubkey( key.GetPubKey() ); - - printf("key valid: %d compressed: %d\n", key.IsValid(), key.IsCompressed()); - printf("pubkey: %s\n", EncodeBase64(&pubkey[0], pubkey.size()).c_str() ); - - // compute message hash and sign it - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - ss << txNew.message; - uint256 hashMsg = ss.GetHash(); - - // vchSig is sig(hash(message)) - vector vchSig; - if (!key.Sign(hashMsg, vchSig)) { - printf("CreateNewBlock: Failed to sign SpamMessage\n"); - return false; - } - - /* - vector vchSigCompact; - if (!key.SignCompact(hashMsg, vchSigCompact)) { - printf("CreateNewBlock: Failed to sign SpamMessage2\n"); - return false; - } - printf("sign size: %zu signCompact size: %zu\n", vchSig.size(), vchSigCompact.size()); - printf("signCompact: %s\n", EncodeBase64(&vchSigCompact[0], vchSigCompact.size()).c_str()); - */ - - printf("CreateSpamMsgTx: msg = %s user = %s hash = %s signedhash = %s\n", txNew.message.ToString().c_str(), strSpamUser.c_str(), - hashMsg.ToString().c_str(), EncodeBase64(&vchSig[0], vchSig.size()).c_str() ); - - // add username and signature - txNew.userName = CScript() << strSpamUser; - txNew.userName += CScript() << vchSig; - txNew.pubKey.clear(); // pubKey will be updated to include extranonce - txNew.nNonce = 0; // no update needed for spamMessage's nonce. - - std::vector< std::vector > vData; - txNew.userName.ExtractPushData(vData); - - printf("Verify: %d\n", pubkey.Verify(hashMsg,vData[1])); - - exit(1); -} - extern void GenesisMiner(); extern void noui_connect(); int main(int argc, char* argv[]) @@ -190,7 +132,6 @@ int main(int argc, char* argv[]) fHaveGUI = false; //GenesisMiner(); - //TestCreateSpamMsgTx(); // Connect bitcoind signal handlers noui_connect(); diff --git a/src/main.cpp b/src/main.cpp index 965353eb..1cc24acd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -425,10 +425,45 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) { // Basic checks that don't depend on any context if (tx.IsSpamMessage()) { - if (tx.message.size() > MAX_SPAM_MSG_SIZE) - return state.DoS(100, error("CheckTransaction() : spam message too big")); - // [MF] TODO: check message signature - // [MF] Problem: registration of this user may be in the block itself, better check later. + string spamMsg = tx.message.ExtractPushDataString(0); + if (!spamMsg.size()) + return state.DoS(100, error("CheckTransaction() : invalid or empty spam message")); + if (spamMsg.size() > MAX_SPAM_MSG_SIZE) + return state.DoS(100, error("CheckTransaction() : spam message too big")); + + string spamUser = tx.userName.ExtractPushDataString(0); + if( spamUser != "nobody" ) { + string strSign = tx.userName.ExtractPushDataString(1); + if (!strSign.size()) + return state.DoS(100, error("CheckTransaction() : spam signature missing")); + vector vchSig((const unsigned char*)strSign.data(), + (const unsigned char*)strSign.data() + strSign.size()); + + CPubKey pubkey; + CTransaction txPubKey; + uint256 hashBlock; + uint256 userhash = SerializeHash(spamUser); + if( !GetTransaction(userhash, txPubKey, hashBlock) ) + return state.DoS(100, error("CheckTransaction() : spam signed by unknown user")); + + std::vector< std::vector > vData; + if( !txPubKey.pubKey.ExtractPushData(vData) || vData.size() < 1 ) + return state.DoS(100, error("CheckTransaction() : spam signed with broken pubkey")); + + pubkey = CPubKey(vData[0]); + + // compute message hash for signature checking + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + ss << strMessageMagic; + ss << tx.message; + + CPubKey pubkeyRec; + if (!pubkeyRec.RecoverCompact(ss.GetHash(), vchSig)) + return state.DoS(100, error("CheckTransaction() : RecoverCompact failed for spammsg")); + + if (pubkeyRec.GetID() != pubkey.GetID()) + return state.DoS(100, error("CheckTransaction() : spam signature verification failed")); + } } else { if (tx.userName.empty()) return state.DoS(10, error("CheckTransaction() : username empty")); @@ -1713,11 +1748,10 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl if( pblock->vtx[0].IsSpamMessage() ) { string msg = pblock->vtx[0].message.ExtractPushDataString(0); string user = pblock->vtx[0].userName.ExtractPushDataString(0); - // [MF] FIXME: validate user properly - if( msg.length() <= 140 ) { - printf("ProcessBlock: msg='%s' user='%s'\n", msg.c_str(), user.c_str()); - receivedSpamMessage(msg, user); - } + + // SpamMessage was already validated in CheckBlock => CheckTransation + printf("ProcessBlock: msg='%s' user='%s'\n", msg.c_str(), user.c_str()); + receivedSpamMessage(msg, user); } return true; } @@ -3492,7 +3526,7 @@ static bool CreateSpamMsgTx(CTransaction &txNew, std::vector &sal std::string strUsername = strSpamUser; CKeyID keyID; - if( !pwalletMain->GetKeyIdFromUsername(strSpamUser, keyID) ) { + if( strSpamUser != "nobody" && !pwalletMain->GetKeyIdFromUsername(strSpamUser, keyID) ) { if( pwalletMain->vchDefaultKey.IsValid() ) { keyID = pwalletMain->vchDefaultKey.GetID(); strUsername = pwalletMain->mapKeyMetadata[keyID].username; @@ -3534,6 +3568,10 @@ static bool CreateSpamMsgTx(CTransaction &txNew, std::vector &sal txNew.pubKey.clear(); // pubKey will be updated to include extranonce txNew.nNonce = 0; // no update needed for spamMessage's nonce. + CValidationState state; + bool ret = CheckTransaction(txNew, state); + printf("CheckTransaction returned %d\n", ret ); + return true; }