diff --git a/libretroshare/src/crypto/hashstream.cc b/libretroshare/src/crypto/hashstream.cc index 1d3c46b75..e1c39a60c 100644 --- a/libretroshare/src/crypto/hashstream.cc +++ b/libretroshare/src/crypto/hashstream.cc @@ -54,7 +54,12 @@ namespace librs return Sha1CheckSum(h); } - + template<> + HashStream& operator<<(HashStream& u,const std::pair& p) + { + EVP_DigestUpdate(u.mdctx,p.first,p.second) ; + return u; + } template<> HashStream& operator<<(HashStream& u,const std::string& s) { diff --git a/libretroshare/src/pgp/pgpkeyutil.cc b/libretroshare/src/pgp/pgpkeyutil.cc index 76b332edf..105556ebb 100644 --- a/libretroshare/src/pgp/pgpkeyutil.cc +++ b/libretroshare/src/pgp/pgpkeyutil.cc @@ -21,6 +21,7 @@ *******************************************************************************/ #include #include +#include #include "pgpkeyutil.h" #include @@ -181,6 +182,59 @@ uint32_t PGPKeyManagement::compute24bitsCRC(unsigned char *octets, size_t len) return crc & 0xFFFFFFL; } +bool PGPKeyManagement::parsePGPPublicKey(const unsigned char *keydata, size_t keylen, PGPKeyInfo& info) +{ +#ifdef DEBUG_PGPUTIL + std::cerr << "Total size: " << keylen << std::endl; +#endif + unsigned char *data = (unsigned char*)keydata; + + uint8_t packet_tag; + uint32_t packet_length ; + + PGPKeyParser::read_packetHeader(data,packet_tag,packet_length) ; + +#ifdef DEBUG_PGPUTIL + std::cerr << "Packet tag : " << (int)packet_tag << ", length=" << packet_length << std::endl; +#endif + if(packet_tag != PGPKeyParser::PGP_PACKET_TAG_PUBLIC_KEY) + { + std::cerr << "(EE) Parsing error in PGP public key. Expected a public key tag (6). Found " << (int)packet_tag << " instead." << std::endl; + return false; + } + librs::crypto::HashStream H(librs::crypto::HashStream::SHA1); + + H << (uint8_t)0x99; // RFC_4880 + + std::cerr << "Packet length = " << packet_length << std::endl; + + H << (uint8_t)(packet_length >> 8); + H << (uint8_t)(packet_length); + H << std::make_pair(data,packet_length) ; + + auto hash = H.hash(); + + memcpy(info.fingerprint, hash.toByteArray(),hash.SIZE_IN_BYTES); + + data += packet_length; + + // Read user ID. + + PGPKeyParser::read_packetHeader(data,packet_tag,packet_length) ; + + if(packet_tag != PGPKeyParser::PGP_PACKET_TAG_USER_ID) + { + std::cerr << "(EE) Parsing error in PGP public key. Expected a user ID key tag (13). Found " << (int)packet_tag << " instead." << std::endl; + return false; + } + + info.user_id.clear(); + + for(uint32_t i=0;iPacketSubType()) { - case RS_PKT_SUBTYPE_FS_CLIENT_REMOVE: handleClientRemove(dynamic_cast(fsitem)); - break; case RS_PKT_SUBTYPE_FS_CLIENT_PUBLISH: handleClientPublish(dynamic_cast(fsitem)); break; + case RS_PKT_SUBTYPE_FS_CLIENT_REMOVE: handleClientRemove(dynamic_cast(fsitem)); + break; default: ; } delete item; @@ -169,23 +170,27 @@ std::map FriendServer::computeListOfFriendInvites(uint32_t nb std::map::iterator FriendServer::handleIncomingClientData(const std::string& pgp_public_key_b64,const std::string& short_invite_b64) { + // 1 - Check that the incoming data is sound. + RsDbg() << " Checking item data..."; std::string error_string; - RsPgpId pgp_id ; std::vector key_binary_data ; - // key_binary_data = Radix64::decode(pgp_public_key_b64); - if(RsBase64::decode(pgp_public_key_b64,key_binary_data)) throw std::runtime_error(" Cannot decode client pgp public key: \"" + pgp_public_key_b64 + "\". Wrong format??"); - RsDbg() << " Public key radix is fine." ; + RsDbg() << " Parsing public key:" ; - if(!mPgpHandler->LoadCertificateFromBinaryData(key_binary_data.data(),key_binary_data.size(), pgp_id, error_string)) - throw std::runtime_error("Cannot load client's pgp public key into keyring: " + error_string) ; + PGPKeyInfo received_key_info; - RsDbg() << " Public key added to keyring."; + if(!PGPKeyManagement::parsePGPPublicKey(key_binary_data.data(),key_binary_data.size(),received_key_info)) + throw std::runtime_error("Cannot parse received pgp public key.") ; + + RsDbg() << " Issuer : \"" << received_key_info.user_id << "\"" ; + RsDbg() << " Fingerprint: " << RsPgpFingerprint::fromBufferUnsafe(received_key_info.fingerprint) ; + + RsDbg() << " Parsing short invite:" ; RsPeerDetails shortInviteDetails; uint32_t errorCode = 0; @@ -193,19 +198,30 @@ std::map::iterator FriendServer::handleIncomingClientData(con if(short_invite_b64.empty() || !RsCertificate::decodeRadix64ShortInvite(short_invite_b64, shortInviteDetails,errorCode )) throw std::runtime_error("Could not parse short certificate. Error = " + RsUtil::NumberToString(errorCode)); - RsDbg() << " Short invite is fine. PGP fingerprint: " << shortInviteDetails.fpr ; + RsDbg() << " Fingerprint: " << shortInviteDetails.fpr ; + RsDbg() << " Peer ID: " << shortInviteDetails.id ; + if(shortInviteDetails.fpr != RsPgpFingerprint::fromBufferUnsafe(received_key_info.fingerprint)) + throw std::runtime_error("Fingerpring from short invite and public key are different! Very unexpected! Message will be ignored."); + + // 3 - if the key is not already here, add it to keyring. + + { RsPgpFingerprint fpr_test; - if(!mPgpHandler->getKeyFingerprint(pgp_id,fpr_test)) - throw std::runtime_error("Cannot get fingerprint from keyring for client public key. Something's really wrong.") ; + if(mPgpHandler->isPgpPubKeyAvailable(RsPgpId::fromBufferUnsafe(received_key_info.fingerprint+12))) + RsDbg() << " PGP Key is already into keyring."; + else + { + RsPgpId pgp_id; + if(!mPgpHandler->LoadCertificateFromBinaryData(key_binary_data.data(),key_binary_data.size(), pgp_id, error_string)) + throw std::runtime_error("Cannot load client's pgp public key into keyring: " + error_string) ; - if(fpr_test != shortInviteDetails.fpr) - throw std::runtime_error("Cannot get fingerprint from keyring for client public key. Something's really wrong.") ; + RsDbg() << " Public key added to keyring."; + RsDbg() << " Sync-ing the PGP keyring on disk"; - RsDbg() << " Short invite PGP fingerprint matches the public key fingerprint."; - RsDbg() << " Sync-ing the PGP keyring on disk"; - - mPgpHandler->syncDatabase(); + mPgpHandler->syncDatabase(); + } + } // Check the item's data signature. Is that needed? Not sure, since the data is sent PGP-encrypted, so only the owner // of the secret PGP key can actually use it. @@ -219,7 +235,7 @@ std::map::iterator FriendServer::handleIncomingClientData(con pi.short_certificate = short_invite_b64; pi.last_connection_TS = time(nullptr); - pi.pgp_fingerprint = fpr_test; + pi.pgp_fingerprint = shortInviteDetails.fpr; while(pi.last_nonce == 0) // reuse the same identifier (so it's not really a nonce, but it's kept secret whatsoever). pi.last_nonce = RsRandom::random_u64();