Bug fix, did not add time stamp at msg signing stage (bug thunder found)

Did not do check for msgs that already existed, msg is not checked if it exist this is deleted and error is sent to GUI for token
need to do same for groups!
Removed stack allocated msgs which cause crashes for large message items (bug defnax found)
Added function to retrieve group keys from GXS to RsGenExchange
First bits need for validation: Signing now consist of all msg data (msg + meta except msgId and signature)



git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.5-gxs-b1@5718 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
chrisparker126 2012-10-23 21:52:51 +00:00
parent 6e04229d39
commit 301e85c2fa
6 changed files with 286 additions and 123 deletions

View File

@ -28,6 +28,8 @@
#include "pqi/authgpg.h"
#include "retroshare/rspeers.h"
#define GXS_SECURITY_DEBUG
GxsSecurity::GxsSecurity()
{
}
@ -48,10 +50,92 @@ RSA *GxsSecurity::extractPublicKey(RsTlvSecurityKey& key)
}
bool GxsSecurity::validateNxsMsg(RsNxsMsg *msg, RsGxsGrpMetaData *grpMeta)
bool GxsSecurity::validateNxsMsg(RsNxsMsg *msg, RsTlvKeySignature& sign, RsTlvSecurityKeySet& key)
{
//#ifdef GXS_SECURITY_DEBUG
// std::cerr << "GxsSecurity::validateNxsMsg()";
// std::cerr << std::endl;
// std::cerr << "RsNxsMsg :";
// std::cerr << std::endl;
// msg->print(std::cerr, 10);
// std::cerr << std::endl;
//#endif
return false;
// /********************* check signature *******************/
// /* check signature timeperiod */
// if ((newMsg->timestamp < kit->second.startTS) ||
// (newMsg->timestamp > kit->second.endTS))
// {
//#ifdef DISTRIB_DEBUG
// std::cerr << "p3GroupDistrib::locked_validateDistribSignedMsg() TS out of range";
// std::cerr << std::endl;
//#endif
// return false;
// }
// /* decode key */
// const unsigned char *keyptr = (const unsigned char *) kit->second.keyData.bin_data;
// long keylen = kit->second.keyData.bin_len;
// unsigned int siglen = newMsg->publishSignature.signData.bin_len;
// unsigned char *sigbuf = (unsigned char *) newMsg->publishSignature.signData.bin_data;
//#ifdef DISTRIB_DEBUG
// std::cerr << "p3GroupDistrib::locked_validateDistribSignedMsg() Decode Key";
// std::cerr << " keylen: " << keylen << " siglen: " << siglen;
// std::cerr << std::endl;
//#endif
// /* extract admin key */
// RSA *rsakey = d2i_RSAPublicKey(NULL, &(keyptr), keylen);
// if (!rsakey)
// {
//#ifdef DISTRIB_DEBUG
// std::cerr << "p3GroupDistrib::locked_validateDistribSignedMsg()";
// std::cerr << " Invalid RSA Key";
// std::cerr << std::endl;
// unsigned long err = ERR_get_error();
// std::cerr << "RSA Load Failed .... CODE(" << err << ")" << std::endl;
// std::cerr << ERR_error_string(err, NULL) << std::endl;
// kit->second.print(std::cerr, 10);
//#endif
// }
// EVP_PKEY *signKey = EVP_PKEY_new();
// EVP_PKEY_assign_RSA(signKey, rsakey);
// /* calc and check signature */
// EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
// EVP_VerifyInit(mdctx, EVP_sha1());
// EVP_VerifyUpdate(mdctx, newMsg->packet.bin_data, newMsg->packet.bin_len);
// int signOk = EVP_VerifyFinal(mdctx, sigbuf, siglen, signKey);
// /* clean up */
// EVP_PKEY_free(signKey);
// EVP_MD_CTX_destroy(mdctx);
// if (signOk == 1)
// {
//#ifdef GXS_SECURITY_DEBUG
// std::cerr << "p3GroupDistrib::locked_validateDistribSignedMsg() Signature OK";
// std::cerr << std::endl;
//#endif
// return true;
// }
//#ifdef DISTRIB_DEBUG
// std::cerr << "p3GroupDistrib::locked_validateDistribSignedMsg() Signature invalid";
// std::cerr << std::endl;
//#endif
// return false;
}
@ -235,7 +319,7 @@ std::string GxsSecurity::getRsaKeySign(RSA *pubkey)
}
bool GxsSecurity::validateNxsGrp(RsNxsGrp *newGrp)
bool GxsSecurity::validateNxsGrp(RsNxsGrp *newGrp, RsTlvKeySignature& sign, RsTlvSecurityKey& key)
{
}

View File

@ -2,12 +2,12 @@
#define GXSSECURITY_H
/*
* libretroshare/src/gxs: gxssecurity
* libretroshare/src/gxs: gxssecurity.h
*
* Security functions for Gxs
*
* Copyright 2008-2010 by Robert Fernie
* 2012 Christopher Evi-Parker
* 2011-2012 Christopher Evi-Parker
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -82,11 +82,11 @@ public:
static std::string getRsaKeySign(RSA *pubkey);
/*!
* extracts the signature and stores it in a string
* extracts the first CERTSIGNLEN bytes of signature and stores it in a string
* in hex format
* @param data
* @param len
* @return
* @param data signature
* @param len the length of the signature data
* @return returns the first CERTSIGNLEN of the signature as a string
*/
static std::string getBinDataSign(void *data, int len);
@ -115,18 +115,21 @@ public:
/*!
* uses grp signature to check if group has been
* tampered with
* @param newGrp
* @param newGrp the Nxs group to be validated
* @param sign the signature to validdate against
* @param key the public key to use to check signature
* @return true if group valid false otherwise
*/
static bool validateNxsGrp(RsNxsGrp *newGrp);
static bool validateNxsGrp(RsNxsGrp *newGrp, RsTlvKeySignature& sign, RsTlvSecurityKey& key);
/*!
* uses groupinfo public key to verify signature of signed message
* @param info groupinfo for which msg is meant for
* @param msg
* Validate a msg's signature using the given public key
* @param msg the Nxs message to be validated
* @param sign the signature to validdate against
* @param key the public key to use to check signature
* @return false if verfication of signature is not passed
*/
static bool validateNxsMsg(RsNxsMsg *msg, RsGxsGrpMetaData* grpMeta);
static bool validateNxsMsg(RsNxsMsg *msg, RsTlvKeySignature& sign, RsTlvSecurityKeySet& key);
};
#endif // GXSSECURITY_H

View File

@ -400,7 +400,7 @@ RsNxsMsg* RsDataService::getMessage(RetroCursor &c)
if(ok){
char msg_data[data_len];
char* msg_data = new char[data_len];
std::ifstream istrm(msgFile.c_str(), std::ios::binary);
istrm.seekg(offset, std::ios::beg);
istrm.read(msg_data, data_len);
@ -408,6 +408,7 @@ RsNxsMsg* RsDataService::getMessage(RetroCursor &c)
istrm.close();
offset = 0;
ok &= msg->msg.GetTlv(msg_data, data_len, &offset);
delete[] msg_data;
}
if(ok)

View File

@ -36,8 +36,8 @@
#include "rsgxsflags.h"
RsGenExchange::RsGenExchange(RsGeneralDataService *gds,
RsNetworkExchangeService *ns, RsSerialType *serviceSerialiser, uint16_t servType)
: mGenMtx("GenExchange"), mDataStore(gds), mNetService(ns), mSerialiser(serviceSerialiser), mServType(servType)
RsNetworkExchangeService *ns, RsSerialType *serviceSerialiser, uint16_t servType, RsGixs* gixs)
: mGenMtx("GenExchange"), mDataStore(gds), mNetService(ns), mSerialiser(serviceSerialiser), mServType(servType), mGixs(gixs)
{
mDataAccess = new RsGxsDataAccess(gds);
@ -206,12 +206,11 @@ bool RsGenExchange::createMessage(RsNxsMsg* msg)
}
else
{
// get publish key
RsGxsGrpMetaData* meta = metaMap[id];
RsGxsGrpMetaData* grpMeta = metaMap[id];
// public and shared is publish key
RsTlvSecurityKeySet& keys = meta->keys;
RsTlvSecurityKeySet& keys = grpMeta->keys;
RsTlvSecurityKey* pubKey;
std::map<std::string, RsTlvSecurityKey>::iterator mit =
@ -235,15 +234,28 @@ bool RsGenExchange::createMessage(RsNxsMsg* msg)
/* calc and check signature */
EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
RsGxsMsgMetaData &meta = *(msg->metaData);
uint32_t metaDataLen = meta.serial_size();
uint32_t allMsgDataLen = metaDataLen + msg->msg.bin_len;
char* metaData = new char[metaDataLen];
char* allMsgData = new char[allMsgDataLen]; // msgData + metaData
meta.serialise(metaData, &metaDataLen);
// copy msg data and meta in allmsgData buffer
memcpy(allMsgData, msg->msg.bin_data, msg->msg.bin_len);
memcpy(allMsgData+(msg->msg.bin_len), metaData, metaDataLen);
ok = EVP_SignInit(mdctx, EVP_sha1()) == 1;
ok = EVP_SignUpdate(mdctx, msg->msg.bin_data, msg->msg.bin_len) == 1;
ok = EVP_SignUpdate(mdctx, allMsgData, allMsgDataLen) == 1;
unsigned int siglen = EVP_PKEY_size(key_pub);
unsigned char sigbuf[siglen];
ok = EVP_SignFinal(mdctx, sigbuf, &siglen, key_pub) == 1;
//place signature in msg meta
RsGxsMsgMetaData &meta = *(msg->metaData);
RsTlvKeySignatureSet& signSet = meta.signSet;
RsTlvKeySignature pubSign = signSet.keySignSet[GXS_SERV::FLAG_AUTHEN_PUBLISH];
pubSign.signData.setBinData(sigbuf, siglen);
@ -251,7 +263,7 @@ bool RsGenExchange::createMessage(RsNxsMsg* msg)
// get hash of msg data to create msg id
pqihash hash;
hash.addData(msg->msg.bin_data, msg->msg.bin_len);
hash.addData(allMsgData, allMsgDataLen);
hash.Complete(msg->msgId);
msg->metaData->mMsgId = msg->msgId;
@ -261,13 +273,16 @@ bool RsGenExchange::createMessage(RsNxsMsg* msg)
//RSA_free(rsa_pub);
EVP_PKEY_free(key_pub);
// no need to free rsa key as evp key is considered parent key by SSL
delete[] metaData;
delete[] allMsgData;
}
else
{
ok = false;
}
delete meta;
delete grpMeta;
}
return ok;
@ -366,33 +381,35 @@ bool RsGenExchange::getGroupData(const uint32_t &token, std::vector<RsGxsGrpItem
bool RsGenExchange::getMsgData(const uint32_t &token,
GxsMsgDataMap &msgItems)
{
NxsMsgDataResult msgResult;
bool ok = mDataAccess->getMsgData(token, msgResult);
NxsMsgDataResult::iterator mit = msgResult.begin();
if(ok)
{
for(; mit != msgResult.end(); mit++)
{
std::vector<RsGxsMsgItem*> gxsMsgItems;
const RsGxsGroupId& grpId = mit->first;
std::vector<RsNxsMsg*>& nxsMsgsV = mit->second;
std::vector<RsNxsMsg*>::iterator vit
= nxsMsgsV.begin();
for(; vit != nxsMsgsV.end(); vit++)
{
RsNxsMsg*& msg = *vit;
RsStackMutex stack(mGenMtx);
NxsMsgDataResult msgResult;
bool ok = mDataAccess->getMsgData(token, msgResult);
NxsMsgDataResult::iterator mit = msgResult.begin();
RsItem* item = mSerialiser->deserialise(msg->msg.bin_data,
&msg->msg.bin_len);
RsGxsMsgItem* mItem = dynamic_cast<RsGxsMsgItem*>(item);
mItem->meta = *((*vit)->metaData); // get meta info from nxs msg
gxsMsgItems.push_back(mItem);
delete msg;
}
msgItems[grpId] = gxsMsgItems;
}
}
if(ok)
{
for(; mit != msgResult.end(); mit++)
{
std::vector<RsGxsMsgItem*> gxsMsgItems;
const RsGxsGroupId& grpId = mit->first;
std::vector<RsNxsMsg*>& nxsMsgsV = mit->second;
std::vector<RsNxsMsg*>::iterator vit
= nxsMsgsV.begin();
for(; vit != nxsMsgsV.end(); vit++)
{
RsNxsMsg*& msg = *vit;
RsItem* item = mSerialiser->deserialise(msg->msg.bin_data,
&msg->msg.bin_len);
RsGxsMsgItem* mItem = dynamic_cast<RsGxsMsgItem*>(item);
mItem->meta = *((*vit)->metaData); // get meta info from nxs msg
gxsMsgItems.push_back(mItem);
delete msg;
}
msgItems[grpId] = gxsMsgItems;
}
}
return ok;
}
@ -562,70 +579,90 @@ void RsGenExchange::publishMsgs()
for(; mit != mMsgsToPublish.end(); mit++)
{
RsNxsMsg* msg = new RsNxsMsg(mServType);
RsGxsMsgItem* msgItem = mit->second;
RsNxsMsg* msg = new RsNxsMsg(mServType);
RsGxsMsgItem* msgItem = mit->second;
msg->grpId = msgItem->meta.mGroupId;
msg->grpId = msgItem->meta.mGroupId;
uint32_t size = mSerialiser->size(msgItem);
char mData[size];
bool ok = mSerialiser->serialise(msgItem, mData, &size);
uint32_t size = mSerialiser->size(msgItem);
char* mData = new char[size];
bool serialOk = false;
bool createOk = false;
serialOk = mSerialiser->serialise(msgItem, mData, &size);
if(ok)
{
msg->metaData = new RsGxsMsgMetaData();
msg->msg.setBinData(mData, size);
*(msg->metaData) = msgItem->meta;
if(serialOk)
{
msg->msg.setBinData(mData, size);
ok = createMessage(msg);
RsGxsMessageId msgId;
RsGxsGroupId grpId;
if(ok)
{
msg->metaData->mPublishTs = time(NULL);
// now create meta
msg->metaData = new RsGxsMsgMetaData();
*(msg->metaData) = msgItem->meta;
// empty orig msg id means this is the original
// msg
// TODO: a non empty msgid means one should at least
// have the msg on disk, after which this msg is signed
// based on the security settings
// public grp (sign by grp public pub key, private/id: signed by
// id
if(msg->metaData->mOrigMsgId.empty())
{
msg->metaData->mOrigMsgId = msg->metaData->mMsgId;
}
// assign time stamp
msg->metaData->mPublishTs = time(NULL);
// now serialise meta data
size = msg->metaData->serial_size();
char metaDataBuff[size];
msg->metaData->serialise(metaDataBuff, &size);
msg->meta.setBinData(metaDataBuff, size);
// now intialise msg (sign it)
createOk = createMessage(msg);
RsGxsMessageId msgId;
RsGxsGroupId grpId = msgItem->meta.mGroupId;
bool msgDoesnExist = false;
if(createOk)
{
GxsMsgReq req;
std::vector<RsGxsMessageId> msgV;
msgV.push_back(msg->msgId);
GxsMsgMetaResult res;
req.insert(std::make_pair(msg->grpId, msgV));
mDataStore->retrieveGxsMsgMetaData(req, res);
msgDoesnExist = res[grpId].empty();
}
if(createOk && msgDoesnExist)
{
// empty orig msg id means this is the original
// msg
// TODO: a non empty msgid means one should at least
// have the msg on disk, after which this msg is signed
// based on the security settings
// public grp (sign by grp public pub key, private/id: signed by
// id
if(msg->metaData->mOrigMsgId.empty())
{
msg->metaData->mOrigMsgId = msg->metaData->mMsgId;
}
// now serialise meta data
size = msg->metaData->serial_size();
char metaDataBuff[size];
msg->metaData->serialise(metaDataBuff, &size);
msg->meta.setBinData(metaDataBuff, size);
msgId = msg->msgId;
grpId = msg->grpId;
mDataAccess->addMsgData(msg);
msgId = msg->msgId;
grpId = msg->grpId;
ok = mDataAccess->addMsgData(msg);
}
// add to published to allow acknowledgement
mMsgNotify.insert(std::make_pair(mit->first, std::make_pair(grpId, msgId)));
mDataAccess->updatePublicRequestStatus(mit->first, RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE);
}
else
{
// delete msg if created wasn't ok
delete msg;
mDataAccess->updatePublicRequestStatus(mit->first, RsTokenService::GXS_REQUEST_V2_STATUS_FAILED);
// add to published to allow acknowledgement
mMsgNotify.insert(std::make_pair(mit->first, std::make_pair(grpId, msgId)));
mDataAccess->updatePublicRequestStatus(mit->first, RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE);
}
// if addition failed then delete nxs message
if(!ok)
{
#ifdef GEN_EXCH_DEBUG
std::cerr << "RsGenExchange::publishMsgs() failed to publish msg " << std::endl;
std::cerr << "RsGenExchange::publishMsgs() failed to publish msg " << std::endl;
#endif
mMsgNotify.insert(std::make_pair(mit->first, std::make_pair(RsGxsGroupId(""), RsGxsMessageId(""))));
}
}
continue;
}
delete msgItem; // delete msg item as we're done with it
delete[] mData;
delete msgItem;
}
// clear msg list as we're done publishing them and entries
@ -715,6 +752,29 @@ RsGeneralDataService* RsGenExchange::getDataStore()
return mDataStore;
}
bool RsGenExchange::getGroupKeys(const RsGxsGroupId &grpId, RsTlvSecurityKeySet &keySet)
{
if(grpId.empty())
return false;
RsStackMutex stack(mGenMtx);
std::map<RsGxsGroupId, RsGxsGrpMetaData*> grpMeta;
grpMeta[grpId] = NULL;
mDataStore->retrieveGxsGrpMetaData(grpMeta);
if(grpMeta.empty())
return false;
RsGxsGrpMetaData* meta = grpMeta[grpId];
if(meta == NULL)
return false;
keySet = meta->keys;
return true;
}
void RsGenExchange::createDummyGroup(RsGxsGrpItem *grpItem)
{

View File

@ -32,6 +32,7 @@
#include "rsgxs.h"
#include "rsgds.h"
#include "rsnxs.h"
#include "rsgixs.h"
#include "rsgxsdataaccess.h"
#include "rsnxsobserver.h"
#include "retroshare/rsgxsservice.h"
@ -49,17 +50,17 @@ typedef std::map<RsGxsGroupId, std::vector<RsMsgMetaData> > GxsMsgMetaMap;
* management/publishing/sync features
*
* Features: \n
* a. Data Access:
* Provided by handle to RsTokenService. This ensure consistency
* of requests and hiearchy of groups -> then messages which are
* sectioned by group ids.
* The one caveat is that redemption of tokens are done through
* the backend of this class
* b. Publishing:
* Methods are provided to publish msg and group items and also make
* changes to meta information of both item types
* c. Sync/Notification:
* Also notifications are made here on receipt of new data from
* a. Data Access: \n
* Provided by handle to RsTokenService. This ensure consistency \n
* of requests and hiearchy of groups -> then messages which are \n
* sectioned by group ids. \n
* The one caveat is that redemption of tokens are done through \n
* the backend of this class \n
* b. Publishing: \n
* Methods are provided to publish msg and group items and also make \n
* changes to meta information of both item types \n
* c. Sync/Notification: \n
* Also notifications are made here on receipt of new data from \n
* connected peers
*/
class RsGenExchange : public RsGxsService, public RsNxsObserver
@ -67,14 +68,17 @@ class RsGenExchange : public RsGxsService, public RsNxsObserver
public:
/*!
* Constructs a RsGenExchange object, the owner ship of gds, ns, and serviceserialiser passes
* Constructs a RsGenExchange object, the owner ship of gds, ns, and serviceserialiser passes \n
* onto the constructed object
* @param gds Data service needed to act as store of message
* @param ns Network service needed to synchronise data with rs peers
* @param serviceSerialiser The users service needs this \n
* in order for gen exchange to deal with its data types
* @param mServType This should be service type used by the serialiser
* @param This is used for verification of msgs and groups received by Gen Exchange using identities, set to NULL if \n
* identity verification is not wanted
*/
RsGenExchange(RsGeneralDataService* gds, RsNetworkExchangeService* ns, RsSerialType* serviceSerialiser, uint16_t mServType);
RsGenExchange(RsGeneralDataService* gds, RsNetworkExchangeService* ns, RsSerialType* serviceSerialiser, uint16_t mServType, RsGixs* gixs = NULL);
virtual ~RsGenExchange();
@ -204,6 +208,16 @@ protected:
*/
RsGeneralDataService* getDataStore();
/*!
* Retrieve keys for a given group, \n
* call is blocking retrieval for underlying db
* @warning under normal circumstance a service should not need this
* @param grpId the id of the group to retrieve keys for
* @param keys this is set to the retrieved keys
* @return false if group does not exist or grpId is empty
*/
bool getGroupKeys(const RsGxsGroupId& grpId, RsTlvSecurityKeySet& keySet);
public:
/*!
@ -326,6 +340,7 @@ private:
RsGeneralDataService* mDataStore;
RsNetworkExchangeService *mNetService;
RsSerialType *mSerialiser;
RsGixs* mGixs;
std::vector<RsNxsMsg*> mReceivedMsgs;
std::vector<RsNxsGrp*> mReceivedGrps;

View File

@ -122,7 +122,7 @@ typedef std::string PeerId;
/* Identity Interface for GXS Message Verification.
*/
typedef std::string RsGxsId;
class RsGixs
{
public:
@ -180,14 +180,14 @@ public:
/*** This Class pulls all the GXS Interfaces together ****/
class RsGxsIdExchange: public RsGenExchange, public RsGixsReputation, public RsGixs
{
public:
RsGxsIdExchange(RsGeneralDataService* gds, RsNetworkExchangeService* ns, RsSerialType* serviceSerialiser, uint16_t mServType)
:RsGenExchange(gds,ns,serviceSerialiser,mServType) { return; }
virtual ~RsGxsIdExchange() { return; }
//class RsGxsIdExchange: public RsGenExchange, public RsGixsReputation, public RsGixs
//{
//public:
// RsGxsIdExchange(RsGeneralDataService* gds, RsNetworkExchangeService* ns, RsSerialType* serviceSerialiser, uint16_t mServType)
// :RsGenExchange(gds,ns,serviceSerialiser,mServType) { return; }
//virtual ~RsGxsIdExchange() { return; }
};
//};