GxsMail: Implemented RSA mail receiving

RsGxsMailBaseItem::deserialize(...) fix offset calculation
RsGxsMailItem::serialize(...) fix offset calculation
RsGxsMailBaseItem initialize cryptoType to UNDEFINED_ENCRYPTION
p3IdService::decryptData(...) implemented multi id variant
RsGixs::*cryptData(...) proper param order
p3IdService::*cryptData(...) proper param order
This commit is contained in:
Gioacchino Mazzurco 2017-01-31 20:14:17 +01:00
parent 54a0f87369
commit 1f1f4ded02
8 changed files with 260 additions and 45 deletions

View File

@ -1892,7 +1892,9 @@ bool p3GRouter::encryptDataItem(RsGRouterGenericDataItem *item,const RsGxsId& de
uint32_t encrypted_size =0;
uint32_t error_status ;
if(!mGixs->encryptData(item->data_bytes,item->data_size,encrypted_data,encrypted_size,destination_key,true,error_status))
if(!mGixs->encryptData( item->data_bytes, item->data_size, encrypted_data,
encrypted_size, destination_key, error_status,
true ))
{
std::cerr << "(EE) Cannot encrypt: " ;
if(error_status == RsGixs::RS_GIXS_ERROR_KEY_NOT_AVAILABLE) std::cerr << " key not available for ID = " << destination_key << std::endl;
@ -1926,7 +1928,9 @@ bool p3GRouter::decryptDataItem(RsGRouterGenericDataItem *item)
uint32_t decrypted_size =0;
uint32_t error_status ;
if(!mGixs->decryptData(item->data_bytes,item->data_size,decrypted_data,decrypted_size,item->destination_key,error_status))
if(!mGixs->decryptData( item->data_bytes, item->data_size, decrypted_data,
decrypted_size, item->destination_key, error_status,
true ))
{
if(error_status == RsGixs::RS_GIXS_ERROR_KEY_NOT_AVAILABLE)
std::cerr << "(EE) Cannot decrypt incoming message. Key " << item->destination_key << " unknown." << std::endl;

View File

@ -103,7 +103,7 @@ typedef PGPIdType RsPgpId;
class RsGixs
{
public:
// TODO: cleanup this should be an enum!
static const uint32_t RS_GIXS_ERROR_NO_ERROR = 0x0000 ;
static const uint32_t RS_GIXS_ERROR_UNKNOWN = 0x0001 ;
static const uint32_t RS_GIXS_ERROR_KEY_NOT_AVAILABLE = 0x0002 ;
@ -119,8 +119,17 @@ public:
virtual bool signData(const uint8_t *data,uint32_t data_size,const RsGxsId& signer_id,RsTlvKeySignature& signature,uint32_t& signing_error) = 0 ;
virtual bool validateData(const uint8_t *data,uint32_t data_size,const RsTlvKeySignature& signature,bool force_load,const RsIdentityUsage& info,uint32_t& signing_error) = 0 ;
virtual bool encryptData(const uint8_t *clear_data,uint32_t clear_data_size,uint8_t *& encrypted_data,uint32_t& encrypted_data_size,const RsGxsId& encryption_key_id,bool force_load,uint32_t& encryption_error) = 0 ;
virtual bool decryptData(const uint8_t *encrypted_data,uint32_t encrypted_data_size,uint8_t *& clear_data,uint32_t& clear_data_size,const RsGxsId& encryption_key_id,uint32_t& encryption_error) = 0 ;
virtual bool encryptData( const uint8_t *clear_data,
uint32_t clear_data_size,
uint8_t *& encrypted_data,
uint32_t& encrypted_data_size,
const RsGxsId& encryption_key_id,
uint32_t& encryption_error, bool force_load) = 0 ;
virtual bool decryptData( const uint8_t *encrypted_data,
uint32_t encrypted_data_size,
uint8_t *& clear_data, uint32_t& clear_data_size,
const RsGxsId& encryption_key_id,
uint32_t& encryption_error, bool force_load) = 0 ;
virtual bool getOwnIds(std::list<RsGxsId>& ids) = 0;
virtual bool isOwnId(const RsGxsId& key_id) = 0 ;

View File

@ -25,7 +25,7 @@ bool RsGxsMailBaseItem::serialize(uint8_t* data, uint32_t size,
uint32_t& offset) const
{
bool ok = setRsItemHeader(data, size, PacketId(), size);
ok = ok && (offset += 8); // Take in account the header
ok = ok && (offset += 8); // Take header in account
ok = ok && setRawUInt8(data, size, &offset, cryptoType);
ok = ok && recipientsHint.serialise(data, size, offset);
return ok;
@ -36,10 +36,10 @@ bool RsGxsMailBaseItem::deserialize(const uint8_t* data, uint32_t& size,
{
void* dataPtr = reinterpret_cast<void*>(const_cast<uint8_t*>(data));
uint32_t rssize = getRsItemSize(dataPtr);
uint32_t roffset = offset + 8;
uint32_t roffset = offset + 8; // Take header in account
bool ok = rssize <= size;
uint8_t crType;
ok = ok && getRawUInt8(dataPtr, rssize, &offset, &crType);
ok = ok && getRawUInt8(dataPtr, rssize, &roffset, &crType);
cryptoType = static_cast<EncryptionMode>(crType);
ok = ok && recipientsHint.deserialise(dataPtr, rssize, roffset);
if(ok) { size = rssize; offset = roffset; }

View File

@ -38,7 +38,8 @@ struct RsGxsMailBaseItem : RsGxsMsgItem
{
RsGxsMailBaseItem(GxsMailItemsSubtypes subtype) :
RsGxsMsgItem( RS_SERVICE_TYPE_GXS_MAIL,
static_cast<uint8_t>(subtype) ) {}
static_cast<uint8_t>(subtype) ),
cryptoType(UNDEFINED_ENCRYPTION) {}
/// Values must fit into uint8_t
enum EncryptionMode
@ -86,11 +87,10 @@ struct RsGxsMailBaseItem : RsGxsMsgItem
*/
RsGxsId recipientsHint;
void inline saltRecipientHint(const RsGxsId& salt)
{ saltRecipientHint(recipientsHint, salt); }
void static inline saltRecipientHint(RsGxsId& hint, const RsGxsId& salt)
{ hint = hint | salt; }
void inline saltRecipientHint(const RsGxsId& salt)
{ saltRecipientHint(recipientsHint, salt); }
/**
* @brief maybeRecipient given an id and an hint check if they match
@ -102,6 +102,8 @@ struct RsGxsMailBaseItem : RsGxsMsgItem
*/
bool static inline maybeRecipient(const RsGxsId& hint, const RsGxsId& id)
{ return (~id|hint) == allRecipientsHint; }
bool inline maybeRecipient(const RsGxsId& id) const
{ return maybeRecipient(recipientsHint, id); }
const static RsGxsId allRecipientsHint;
@ -137,9 +139,12 @@ struct RsGxsMailItem : RsGxsMailBaseItem
uint32_t size() const { return RsGxsMailBaseItem::size() + payload.size(); }
bool serialize(uint8_t* data, uint32_t size, uint32_t& offset) const
{
return size < MAX_SIZE
&& RsGxsMailBaseItem::serialize(data, size, offset)
&& memcpy(data+offset, &payload[0], payload.size());
bool ok = size < MAX_SIZE;
ok = ok && RsGxsMailBaseItem::serialize(data, size, offset);
uint32_t psz = payload.size();
ok = ok && memcpy(data+offset, &payload[0], psz);
offset += psz;
return ok;
}
bool deserialize(const uint8_t* data, uint32_t& size, uint32_t& offset)
{

View File

@ -82,15 +82,15 @@ bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service,
// Public metadata
item->meta.mAuthorId = own_gxsid;
item->meta.mGroupId = preferredGroupId;
item->cryptoType = cm;
typedef std::set<RsGxsId>::const_iterator siT;
for(siT it = rcps.begin(); it != rcps.end(); ++it)
item->saltRecipientHint(*it);
item->saltRecipientHint(*it);
// If there is jut one recipient salt with a random id to avoid leaking it
if(rcps.size() == 1) item->saltRecipientHint(RsGxsId::random());
/* At this point we do a lot of memory copying, it doesn't look pretty but
* ATM haven't thinked of an elegant way to have the GxsMailSubServices
* travelling encrypted withuot copying memory around or responsabilize the
@ -100,7 +100,7 @@ bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service,
uint32_t clearTextPldSize = size+2;
item->payload.resize(clearTextPldSize);
uint32_t _discard = 0;
setRawUInt16(&item->payload[0], clearTextPldSize, &_discard, serv);
setRawUInt16(&item->payload[0], 2, &_discard, serv);
memcpy(&item->payload[2], data, size);
switch (cm)
@ -119,7 +119,7 @@ bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service,
uint32_t encryptError = 0;
if( idService.encryptData( &item->payload[0], clearTextPldSize,
encryptedData, encryptedSize,
rcps, true, encryptError ) )
rcps, encryptError, true ) )
{
item->payload.resize(encryptedSize);
memcpy(&item->payload[0], encryptedData, encryptedSize);
@ -143,6 +143,8 @@ bool p3GxsMails::sendMail( GxsMailsClient::GxsMailSubServices service,
}
uint32_t token;
std::cout << "p3GxsMails::sendEmail(...) sending mail to:"<< *recipients[0]
<< " payload size: : " << item->payload.size() << std::endl;
publishMsg(token, item);
return true;
}
@ -228,14 +230,89 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type)
case GXS_MAIL_SUBTYPE_MAIL:
{
RsGxsMailItem* msg = dynamic_cast<RsGxsMailItem*>(it);
if(msg)
if(!msg)
{
std::cerr << "p3GxsMails::handleResponse(...) "
<< "GXS_MAIL_SUBTYPE_MAIL cast error, "
<< "something really wrong is happening"
<< std::endl;
break;
}
std::cout << "p3GxsMails::handleResponse(...) "
<< "GXS_MAIL_SUBTYPE_MAIL got from: "
<< msg->meta.mAuthorId
<< " recipientsHint: "
<< msg->recipientsHint << " cryptoType: "
<< (uint32_t)msg->cryptoType
<< " payload size: " << msg->payload.size()
<< std::endl;
std::set<RsGxsId> decryptIds;
std::list<RsGxsId> ownIds;
idService.getOwnIds(ownIds);
for(auto it = ownIds.begin(); it != ownIds.end(); ++it)
if(msg->maybeRecipient(*it)) decryptIds.insert(*it);
if(decryptIds.empty())
{
std::cout << "p3GxsMails::handleResponse(...) "
<< "GXS_MAIL_SUBTYPE_MAIL got recipientsHint: "
<< msg->recipientsHint << " cryptoType: "
<< (uint32_t)msg->cryptoType
<< " payload size: " << msg->payload.size()
<< std::endl;
<< "GXS_MAIL_SUBTYPE_MAIL hint match none"
<< " of our own ids" << msg->recipientsHint
<< std::endl;
break;
}
std::cout << "p3GxsMails::handleResponse(...) "
<< "GXS_MAIL_SUBTYPE_MAIL hint: "
<< msg->recipientsHint
<< " match with own ids: ";
for(auto it=decryptIds.begin(); it != decryptIds.end(); ++it)
std::cout << *it;
std::cout << std::endl;
switch (msg->cryptoType)
{
case RsGxsMailBaseItem::CLEAR_TEXT:
{
uint16_t csri = 0;
uint32_t off;
getRawUInt16(&msg->payload[0], 2, &off, &csri);
std::string str(reinterpret_cast<const char*>(&msg->payload[2]), msg->payload.size()-2);
std::cout << "service: " << csri
<< " got CLEAR_TEXT message: "
<< str << std::endl;
break;
}
case RsGxsMailBaseItem::RSA:
{
uint8_t* decrypted_data = NULL;
uint32_t decrypted_data_size = 0;
uint32_t decryption_error;
if( idService.decryptData(
&msg->payload[0],
msg->payload.size(), decrypted_data,
decrypted_data_size, decryptIds,
decryption_error ) )
{
uint16_t csri = *reinterpret_cast<uint16_t*>(decrypted_data);
std::string str(reinterpret_cast<char const*>(decrypted_data+2), decrypted_data_size-2);
std::cout << "service: " << csri
<< " got RSA message: "
<< str << std::endl;
}
else std::cout << "p3GxsMails::handleResponse(...) "
<< "GXS_MAIL_SUBTYPE_MAIL RSA decryption"
<< " failed" << std::endl;
free(decrypted_data);
break;
}
default:
std::cout << "Unknown encryption type:"
<< msg->cryptoType << std::endl;
break;
}
break;
}
@ -247,6 +324,7 @@ void p3GxsMails::handleResponse(uint32_t token, uint32_t req_type)
}
}
}
break;
}
default:
std::cerr << "p3GxsMails::handleResponse(...) Unknown req_type: "
@ -271,14 +349,14 @@ void p3GxsMails::service_tick()
std::string ciao("CiAone!");
sendMail( GxsMailsClient::MSG_SERVICE, gxsidA, gxsidB,
reinterpret_cast<const uint8_t*>(ciao.data()),
ciao.size());
ciao.size(), RsGxsMailBaseItem::RSA );
}
else if(idService.isOwnId(gxsidB))
{
std::string ciao("CiBone!");
std::string ciao("CiBuono!");
sendMail( GxsMailsClient::MSG_SERVICE, gxsidB, gxsidA,
reinterpret_cast<const uint8_t*>(ciao.data()),
ciao.size());
ciao.size(), RsGxsMailBaseItem::RSA );
}
}

View File

@ -125,8 +125,13 @@ private:
/// @brief AuthenPolicy check nothing ATM TODO talk with Cyril how this should be
static uint32_t AuthenPolicy() { return 0; }
/// Types to mark GXS queries and answhers
enum GxsReqResTypes { GROUPS_LIST, GROUP_CREATE, MAILS_UPDATE };
/// Types to mark queries in tokens queue
enum GxsReqResTypes
{
GROUPS_LIST = 1,
GROUP_CREATE = 2,
MAILS_UPDATE = 3
};
/// Store the id of the preferred GXS group to send emails
RsGxsGroupId preferredGroupId;

View File

@ -1036,7 +1036,13 @@ bool p3IdService::validateData(const uint8_t *data,uint32_t data_size,const RsTl
return true ;
}
bool p3IdService::encryptData(const uint8_t *decrypted_data,uint32_t decrypted_data_size,uint8_t *& encrypted_data,uint32_t& encrypted_data_size,const RsGxsId& encryption_key_id,bool force_load,uint32_t& error_status)
bool p3IdService::encryptData( const uint8_t *decrypted_data,
uint32_t decrypted_data_size,
uint8_t *& encrypted_data,
uint32_t& encrypted_data_size,
const RsGxsId& encryption_key_id,
uint32_t& error_status,
bool force_load )
{
RsTlvPublicRSAKey encryption_key ;
@ -1071,7 +1077,7 @@ bool p3IdService::encryptData( const uint8_t* decrypted_data,
uint8_t*& encrypted_data,
uint32_t& encrypted_data_size,
const std::set<RsGxsId>& encrypt_ids,
bool force_load, uint32_t& error_status )
uint32_t& error_status, bool force_load )
{
std::set<const RsGxsId*> keyNotYetFoundIds;
@ -1154,18 +1160,22 @@ bool p3IdService::encryptData( const uint8_t* decrypted_data,
return true;
}
bool p3IdService::decryptData(const uint8_t *encrypted_data,uint32_t encrypted_data_size,uint8_t *& decrypted_data,uint32_t& decrypted_size,const RsGxsId& key_id,uint32_t& error_status)
bool p3IdService::decryptData( const uint8_t *encrypted_data,
uint32_t encrypted_data_size,
uint8_t *& decrypted_data,
uint32_t& decrypted_size,
const RsGxsId& key_id, uint32_t& error_status,
bool force_load )
{
RsTlvPrivateRSAKey encryption_key ;
// Get the key, and let the cache find it. It's our own key, so we should be able to find it, even if it takes
// some seconds.
for(int i=0;i<4;++i)
if(getPrivateKey(key_id,encryption_key))
break ;
else
usleep(500*1000) ; // sleep half a sec.
int maxRounds = force_load ? 6 : 1;
for(int i=0; i<maxRounds ;++i)
if(getPrivateKey(key_id,encryption_key)) break;
else usleep(500*1000) ; // sleep half a sec.
if(encryption_key.keyId.isNull())
{
@ -1179,13 +1189,106 @@ bool p3IdService::decryptData(const uint8_t *encrypted_data,uint32_t encrypted_d
std::cerr << " (EE) Decryption failed." << std::endl;
error_status = RS_GIXS_ERROR_UNKNOWN ;
return false ;
}
error_status = RS_GIXS_ERROR_NO_ERROR ;
timeStampKey(key_id,RsIdentityUsage(serviceType(),RsIdentityUsage::IDENTITY_GENERIC_DECRYPTION)) ;
}
error_status = RS_GIXS_ERROR_NO_ERROR;
timeStampKey( key_id,
RsIdentityUsage(
serviceType(),
RsIdentityUsage::IDENTITY_GENERIC_DECRYPTION) );
return true ;
}
bool p3IdService::decryptData( const uint8_t* encrypted_data,
uint32_t encrypted_data_size,
uint8_t*& decrypted_data,
uint32_t& decrypted_data_size,
const std::set<RsGxsId>& decrypt_ids,
uint32_t& error_status,
bool force_load )
{
std::set<const RsGxsId*> keyNotYetFoundIds;
for( std::set<RsGxsId>::const_iterator it = decrypt_ids.begin();
it != decrypt_ids.end(); ++it )
{
const RsGxsId& gId(*it);
if(gId.isNull())
{
std::cerr << "p3IdService::decryptData(...) (EE) got null GXS id"
<< std::endl;
print_stacktrace();
return false;
}
else keyNotYetFoundIds.insert(&gId);
}
if(keyNotYetFoundIds.empty())
{
std::cerr << "p3IdService::decryptData(...) (EE) got empty GXS ids set"
<< std::endl;
print_stacktrace();
return false;
}
std::vector<RsTlvPrivateRSAKey> decryption_keys;
int maxRounds = force_load ? 6 : 1;
for( int i=0; i < maxRounds; ++i )
{
for( std::set<const RsGxsId*>::iterator it = keyNotYetFoundIds.begin();
it !=keyNotYetFoundIds.end(); ++it )
{
RsTlvPrivateRSAKey decryption_key;
if( getPrivateKey(**it, decryption_key)
&& !decryption_key.keyId.isNull() )
{
decryption_keys.push_back(decryption_key);
keyNotYetFoundIds.erase(it);
}
}
if(keyNotYetFoundIds.empty()) break;
else usleep(500*1000);
}
if(!keyNotYetFoundIds.empty())
{
std::cerr << "p3IdService::decryptData(...) (EE) Cannot get private key"
<< " for: ";
for( std::set<const RsGxsId*>::iterator it = keyNotYetFoundIds.begin();
it !=keyNotYetFoundIds.end(); ++it )
std::cerr << **it << " ";
std::cerr << std::endl;
print_stacktrace();
error_status = RS_GIXS_ERROR_KEY_NOT_AVAILABLE;
return false;
}
if(!GxsSecurity::decrypt( decrypted_data, decrypted_data_size,
encrypted_data, encrypted_data_size,
decryption_keys ))
{
std::cerr << "p3IdService::decryptData(...) (EE) Decryption failed."
<< std::endl;
print_stacktrace();
error_status = RS_GIXS_ERROR_UNKNOWN;
return false ;
}
for( std::set<RsGxsId>::const_iterator it = decrypt_ids.begin();
it != decrypt_ids.end(); ++it )
{
timeStampKey( *it,
RsIdentityUsage(
serviceType(),
RsIdentityUsage::IDENTITY_GENERIC_DECRYPTION ) );
}
error_status = RS_GIXS_ERROR_NO_ERROR;
return true;
}
#ifdef TO_BE_REMOVED
/********************************************************************************/

View File

@ -303,21 +303,32 @@ public:
uint8_t*& encrypted_data,
uint32_t& encrypted_data_size,
const RsGxsId& encryption_key_id,
bool force_load, uint32_t& encryption_error);
uint32_t& error_status,
bool force_load = true );
bool encryptData( const uint8_t* decrypted_data,
uint32_t decrypted_data_size,
uint8_t*& encrypted_data,
uint32_t& encrypted_data_size,
const std::set<RsGxsId>& encrypt_ids,
bool force_load, uint32_t& error_status );
uint32_t& error_status, bool force_loa = true );
virtual bool decryptData( const uint8_t* encrypted_data,
uint32_t encrypted_data_size,
uint8_t*& decrypted_data,
uint32_t& decrypted_data_size,
const RsGxsId& encryption_key_id,
uint32_t& encryption_error );
const RsGxsId& decryption_key_id,
uint32_t& error_status,
bool force_load = true );
virtual bool decryptData(const uint8_t* encrypted_data,
uint32_t encrypted_data_size,
uint8_t*& decrypted_data,
uint32_t& decrypted_data_size,
const std::set<RsGxsId>& decrypt_ids,
uint32_t& error_status,
bool force_load = true );
virtual bool haveKey(const RsGxsId &id);
virtual bool havePrivateKey(const RsGxsId &id);