mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-29 01:16:20 -05:00
improved checking of short invite / pgp key in friend server. Added a key parsing method in PGPKeyManagement
This commit is contained in:
parent
0cf889d556
commit
5e50f23423
@ -54,7 +54,12 @@ namespace librs
|
||||
|
||||
return Sha1CheckSum(h);
|
||||
}
|
||||
|
||||
template<>
|
||||
HashStream& operator<<(HashStream& u,const std::pair<unsigned char *,uint32_t>& p)
|
||||
{
|
||||
EVP_DigestUpdate(u.mdctx,p.first,p.second) ;
|
||||
return u;
|
||||
}
|
||||
template<>
|
||||
HashStream& operator<<(HashStream& u,const std::string& s)
|
||||
{
|
||||
|
@ -21,6 +21,7 @@
|
||||
*******************************************************************************/
|
||||
#include <stdint.h>
|
||||
#include <util/radix64.h>
|
||||
#include <crypto/hashstream.h>
|
||||
#include "pgpkeyutil.h"
|
||||
|
||||
#include <iostream>
|
||||
@ -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;i<packet_length;++i)
|
||||
info.user_id += (char)(data[i]);
|
||||
|
||||
return true ;
|
||||
}
|
||||
bool PGPKeyManagement::parseSignature(const unsigned char *signature, size_t sign_len, PGPSignatureInfo& info)
|
||||
{
|
||||
unsigned char *data = (unsigned char *)signature ;
|
||||
|
@ -81,6 +81,16 @@ public:
|
||||
uint8_t hash_algorithm ;
|
||||
};
|
||||
|
||||
class PGPKeyInfo
|
||||
{
|
||||
public:
|
||||
PGPKeyInfo() {}
|
||||
|
||||
std::string user_id;
|
||||
unsigned char fingerprint[20];
|
||||
};
|
||||
|
||||
|
||||
// This class handles GPG keys. For now we only clean them from signatures, but
|
||||
// in the future, we might cache them to avoid unnecessary calls to gpgme.
|
||||
//
|
||||
@ -107,6 +117,8 @@ class PGPKeyManagement
|
||||
static uint32_t compute24bitsCRC(unsigned char *data,size_t len) ;
|
||||
|
||||
static bool parseSignature(const unsigned char *signature, size_t sign_len, PGPSignatureInfo& info) ;
|
||||
|
||||
static bool parsePGPPublicKey(const unsigned char *keydata, size_t keylen, PGPKeyInfo& info);
|
||||
};
|
||||
|
||||
// This class handles the parsing of PGP packet headers under various (old and new) formats.
|
||||
@ -126,7 +138,7 @@ class PGPKeyParser
|
||||
static uint64_t read_KeyID(unsigned char *& data) ;
|
||||
static uint32_t read_125Size(unsigned char *& data) ;
|
||||
static uint32_t read_partialBodyLength(unsigned char *& data) ;
|
||||
static void read_packetHeader(unsigned char *& data,uint8_t& packet_tag,uint32_t& packet_length) ;
|
||||
static void read_packetHeader(unsigned char *&data, uint8_t& packet_tag, uint32_t& packet_length) ;
|
||||
|
||||
// These functions write, and indicate how many bytes where written.
|
||||
//
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "util/rsbase64.h"
|
||||
#include "util/radix64.h"
|
||||
|
||||
#include "pgp/pgpkeyutil.h"
|
||||
#include "pgp/rscertificate.h"
|
||||
|
||||
#include "friendserver.h"
|
||||
@ -34,10 +35,10 @@ void FriendServer::threadTick()
|
||||
|
||||
switch(fsitem->PacketSubType())
|
||||
{
|
||||
case RS_PKT_SUBTYPE_FS_CLIENT_REMOVE: handleClientRemove(dynamic_cast<RsFriendServerClientRemoveItem*>(fsitem));
|
||||
break;
|
||||
case RS_PKT_SUBTYPE_FS_CLIENT_PUBLISH: handleClientPublish(dynamic_cast<RsFriendServerClientPublishItem*>(fsitem));
|
||||
break;
|
||||
case RS_PKT_SUBTYPE_FS_CLIENT_REMOVE: handleClientRemove(dynamic_cast<RsFriendServerClientRemoveItem*>(fsitem));
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
delete item;
|
||||
@ -169,23 +170,27 @@ std::map<std::string, bool> FriendServer::computeListOfFriendInvites(uint32_t nb
|
||||
|
||||
std::map<RsPeerId,PeerInfo>::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<uint8_t> 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<RsPeerId,PeerInfo>::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<RsPeerId,PeerInfo>::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();
|
||||
|
Loading…
Reference in New Issue
Block a user