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);
|
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<>
|
template<>
|
||||||
HashStream& operator<<(HashStream& u,const std::string& s)
|
HashStream& operator<<(HashStream& u,const std::string& s)
|
||||||
{
|
{
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <util/radix64.h>
|
#include <util/radix64.h>
|
||||||
|
#include <crypto/hashstream.h>
|
||||||
#include "pgpkeyutil.h"
|
#include "pgpkeyutil.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -181,6 +182,59 @@ uint32_t PGPKeyManagement::compute24bitsCRC(unsigned char *octets, size_t len)
|
|||||||
return crc & 0xFFFFFFL;
|
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)
|
bool PGPKeyManagement::parseSignature(const unsigned char *signature, size_t sign_len, PGPSignatureInfo& info)
|
||||||
{
|
{
|
||||||
unsigned char *data = (unsigned char *)signature ;
|
unsigned char *data = (unsigned char *)signature ;
|
||||||
|
@ -81,6 +81,16 @@ public:
|
|||||||
uint8_t hash_algorithm ;
|
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
|
// 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.
|
// 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 uint32_t compute24bitsCRC(unsigned char *data,size_t len) ;
|
||||||
|
|
||||||
static bool parseSignature(const unsigned char *signature, size_t sign_len, PGPSignatureInfo& info) ;
|
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.
|
// 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 uint64_t read_KeyID(unsigned char *& data) ;
|
||||||
static uint32_t read_125Size(unsigned char *& data) ;
|
static uint32_t read_125Size(unsigned char *& data) ;
|
||||||
static uint32_t read_partialBodyLength(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.
|
// These functions write, and indicate how many bytes where written.
|
||||||
//
|
//
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "util/rsbase64.h"
|
#include "util/rsbase64.h"
|
||||||
#include "util/radix64.h"
|
#include "util/radix64.h"
|
||||||
|
|
||||||
|
#include "pgp/pgpkeyutil.h"
|
||||||
#include "pgp/rscertificate.h"
|
#include "pgp/rscertificate.h"
|
||||||
|
|
||||||
#include "friendserver.h"
|
#include "friendserver.h"
|
||||||
@ -34,10 +35,10 @@ void FriendServer::threadTick()
|
|||||||
|
|
||||||
switch(fsitem->PacketSubType())
|
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));
|
case RS_PKT_SUBTYPE_FS_CLIENT_PUBLISH: handleClientPublish(dynamic_cast<RsFriendServerClientPublishItem*>(fsitem));
|
||||||
break;
|
break;
|
||||||
|
case RS_PKT_SUBTYPE_FS_CLIENT_REMOVE: handleClientRemove(dynamic_cast<RsFriendServerClientRemoveItem*>(fsitem));
|
||||||
|
break;
|
||||||
default: ;
|
default: ;
|
||||||
}
|
}
|
||||||
delete item;
|
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)
|
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...";
|
RsDbg() << " Checking item data...";
|
||||||
|
|
||||||
std::string error_string;
|
std::string error_string;
|
||||||
RsPgpId pgp_id ;
|
|
||||||
std::vector<uint8_t> key_binary_data ;
|
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))
|
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??");
|
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))
|
PGPKeyInfo received_key_info;
|
||||||
throw std::runtime_error("Cannot load client's pgp public key into keyring: " + error_string) ;
|
|
||||||
|
|
||||||
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;
|
RsPeerDetails shortInviteDetails;
|
||||||
uint32_t errorCode = 0;
|
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 ))
|
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));
|
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;
|
RsPgpFingerprint fpr_test;
|
||||||
if(!mPgpHandler->getKeyFingerprint(pgp_id,fpr_test))
|
if(mPgpHandler->isPgpPubKeyAvailable(RsPgpId::fromBufferUnsafe(received_key_info.fingerprint+12)))
|
||||||
throw std::runtime_error("Cannot get fingerprint from keyring for client public key. Something's really wrong.") ;
|
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)
|
RsDbg() << " Public key added to keyring.";
|
||||||
throw std::runtime_error("Cannot get fingerprint from keyring for client public key. Something's really wrong.") ;
|
RsDbg() << " Sync-ing the PGP keyring on disk";
|
||||||
|
|
||||||
RsDbg() << " Short invite PGP fingerprint matches the public key fingerprint.";
|
mPgpHandler->syncDatabase();
|
||||||
RsDbg() << " Sync-ing the PGP keyring on disk";
|
}
|
||||||
|
}
|
||||||
mPgpHandler->syncDatabase();
|
|
||||||
|
|
||||||
// Check the item's data signature. Is that needed? Not sure, since the data is sent PGP-encrypted, so only the owner
|
// 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.
|
// 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.short_certificate = short_invite_b64;
|
||||||
pi.last_connection_TS = time(nullptr);
|
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).
|
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();
|
pi.last_nonce = RsRandom::random_u64();
|
||||||
|
Loading…
Reference in New Issue
Block a user