diff --git a/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.cc b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.cc index 9b62d45ba..c1e00616d 100644 --- a/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.cc +++ b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.cc @@ -36,7 +36,8 @@ RsItem *RsDiscSerialiser::create_item( switch(static_cast(item_subtype)) { case RsGossipDiscoveryItemType::PGP_LIST: return new RsDiscPgpListItem(); - case RsGossipDiscoveryItemType::PGP_CERT: return new RsDiscPgpCertItem(); +// case RsGossipDiscoveryItemType::PGP_CERT: return new RsDiscPgpCertItem(); + case RsGossipDiscoveryItemType::PGP_CERT_BINARY: return new RsDiscPgpKeyItem(); case RsGossipDiscoveryItemType::CONTACT: return new RsDiscContactItem(); case RsGossipDiscoveryItemType::IDENTITY_LIST: return new RsDiscIdentityListItem(); @@ -78,6 +79,18 @@ void RsDiscPgpCertItem::serial_process(RsGenericSerializer::SerializeJob j,RsGen RsTypeSerializer::serial_process(j,ctx,TLV_TYPE_STR_PGPCERT,pgpCert,"pgpCert") ; } +void RsDiscPgpKeyItem::serial_process(RsGenericSerializer::SerializeJob j,RsGenericSerializer::SerializeContext& ctx) +{ + RsTypeSerializer::serial_process(j,ctx,pgpKeyId,"pgpKeyId") ; + RsTypeSerializer::serial_process(j,ctx,pgpKeyData,"pgpKeyData") ; +} + +void RsDiscPgpKeyItem::clear() +{ + pgpKeyId.clear(); + pgpKeyData.TlvClear(); +} + void RsDiscContactItem::clear() { pgpId.clear(); diff --git a/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.h b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.h index 70bf5920a..c65b9c3a4 100644 --- a/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.h +++ b/libretroshare/src/gossipdiscovery/gossipdiscoveryitems.h @@ -25,6 +25,7 @@ #include "serialiser/rsserial.h" #include "serialiser/rstlvidset.h" #include "serialiser/rstlvaddrs.h" +#include "serialiser/rstlvbinary.h" #include "rsitems/rsserviceids.h" #include "rsitems/rsitem.h" #include "rsitems/itempriorities.h" @@ -34,11 +35,12 @@ enum class RsGossipDiscoveryItemType : uint8_t { PGP_LIST = 0x1, - PGP_CERT = 0x2, + PGP_CERT = 0x2, // deprecated CONTACT = 0x5, IDENTITY_LIST = 0x6, INVITE = 0x7, - INVITE_REQUEST = 0x8 + INVITE_REQUEST = 0x8, + PGP_CERT_BINARY = 0x9, }; class RsDiscItem: public RsItem @@ -96,6 +98,20 @@ public: std::string pgpCert; }; +class RsDiscPgpKeyItem: public RsDiscItem +{ +public: + + RsDiscPgpKeyItem() : RsDiscItem(RsGossipDiscoveryItemType::PGP_CERT_BINARY) + { setPriorityLevel(QOS_PRIORITY_RS_DISC_PGP_CERT); } + + void clear() override; + void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx) override; + + RsPgpId pgpKeyId; // duplicate information for practical reasons + RsTlvBinaryData pgpKeyData; +}; + class RsDiscContactItem: public RsDiscItem { public: diff --git a/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc index 0accc64c7..e1b435df3 100644 --- a/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc +++ b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.cc @@ -32,6 +32,7 @@ /**** * #define P3DISC_DEBUG 1 ****/ +#define P3DISC_DEBUG 1 /*extern*/ std::shared_ptr rsGossipDiscovery(nullptr); @@ -261,11 +262,12 @@ int p3discovery2::handleIncoming() while(nullptr != (item = recvItem())) { RsDiscPgpListItem* pgplist = nullptr; - RsDiscPgpCertItem* pgpcert = nullptr; + RsDiscPgpCertItem* pgpcert = nullptr; // deprecated + RsDiscPgpKeyItem* pgpkey = nullptr; RsDiscContactItem* contact = nullptr; RsDiscIdentityListItem* gxsidlst = nullptr; - RsGossipDiscoveryInviteItem* invite = nullptr; - RsGossipDiscoveryInviteRequestItem* inviteReq = nullptr; +// RsGossipDiscoveryInviteItem* invite = nullptr; +// RsGossipDiscoveryInviteRequestItem* inviteReq = nullptr; ++nhandled; @@ -276,16 +278,18 @@ int p3discovery2::handleIncoming() { if (item->PeerId() == contact->sslId) recvOwnContactInfo(item->PeerId(), contact); - else processContactInfo(item->PeerId(), contact); + else + processContactInfo(item->PeerId(), contact); } - else if( (gxsidlst = dynamic_cast(item)) - != nullptr ) + else if( (gxsidlst = dynamic_cast(item)) != nullptr ) { recvIdentityList(item->PeerId(),gxsidlst->ownIdentityList); delete item; } - else if((pgpcert = dynamic_cast(item)) != nullptr) - recvPGPCertificate(item->PeerId(), pgpcert); +// else if((pgpcert = dynamic_cast(item)) != nullptr) +// recvPGPCertificate(item->PeerId(), pgpcert); + else if((pgpkey = dynamic_cast(item)) != nullptr) + recvPGPCertificate(item->PeerId(), pgpkey); else if((pgplist = dynamic_cast(item)) != nullptr) { if (pgplist->mode == RsGossipDiscoveryPgpListMode::FRIENDS) @@ -294,16 +298,15 @@ int p3discovery2::handleIncoming() recvPGPCertificateRequest(pgplist->PeerId(), pgplist); else delete item; } - else if( (invite = dynamic_cast(item)) - != nullptr ) - recvInvite(std::unique_ptr(invite)); - else if( (inviteReq = - dynamic_cast(item)) - != nullptr ) - { - sendInvite(inviteReq->mInviteId, item->PeerId()); - delete item; - } +// else if( (invite = dynamic_cast(item)) != nullptr ) +// recvInvite(std::unique_ptr(invite)); +// else if( (inviteReq = +// dynamic_cast(item)) +// != nullptr ) +// { +// sendInvite(inviteReq->mInviteId, item->PeerId()); +// delete item; +// } else { RsWarn() << __PRETTY_FUNCTION__ << " Received unknown item type! " @@ -365,6 +368,7 @@ void p3discovery2::sendOwnContactInfo(const SSLID &sslid) void p3discovery2::recvOwnContactInfo(const SSLID &fromId, const RsDiscContactItem *item) { + std::unique_ptr pitem(item); // ensures that item will be destroyed whichever door we leave through #ifdef P3DISC_DEBUG std::cerr << "p3discovery2::recvOwnContactInfo()"; @@ -377,6 +381,21 @@ void p3discovery2::recvOwnContactInfo(const SSLID &fromId, const RsDiscContactIt std::cerr << " -> location : " << item->location << std::endl; std::cerr << std::endl; #endif + // Check that the "own" ID sent corresponds to the one we think it should be. + // Some of these checks may look superfluous but it's better to risk to check twice than not check at all. + + // was obtained using a short invite. , and that the friend is marked as "ignore PGP validation" because it + RsPeerDetails det ; + if(!rsPeers->getPeerDetails(fromId,det)) + { + std::cerr << "(EE) Cannot obtain details from " << fromId << " who is supposed to be a friend! Dropping the info." << std::endl; + return; + } + if(det.gpg_id != item->pgpId) + { + std::cerr << "(EE) peer " << fromId << " sent own details with PGP key ID " << item->pgpId << " which does not match the known key id " << det.gpg_id << ". Dropping the info." << std::endl; + return; + } // Peer Own Info replaces the existing info, because the // peer is the primary source of his own IPs. @@ -389,6 +408,17 @@ void p3discovery2::recvOwnContactInfo(const SSLID &fromId, const RsDiscContactIt updatePeerAddresses(item); + // if the peer is not validated, we stop the exchange here + + if(det.skip_signature_validation) + { +#ifdef P3DISC_DEBUG + std::cerr << "p3discovery2::recvOwnContactInfo() missing PGP key " << item->pgpId << " from short invite friend " << fromId << ". Requesting it." << std::endl; +#endif + requestPGPCertificate(det.gpg_id, fromId); + return; + } + // This information will be sent out to online peers, at the receipt of their PGPList. // It is important that PGPList is received after the OwnContactItem. // This should happen, but is not enforced by the protocol. @@ -422,17 +452,6 @@ void p3discovery2::recvOwnContactInfo(const SSLID &fromId, const RsDiscContactIt #endif } } - else - { -#ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::recvOwnContactInfo()"; - std::cerr << " ERROR missing PGP Entry: " << pgpId; - std::cerr << std::endl; -#endif - } - - // cleanup. - delete item; } void p3discovery2::recvIdentityList(const RsPeerId& pid,const std::list& ids) @@ -690,7 +709,7 @@ void p3discovery2::processPGPList(const SSLID &fromId, const RsDiscPgpListItem * if (!AuthGPG::getAuthGPG()->isGPGId(*fit)) { #ifdef P3DISC_DEBUG - std::cerr << "p3discovery2::processPGPList() requesting PgpId: " << *fit; + std::cerr << "p3discovery2::processPGPList() requesting certificate for PgpId: " << *fit; std::cerr << " from SslId: " << fromId; std::cerr << std::endl; #endif @@ -1023,30 +1042,97 @@ void p3discovery2::recvPGPCertificateRequest( } -void p3discovery2::sendPGPCertificate(const PGPID &aboutId, const SSLID &toId) +void p3discovery2::sendPGPCertificate(const RsPgpId &aboutId, const RsPeerId &toId) { - RsDiscPgpCertItem* item = new RsDiscPgpCertItem(); - item->pgpId = aboutId; - item->PeerId(toId); + //RsDiscPgpCertItem* item = new RsDiscPgpCertItem(); + //item->pgpId = aboutId; - Dbg4() << __PRETTY_FUNCTION__ << " queuing for Cert generation: " - << std::endl << *item << std::endl; + //Dbg4() << __PRETTY_FUNCTION__ << " queuing for Cert generation: " << std::endl << *item << std::endl; - { - RS_STACK_MUTEX(mDiscMtx); - mPendingDiscPgpCertOutList.push_back(item); - } + RsDiscPgpKeyItem *pgp_key_item = new RsDiscPgpKeyItem; + + pgp_key_item->PeerId(toId); + pgp_key_item->pgpKeyId = aboutId; + unsigned char *bin_data; + size_t bin_len; + + if(!AuthGPG::getAuthGPG()->exportPublicKey(aboutId,bin_data,bin_len,false,true)) + { + std::cerr << "(EE) cannot export public key " << aboutId << " requested by peer " << toId << std::endl; + return ; + } + + pgp_key_item->pgpKeyData.bin_data = bin_data; + pgp_key_item->pgpKeyData.bin_len = bin_len; + + sendItem(pgp_key_item); + + // (cyril) we shouldn't need to use a queue for that! There's no cost in getting a PGP cert from AuthGPG. + // { + // RS_STACK_MUTEX(mDiscMtx); + // mPendingDiscPgpCertOutList.push_back(item); + // } } -void p3discovery2::recvPGPCertificate( - const SSLID& /*fromId*/, RsDiscPgpCertItem* item ) +void p3discovery2::recvPGPCertificate(const RsPeerId& fromId, RsDiscPgpKeyItem* item ) { + // 1 - check that the cert structure is valid. + + RsPgpId cert_pgp_id; + std::string cert_name; + std::list cert_signers; + + if(!AuthGPG::getAuthGPG()->getGPGDetailsFromBinaryBlock( (unsigned char*)item->pgpKeyData.bin_data,item->pgpKeyData.bin_len, cert_pgp_id, cert_name, cert_signers )) + { + std::cerr << "(EE) cannot parse own PGP key sent by " << fromId << std::endl; + return; + } + + if(cert_pgp_id != item->pgpKeyId) + { + std::cerr << "(EE) received a PGP key from " << fromId << " which ID (" << cert_pgp_id << ") is different from the one anounced in the packet (" << item->pgpKeyId << ")!" << std::endl; + return; + } + + // 2 - check if the peer who is sending us a cert is already validated + + RsPeerDetails det; + if(!rsPeers->getPeerDetails(fromId,det)) + { + std::cerr << "(EE) cannot get peer details from friend " << fromId << ": this is very wrong!"<< std::endl; + return; + } + + // We treat own pgp keys right away when they are sent by a friend for which we dont have it. This way we can keep the skip_pgg_signature_validation consistent + + if(det.skip_signature_validation) + { #ifdef P3DISC_DEBUG - std::cerr << __PRETTY_FUNCTION__ << " queuing for Cert loading" << std::endl; + std::cerr << __PRETTY_FUNCTION__ << " Received own full certificate from short-invite friend " << fromId << std::endl; #endif - /* push this back to be processed by pgp when possible */ - RS_STACK_MUTEX(mDiscMtx); - mPendingDiscPgpCertInList.push_back(item); + // do some extra checks. Dont remove them. They cost nothing as compared to what they could avoid. + + if(item->pgpKeyId != det.gpg_id) + { + std::cerr << "(EE) received a PGP key with ID " << item->pgpKeyId << " from non validated peer " << fromId << ", which should only be allowed to send his own key " << det.gpg_id << std::endl; + return; + } + } + RsPgpId tmp_pgp_id; + std::string error_string; + +#ifdef P3DISC_DEBUG + std::cerr << __PRETTY_FUNCTION__ << "Received PGP key " << cert_pgp_id << " from from friend " << fromId << ". Adding to keyring." << std::endl; +#endif + // now that will add the key *and* set the skip_signature_validation flag at once + rsPeers->loadPgpKeyFromBinaryData((unsigned char*)item->pgpKeyData.bin_data,item->pgpKeyData.bin_len, tmp_pgp_id,error_string); // no error should occur at this point because we called loadDetailsFromStringCert() already + delete item; + + // Make sure we allow connections after the key is added. This is not the case otherwise. We only do that if the peer is non validated peer, since + // otherwise the connection should already be accepted. This only happens when the short invite peer sends its own PGP key. + + if(det.skip_signature_validation) + AuthGPG::getAuthGPG()->AllowConnection(det.gpg_id,true); } /************* from pqiServiceMonitor *******************/ @@ -1139,7 +1225,7 @@ bool p3discovery2::getDiscFriends(const RsPeerId& id, std::list &proxy bool p3discovery2::getWaitingDiscCount(size_t &sendCount, size_t &recvCount) { RS_STACK_MUTEX(mDiscMtx); - sendCount = mPendingDiscPgpCertOutList.size(); + //sendCount = mPendingDiscPgpCertOutList.size(); recvCount = mPendingDiscPgpCertInList.size(); return true; @@ -1256,20 +1342,18 @@ void p3discovery2::rsEventsHandler(const RsEvent& event) switch(event.mType) { - case RsEventType::PEER_STATE_CHANGED: - { - const RsPeerId& sslId = - static_cast(event).mSslId; - if( rsPeers && rsPeers->isSslOnlyFriend(sslId) && - mServiceCtrl->isPeerConnected( - getServiceInfo().mServiceType, sslId ) ) - { - if(!requestInvite(sslId, sslId)) - RsErr() << __PRETTY_FUNCTION__ << " requestInvite to peer " - << sslId << " failed" << std::endl; - } - break; - } +// case RsEventType::PEER_STATE_CHANGED: +// { +// const RsPeerId& sslId = static_cast(event).mSslId; +// +// if( rsPeers && rsPeers->isSslOnlyFriend(sslId) && mServiceCtrl->isPeerConnected( getServiceInfo().mServiceType, sslId ) ) +// { +// if(!requestPGPCertificate(sslId, sslId)) +// RsErr() << __PRETTY_FUNCTION__ << " requestInvite to peer " +// << sslId << " failed" << std::endl; +// } +// break; +// } default: break; } } @@ -1292,17 +1376,17 @@ AuthGPGOperation *p3discovery2::getGPGOperation() } } - { - RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ - - /* process disc reply in list */ - if (!mPendingDiscPgpCertOutList.empty()) { - RsDiscPgpCertItem *item = mPendingDiscPgpCertOutList.front(); - mPendingDiscPgpCertOutList.pop_front(); - - return new AuthGPGOperationLoadOrSave(false, item->pgpId, "", item); - } - } +// { +// RsStackMutex stack(mDiscMtx); /********** STACK LOCKED MTX ******/ +// +// /* process disc reply in list */ +// if (!mPendingDiscPgpCertOutList.empty()) { +// RsDiscPgpCertItem *item = mPendingDiscPgpCertOutList.front(); +// mPendingDiscPgpCertOutList.pop_front(); +// +// return new AuthGPGOperationLoadOrSave(false, item->pgpId, "", item); +// } +// } return NULL; } diff --git a/libretroshare/src/gossipdiscovery/p3gossipdiscovery.h b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.h index 6c6864fb9..eaf148bb5 100644 --- a/libretroshare/src/gossipdiscovery/p3gossipdiscovery.h +++ b/libretroshare/src/gossipdiscovery/p3gossipdiscovery.h @@ -130,8 +130,9 @@ private: void recvPGPCertificateRequest( const RsPeerId& fromId, const RsDiscPgpListItem* item ); - void sendPGPCertificate(const PGPID &aboutId, const SSLID &toId); - void recvPGPCertificate(const SSLID &fromId, RsDiscPgpCertItem *item); + void sendPGPCertificate(const RsPgpId &aboutId, const RsPeerId &toId); + void recvPGPCertificate(const SSLID &fromId, RsDiscPgpCertItem *item); // deprecated + void recvPGPCertificate(const SSLID &fromId, RsDiscPgpKeyItem *item); void recvIdentityList(const RsPeerId& pid,const std::list& ids); bool setPeerVersion(const SSLID &peerId, const std::string &version); @@ -160,7 +161,7 @@ private: std::map mLocationMap; std::list mPendingDiscPgpCertInList; - std::list mPendingDiscPgpCertOutList; + //std::list mPendingDiscPgpCertOutList; protected: RS_SET_CONTEXT_DEBUG_LEVEL(1) diff --git a/libretroshare/src/pgp/pgphandler.cc b/libretroshare/src/pgp/pgphandler.cc index 46e8b166c..48915aa85 100644 --- a/libretroshare/src/pgp/pgphandler.cc +++ b/libretroshare/src/pgp/pgphandler.cc @@ -1037,7 +1037,17 @@ void PGPHandler::addNewKeyToOPSKeyring(ops_keyring_t *kr,const ops_keydata_t& ke kr->nkeys++ ; } +bool PGPHandler::LoadCertificateFromBinaryData(const unsigned char *data,uint32_t data_len,RsPgpId& id,std::string& error_string) +{ + return LoadCertificate(data,data_len,ops_false,id,error_string); +} + bool PGPHandler::LoadCertificateFromString(const std::string& pgp_cert,RsPgpId& id,std::string& error_string) +{ + return LoadCertificate((unsigned char*)(pgp_cert.c_str()),pgp_cert.length(),ops_true,id,error_string); +} + +bool PGPHandler::LoadCertificate(const unsigned char *data,uint32_t data_len,bool armoured,RsPgpId& id,std::string& error_string) { RsStackMutex mtx(pgphandlerMtx) ; // lock access to PGP memory structures. #ifdef DEBUG_PGPHANDLER @@ -1046,9 +1056,9 @@ bool PGPHandler::LoadCertificateFromString(const std::string& pgp_cert,RsPgpId& ops_keyring_t *tmp_keyring = allocateOPSKeyring(); ops_memory_t *mem = ops_memory_new() ; - ops_memory_add(mem,(unsigned char *)pgp_cert.c_str(),pgp_cert.length()) ; + ops_memory_add(mem,data,data_len) ; - if(!ops_keyring_read_from_mem(tmp_keyring,ops_true,mem)) + if(!ops_keyring_read_from_mem(tmp_keyring,armoured,mem)) { ops_keyring_free(tmp_keyring) ; free(tmp_keyring) ; diff --git a/libretroshare/src/pgp/pgphandler.h b/libretroshare/src/pgp/pgphandler.h index e6c16764e..fee240e6a 100644 --- a/libretroshare/src/pgp/pgphandler.h +++ b/libretroshare/src/pgp/pgphandler.h @@ -104,6 +104,7 @@ class PGPHandler bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId& pgpId, const int keynumbits, std::string& errString) ; bool LoadCertificateFromString(const std::string& pem, RsPgpId& gpg_id, std::string& error_string); + bool LoadCertificateFromBinaryData(const unsigned char *bin_data,uint32_t bin_data_len, RsPgpId& gpg_id, std::string& error_string); std::string SaveCertificateToString(const RsPgpId& id,bool include_signatures) const ; bool exportPublicKey(const RsPgpId& id,unsigned char *& mem,size_t& mem_size,bool armoured,bool include_signatures) const ; @@ -172,6 +173,7 @@ class PGPHandler bool syncDatabase() ; private: + bool LoadCertificate(const unsigned char *bin_data,uint32_t bin_data_len, bool armoured, RsPgpId& gpg_id, std::string& error_string); void initCertificateInfo(PGPCertificateInfo& cert,const ops_keydata_t *keydata,uint32_t i) ; // Returns true if the signatures have been updated diff --git a/libretroshare/src/pqi/authgpg.cc b/libretroshare/src/pqi/authgpg.cc index bf485a2ad..076cb66b5 100644 --- a/libretroshare/src/pqi/authgpg.cc +++ b/libretroshare/src/pqi/authgpg.cc @@ -534,6 +534,19 @@ bool AuthGPG::getGPGSignedList(std::list &ids) return PGPHandler::SaveCertificateToString(id,include_signatures) ; } +/* import to GnuPG and other Certificates */ +bool AuthGPG::LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string) +{ + RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/ + + if(PGPHandler::LoadCertificateFromBinaryData(data,data_len,gpg_id,error_string)) + { + updateOwnSignatureFlag(gpg_id,mOwnGpgId) ; + return true ; + } + + return false ; +} /* import to GnuPG and other Certificates */ bool AuthGPG::LoadCertificateFromString(const std::string &str, RsPgpId& gpg_id,std::string& error_string) diff --git a/libretroshare/src/pqi/authgpg.h b/libretroshare/src/pqi/authgpg.h index 11b7203dd..871830445 100644 --- a/libretroshare/src/pqi/authgpg.h +++ b/libretroshare/src/pqi/authgpg.h @@ -172,6 +172,7 @@ public: * ****/ virtual bool LoadCertificateFromString(const std::string &pem, RsPgpId& gpg_id,std::string& error_string); + virtual bool LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string); virtual std::string SaveCertificateToString(const RsPgpId &id,bool include_signatures) ; // Cached certificates. diff --git a/libretroshare/src/pqi/p3peermgr.cc b/libretroshare/src/pqi/p3peermgr.cc index 90ca5cecd..57faff741 100644 --- a/libretroshare/src/pqi/p3peermgr.cc +++ b/libretroshare/src/pqi/p3peermgr.cc @@ -886,8 +886,7 @@ bool p3PeerMgrIMPL::haveOnceConnected() RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ /* check for existing */ - std::map::iterator it; - for(it = mFriendList.begin(); it != mFriendList.end(); ++it) + for(auto it = mFriendList.begin(); it != mFriendList.end(); ++it) { if (it->second.lastcontact > 0) { @@ -910,6 +909,28 @@ bool p3PeerMgrIMPL::haveOnceConnected() } +bool p3PeerMgrIMPL::notifyPgpKeyReceived(const RsPgpId& pgp_id) +{ + RsStackMutex stack(mPeerMtx); /****** STACK LOCK MUTEX *******/ + + bool changed = false; + + for(auto it(mFriendList.begin());it!=mFriendList.end();++it) + { + if(it->second.gpg_id == pgp_id) + { + std::cerr << "(WW) notification that full key " << pgp_id << " is available. Reseting short invite flag for peer " << it->first << std::endl; + it->second.skip_pgp_signature_validation = false; + + changed = true; + } + } + + if(changed) + IndicateConfigChanged(); + + return true; +} /*******************************************************************/ /*******************************************************************/ @@ -946,16 +967,9 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg std::map::iterator it; if (mFriendList.end() != (it=mFriendList.find(id))) { -#ifdef PEER_DEBUG - std::cerr << "p3PeerMgrIMPL::addFriend() Already Exists" << std::endl; -#endif - if(it->second.gpg_id.isNull()) // already exists as a SSL-only friend - { - it->second.gpg_id = input_gpg_id; - it->second.skip_pgp_signature_validation = false; - return true; - } - else if(it->second.gpg_id != input_gpg_id)// already exists as a friend with a different PGP id!! + // The friend may already be here, including with a short invite (meaning the PGP key is unknown). + + if(it->second.gpg_id != input_gpg_id)// already exists as a friend with a different PGP id!! { RsErr() << "Trying to add SSL id (" << id << ") that is already a friend with existing PGP key (" << it->second.gpg_id << ") but using a different PGP key (" << input_gpg_id << "). This is a bug!" << std::endl; return false; @@ -975,6 +989,7 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg return false; } + // after that, we know that we have the key, because AuthGPG wouldn't answer yes for a key it doesn't know. /* check if it is in others */ if (mOthersList.end() != (it = mOthersList.find(id))) diff --git a/libretroshare/src/pqi/p3peermgr.h b/libretroshare/src/pqi/p3peermgr.h index 131cec418..f8cfa64ed 100644 --- a/libretroshare/src/pqi/p3peermgr.h +++ b/libretroshare/src/pqi/p3peermgr.h @@ -80,7 +80,6 @@ class peerState // have short invites. However, because this represent a significant security risk, we perform multiple consistency checks // whenever we use this flag, in particular: // flat is true <==> friend SSL cert is in the friend list, but PGP id is not in the friend list - // PGP id is undefined and therefore set to null bool skip_pgp_signature_validation; @@ -140,6 +139,9 @@ public: const RsPgpId& pgpId, const RsPeerDetails& details = RsPeerDetails() ) = 0; + // Calling this removed the skip_pgp_signature_validation flag on all peers which PGP key is the one supplied. + virtual bool notifyPgpKeyReceived(const RsPgpId& pgp_key_id) = 0; + virtual bool removeFriend(const RsPeerId &ssl_id, bool removePgpId) = 0; virtual bool isFriend(const RsPeerId& ssl_id) = 0; virtual bool isSslOnlyFriend(const RsPeerId &ssl_id)=0; @@ -259,6 +261,8 @@ public: bool addSslOnlyFriend(const RsPeerId& sslId, const RsPgpId &pgp_id, const RsPeerDetails& details = RsPeerDetails() ) override; + virtual bool notifyPgpKeyReceived(const RsPgpId& pgp_key_id) override; + virtual bool removeFriend(const RsPeerId &ssl_id, bool removePgpId); virtual bool removeFriend(const RsPgpId &pgp_id); diff --git a/libretroshare/src/retroshare/rspeers.h b/libretroshare/src/retroshare/rspeers.h index cb9f1ec27..383430541 100644 --- a/libretroshare/src/retroshare/rspeers.h +++ b/libretroshare/src/retroshare/rspeers.h @@ -74,7 +74,7 @@ const uint32_t RS_HIDDEN_TYPE_I2P = 0x0004; /* mask to match all valid hidden types */ const uint32_t RS_HIDDEN_TYPE_MASK = RS_HIDDEN_TYPE_I2P | RS_HIDDEN_TYPE_TOR; -/* Visibility */ +/* Visibility parameter for discovery */ const uint32_t RS_VS_DISC_OFF = 0x0000; const uint32_t RS_VS_DISC_MINIMAL = 0x0001; const uint32_t RS_VS_DISC_FULL = 0x0002; @@ -734,6 +734,11 @@ public: const std::string& cert, RsPeerDetails& certDetails, uint32_t& errorCode ) = 0; + virtual bool loadPgpKeyFromBinaryData( const unsigned char *bin_key_data, + uint32_t bin_key_len, + RsPgpId& gpg_id, + std::string& error_string )=0; + // Certificate utils virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert,bool& is_short_format,uint32_t& error_code) = 0; virtual bool saveCertificateToFile(const RsPeerId& id, const std::string &fname) = 0; diff --git a/libretroshare/src/rsserver/p3peers.cc b/libretroshare/src/rsserver/p3peers.cc index c320c0260..393ae816e 100644 --- a/libretroshare/src/rsserver/p3peers.cc +++ b/libretroshare/src/rsserver/p3peers.cc @@ -1526,12 +1526,25 @@ bool p3Peers::loadCertificateFromString( } RsPgpId gpgid; - bool res = AuthGPG::getAuthGPG()->LoadCertificateFromString( - crt->armouredPGPKey(), gpgid, error_string ); + bool res = AuthGPG::getAuthGPG()->LoadCertificateFromString( crt->armouredPGPKey(), gpgid, error_string ); gpg_id = gpgid; ssl_id = crt->sslid(); + // now get all friends who declare this key ID to be the one needed to check connections, and clear their "skip_pgp_signature_validation" flag + + if(res) + mPeerMgr->notifyPgpKeyReceived(gpgid); + + return res; +} +bool p3Peers::loadPgpKeyFromBinaryData( const unsigned char *bin_key_data,uint32_t bin_key_len, RsPgpId& gpg_id, std::string& error_string ) +{ + bool res = AuthGPG::getAuthGPG()->LoadPGPKeyFromBinaryData( bin_key_data,bin_key_len, gpg_id, error_string ); + + if(res) + mPeerMgr->notifyPgpKeyReceived(gpg_id); + return res; } diff --git a/libretroshare/src/rsserver/p3peers.h b/libretroshare/src/rsserver/p3peers.h index b5b8d09d5..ad6f2d056 100644 --- a/libretroshare/src/rsserver/p3peers.h +++ b/libretroshare/src/rsserver/p3peers.h @@ -157,6 +157,7 @@ public: virtual bool hasExportMinimal(); virtual bool loadCertificateFromString(const std::string& cert, RsPeerId& ssl_id,RsPgpId& pgp_id, std::string& error_string); + virtual bool loadPgpKeyFromBinaryData( const unsigned char *bin_key_data,uint32_t bin_key_len, RsPgpId& gpg_id, std::string& error_string ); virtual bool loadDetailsFromStringCert(const std::string &cert, RsPeerDetails &pd, uint32_t& error_code); virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert, bool &is_short_format, uint32_t& error_code) override;