2012-08-12 16:46:21 -04:00
/*
2012-11-02 19:35:10 -04:00
* libretroshare / src / gxs : gxssecurity . cc
2012-08-12 16:46:21 -04:00
*
*
* Copyright 2008 - 2010 by Robert Fernie
2012-11-02 19:35:10 -04:00
* 2011 - 2012 Christopher Evi - Parker
2012-08-12 16:46:21 -04:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Library General Public
* License Version 2 as published by the Free Software Foundation .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Library General Public License for more details .
*
* You should have received a copy of the GNU Library General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307
* USA .
*
* Please report all bugs and problems to " retroshare@lunamutt.com " .
*
*/
# include "gxssecurity.h"
# include "pqi/authgpg.h"
2014-05-15 17:00:44 -04:00
# include "util/rsdir.h"
2015-12-17 00:08:08 -05:00
# include "util/rsmemory.h"
2014-04-27 09:14:07 -04:00
//#include "retroshare/rspeers.h"
2012-08-12 16:46:21 -04:00
2014-05-04 08:48:42 -04:00
/****
* # define GXS_SECURITY_DEBUG 1
* * */
2012-10-23 17:52:51 -04:00
2016-02-18 21:30:52 -05:00
static const uint32_t MULTI_ENCRYPTION_FORMAT_v001_HEADER = 0xFACE ;
static const uint32_t MULTI_ENCRYPTION_FORMAT_v001_HEADER_SIZE = 2 ;
static const uint32_t MULTI_ENCRYPTION_FORMAT_v001_NUMBER_OF_KEYS_SIZE = 2 ;
2016-02-18 23:38:07 -05:00
static const uint32_t MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE = 256 ;
2016-02-16 22:36:22 -05:00
2016-06-17 20:46:24 -04:00
static RsGxsId getRsaKeyFingerprint_old_insecure_method ( RSA * pubkey )
{
int lenn = BN_num_bytes ( pubkey - > n ) ;
RsTemporaryMemory tmp ( lenn ) ;
BN_bn2bin ( pubkey - > n , tmp ) ;
// Copy first CERTSIGNLEN bytes from the hash of the public modulus and exponent
// We should not be using strings here, but a real ID. To be done later.
assert ( lenn > = CERTSIGNLEN ) ;
return RsGxsId ( ( unsigned char * ) tmp ) ;
}
2014-06-12 06:28:23 -04:00
static RsGxsId getRsaKeyFingerprint ( RSA * pubkey )
2012-08-12 16:46:21 -04:00
{
2014-05-17 09:50:40 -04:00
int lenn = BN_num_bytes ( pubkey - > n ) ;
int lene = BN_num_bytes ( pubkey - > e ) ;
2016-04-30 17:25:24 -04:00
RsTemporaryMemory tmp ( lenn + lene ) ;
2014-05-17 09:50:40 -04:00
BN_bn2bin ( pubkey - > n , tmp ) ;
BN_bn2bin ( pubkey - > e , & tmp [ lenn ] ) ;
2016-04-30 17:25:24 -04:00
Sha1CheckSum s = RsDirUtil : : sha1sum ( tmp , lenn + lene ) ;
2014-05-17 09:50:40 -04:00
// Copy first CERTSIGNLEN bytes from the hash of the public modulus and exponent
// We should not be using strings here, but a real ID. To be done later.
assert ( Sha1CheckSum : : SIZE_IN_BYTES > = CERTSIGNLEN ) ;
2014-06-12 06:28:23 -04:00
return RsGxsId ( s . toStdString ( ) . substr ( 0 , 2 * CERTSIGNLEN ) ) ;
2012-08-12 16:46:21 -04:00
}
2016-06-02 23:47:57 -04:00
static RSA * extractPrivateKey ( const RsTlvPrivateRSAKey & key )
2015-07-15 18:20:00 -04:00
{
assert ( key . keyFlags & RSTLV_KEY_TYPE_FULL ) ;
const unsigned char * keyptr = ( const unsigned char * ) key . keyData . bin_data ;
long keylen = key . keyData . bin_len ;
/* extract admin key */
RSA * rsakey = d2i_RSAPrivateKey ( NULL , & ( keyptr ) , keylen ) ;
return rsakey ;
}
2016-06-02 23:47:57 -04:00
static RSA * extractPublicKey ( const RsTlvPublicRSAKey & key )
2012-08-12 16:46:21 -04:00
{
2015-01-10 02:30:26 -05:00
assert ( ! ( key . keyFlags & RSTLV_KEY_TYPE_FULL ) ) ;
2014-05-17 09:50:40 -04:00
const unsigned char * keyptr = ( const unsigned char * ) key . keyData . bin_data ;
long keylen = key . keyData . bin_len ;
/* extract admin key */
RSA * rsakey = d2i_RSAPublicKey ( NULL , & ( keyptr ) , keylen ) ;
return rsakey ;
2012-08-12 16:46:21 -04:00
}
2016-06-02 23:47:57 -04:00
static void setRSAPublicKeyData ( RsTlvPublicRSAKey & key , RSA * rsa_pub )
2014-05-17 09:50:40 -04:00
{
2016-06-02 23:47:57 -04:00
assert ( ! ( key . keyFlags & RSTLV_KEY_TYPE_FULL ) ) ;
2014-05-17 09:50:40 -04:00
unsigned char * data = NULL ; // this works for OpenSSL > 0.9.7
int reqspace = i2d_RSAPublicKey ( rsa_pub , & data ) ;
key . keyData . setBinData ( data , reqspace ) ;
key . keyId = getRsaKeyFingerprint ( rsa_pub ) ;
2012-08-12 16:46:21 -04:00
2016-06-02 23:47:57 -04:00
free ( data ) ;
2014-05-17 09:50:40 -04:00
}
2016-06-16 21:27:28 -04:00
static void setRSAPrivateKeyData ( RsTlvPrivateRSAKey & key , RSA * rsa_priv )
2016-06-02 23:47:57 -04:00
{
assert ( key . keyFlags & RSTLV_KEY_TYPE_FULL ) ;
2016-06-16 21:27:28 -04:00
2016-06-02 23:47:57 -04:00
unsigned char * data = NULL ; // this works for OpenSSL > 0.9.7
2016-06-16 21:27:28 -04:00
int reqspace = i2d_RSAPrivateKey ( rsa_priv , & data ) ;
2016-06-02 23:47:57 -04:00
key . keyData . setBinData ( data , reqspace ) ;
2016-06-16 21:27:28 -04:00
key . keyId = getRsaKeyFingerprint ( rsa_priv ) ;
2016-06-02 23:47:57 -04:00
free ( data ) ;
}
2016-06-17 22:21:06 -04:00
bool GxsSecurity : : checkFingerprint ( const RsTlvPublicRSAKey & key )
{
RSA * rsa_pub = : : extractPublicKey ( key ) ;
bool res = ( key . keyId = = getRsaKeyFingerprint ( rsa_pub ) ) ;
RSA_free ( rsa_pub ) ;
return res ;
}
2016-06-02 23:47:57 -04:00
bool GxsSecurity : : checkPrivateKey ( const RsTlvPrivateRSAKey & key )
2015-07-15 18:20:00 -04:00
{
2016-06-16 23:10:13 -04:00
# ifdef GXS_SECURITY_DEBUG
2015-07-15 18:20:00 -04:00
std : : cerr < < " Checking private key " < < key . keyId < < " ... " < < std : : endl ;
2016-06-16 23:10:13 -04:00
# endif
2015-07-15 18:20:00 -04:00
if ( ( key . keyFlags & RSTLV_KEY_TYPE_MASK ) ! = RSTLV_KEY_TYPE_FULL )
{
std : : cerr < < " (WW) GxsSecurity::checkPrivateKey(): private key has wrong flags " < < std : : hex < < ( key . keyFlags & RSTLV_KEY_TYPE_MASK ) < < std : : dec < < " . This is unexpected. " < < std : : endl ;
return false ;
}
RSA * rsa_prv = : : extractPrivateKey ( key ) ;
if ( rsa_prv = = NULL )
{
std : : cerr < < " (WW) GxsSecurity::checkPrivateKey(): no private key can be extracted from key ID " < < key . keyId < < " . Key is corrupted? " < < std : : endl ;
return false ;
}
RSA * rsa_pub = RSAPublicKey_dup ( rsa_prv ) ;
RSA_free ( rsa_prv ) ;
if ( rsa_pub = = NULL )
{
std : : cerr < < " (WW) GxsSecurity::checkPrivateKey(): no public key can be extracted from key ID " < < key . keyId < < " . Key is corrupted? " < < std : : endl ;
return false ;
}
RsGxsId recomputed_key_id = getRsaKeyFingerprint ( rsa_pub ) ;
if ( recomputed_key_id ! = key . keyId )
{
2016-06-17 20:46:24 -04:00
if ( key . keyId = = getRsaKeyFingerprint_old_insecure_method ( rsa_pub ) )
{
2016-06-17 22:21:06 -04:00
# ifdef GXS_SECURITY_DEBUG
std : : cerr < < " (WW) fingerprint of key " < < key . keyId < < " was derived using old---insecure---format. It can be faked easily. You should get rid of this key! " < < std : : endl ;
# endif
2016-06-17 20:46:24 -04:00
RSA_free ( rsa_pub ) ;
2016-06-17 22:21:06 -04:00
// The policy is to *accept* these private keys, but the public key that corresponds will be rejected anyway, as it can easily be faked.
2016-06-17 20:46:24 -04:00
return true ;
}
2016-06-17 22:21:06 -04:00
else
{
std : : cerr < < " (WW) GxsSecurity::checkPrivateKey(): key " < < key . keyId < < " has wrong fingerprint " < < recomputed_key_id < < std : : endl ;
RSA_free ( rsa_pub ) ;
return false ;
}
2015-07-15 18:20:00 -04:00
}
2016-06-17 20:46:24 -04:00
RSA_free ( rsa_pub ) ;
2015-07-15 18:20:00 -04:00
return true ;
}
2016-06-17 22:21:06 -04:00
2016-06-02 23:47:57 -04:00
bool GxsSecurity : : checkPublicKey ( const RsTlvPublicRSAKey & key )
2015-07-15 18:20:00 -04:00
{
2016-06-16 23:10:13 -04:00
# ifdef GXS_SECURITY_DEBUG
2015-07-15 18:20:00 -04:00
std : : cerr < < " Checking public key " < < key . keyId < < " ... " < < std : : endl ;
2016-06-16 23:10:13 -04:00
# endif
2015-07-15 18:20:00 -04:00
if ( ( key . keyFlags & RSTLV_KEY_TYPE_MASK ) ! = RSTLV_KEY_TYPE_PUBLIC_ONLY )
{
std : : cerr < < " (WW) GxsSecurity::checkPublicKey(): public key has wrong flags " < < std : : hex < < ( key . keyFlags & RSTLV_KEY_TYPE_MASK ) < < std : : dec < < " . This is unexpected. " < < std : : endl ;
return false ;
}
2016-06-16 23:06:07 -04:00
// try to extract private key
const unsigned char * keyptr = ( const unsigned char * ) key . keyData . bin_data ;
long keylen = key . keyData . bin_len ;
RSA * rsa_prv = d2i_RSAPrivateKey ( NULL , & ( keyptr ) , keylen ) ;
if ( rsa_prv ! = NULL )
{
std : : cerr < < " (SS) GxsSecurity::checkPublicKey(): public key with ID " < < key . keyId < < " actually is a Private key!!! " < < std : : endl ;
RSA_free ( rsa_prv ) ;
return false ;
}
2015-07-15 18:20:00 -04:00
RSA * rsa_pub = : : extractPublicKey ( key ) ;
if ( rsa_pub = = NULL )
{
std : : cerr < < " (WW) GxsSecurity::checkPublicKey(): no public key can be extracted from key ID " < < key . keyId < < " . Key is corrupted? " < < std : : endl ;
return false ;
}
RsGxsId recomputed_key_id = getRsaKeyFingerprint ( rsa_pub ) ;
if ( recomputed_key_id ! = key . keyId )
{
2016-06-17 20:46:24 -04:00
if ( key . keyId = = getRsaKeyFingerprint_old_insecure_method ( rsa_pub ) )
{
# ifdef GXS_SECURITY_DEBUG
std : : cerr < < " (WW) fingerprint was derived using old---insecure---format. It can be faked easily. " < < std : : endl ;
# endif
RSA_free ( rsa_pub ) ;
2016-06-17 22:21:06 -04:00
// The policy is to accept these public keys, but warn the owner, since they might be fake keys. They will be soon rejected here, by replacing
// the return value by false.
2016-06-17 20:46:24 -04:00
return true ;
}
else
std : : cerr < < " (WW) GxsSecurity::checkPublicKey(): key " < < key . keyId < < " has wrong fingerprint " < < recomputed_key_id < < " ! Key will be discarded. " < < std : : endl ;
RSA_free ( rsa_pub ) ;
2015-07-15 18:20:00 -04:00
return false ;
}
2016-06-17 20:46:24 -04:00
RSA_free ( rsa_pub ) ;
2015-07-15 18:20:00 -04:00
return true ;
}
2016-06-02 23:47:57 -04:00
bool GxsSecurity : : generateKeyPair ( RsTlvPublicRSAKey & public_key , RsTlvPrivateRSAKey & private_key )
2014-05-17 09:50:40 -04:00
{
// admin keys
2016-08-22 21:11:49 -04:00
BIGNUM * ebn = BN_new ( ) ;
BN_set_word ( ebn , 65537 ) ;
RSA * rsa = RSA_new ( ) ;
RSA_generate_key_ex ( rsa , 2048 , ebn , NULL ) ;
2014-05-17 09:50:40 -04:00
RSA * rsa_pub = RSAPublicKey_dup ( rsa ) ;
2016-06-16 21:27:28 -04:00
public_key . keyFlags = RSTLV_KEY_TYPE_PUBLIC_ONLY ;
private_key . keyFlags = RSTLV_KEY_TYPE_FULL ;
2014-05-17 09:50:40 -04:00
2014-11-15 15:24:56 -05:00
setRSAPublicKeyData ( public_key , rsa_pub ) ;
setRSAPrivateKeyData ( private_key , rsa ) ;
2014-05-17 09:50:40 -04:00
2014-11-15 15:24:56 -05:00
public_key . startTS = time ( NULL ) ;
public_key . endTS = public_key . startTS + 60 * 60 * 24 * 365 * 5 ; /* approx 5 years */
2014-05-17 09:50:40 -04:00
2014-11-15 15:24:56 -05:00
private_key . startTS = public_key . startTS ;
private_key . endTS = 0 ; /* no end */
2014-05-17 09:50:40 -04:00
// clean up
RSA_free ( rsa ) ;
RSA_free ( rsa_pub ) ;
2016-06-16 23:06:07 -04:00
if ( ! ( private_key . checkKey ( ) & & public_key . checkKey ( ) ) )
2016-06-02 23:47:57 -04:00
{
std : : cerr < < " (EE) ERROR while generating keys. Something inconsistent in flags. This is probably a bad sign! " < < std : : endl ;
return false ;
}
return true ;
2014-05-17 09:50:40 -04:00
}
2016-06-02 23:47:57 -04:00
bool GxsSecurity : : extractPublicKey ( const RsTlvPrivateRSAKey & private_key , RsTlvPublicRSAKey & public_key )
2014-05-17 09:50:40 -04:00
{
2014-11-15 15:24:56 -05:00
public_key . TlvClear ( ) ;
if ( ! ( private_key . keyFlags & RSTLV_KEY_TYPE_FULL ) )
return false ;
2014-05-17 09:50:40 -04:00
2014-11-15 15:24:56 -05:00
RSA * rsaPrivKey = extractPrivateKey ( private_key ) ;
2014-05-17 09:50:40 -04:00
2014-11-15 15:24:56 -05:00
if ( ! rsaPrivKey )
return false ;
2014-05-17 09:50:40 -04:00
2014-11-15 15:24:56 -05:00
RSA * rsaPubKey = RSAPublicKey_dup ( rsaPrivKey ) ;
RSA_free ( rsaPrivKey ) ;
2014-05-17 09:50:40 -04:00
2014-11-15 15:24:56 -05:00
if ( ! rsaPubKey )
return false ;
2014-05-17 09:50:40 -04:00
2014-11-15 15:24:56 -05:00
setRSAPublicKeyData ( public_key , rsaPubKey ) ;
RSA_free ( rsaPubKey ) ;
2014-05-17 09:50:40 -04:00
2014-11-15 15:24:56 -05:00
public_key . keyFlags = private_key . keyFlags & ( RSTLV_KEY_DISTRIB_MASK ) ; // keep the distrib flags
public_key . keyFlags | = RSTLV_KEY_TYPE_PUBLIC_ONLY ;
public_key . startTS = private_key . startTS ;
public_key . endTS = public_key . startTS + 60 * 60 * 24 * 365 * 5 ; /* approx 5 years */
2014-05-17 09:50:40 -04:00
2014-11-15 15:54:42 -05:00
// This code fixes a problem of old RSA keys where the fingerprint wasn't computed using SHA1(n,e) but
// using the first bytes of n (ouuuuch!). Still, these keys are valid and should produce a correct
// fingerprint. So we replace the public key fingerprint (that is normally recomputed) with the FP of
// the private key.
if ( public_key . keyId ! = private_key . keyId )
{
std : : cerr < < std : : endl ;
std : : cerr < < " WARNING: GXS ID key pair " < < private_key . keyId < < " has inconsistent fingerprint. This is an old key " < < std : : endl ;
2016-02-20 17:53:03 -05:00
std : : cerr < < " that is unsecure (can be faked easily). You should delete it! " < < std : : endl ;
2014-11-15 15:54:42 -05:00
std : : cerr < < std : : endl ;
public_key . keyId = private_key . keyId ;
}
2014-11-15 15:24:56 -05:00
return true ;
2014-05-17 09:50:40 -04:00
}
2016-06-02 23:47:57 -04:00
bool GxsSecurity : : getSignature ( const char * data , uint32_t data_len , const RsTlvPrivateRSAKey & privKey , RsTlvKeySignature & sign )
2012-11-02 19:35:10 -04:00
{
2016-06-16 21:27:28 -04:00
RSA * rsa_priv = extractPrivateKey ( privKey ) ;
2014-05-08 05:20:25 -04:00
2016-06-16 21:27:28 -04:00
if ( ! rsa_priv )
2014-05-08 05:20:25 -04:00
{
2014-06-12 06:28:23 -04:00
std : : cerr < < " GxsSecurity::getSignature(): Cannot create signature. Keydata is incomplete. " < < std : : endl ;
2014-05-08 05:20:25 -04:00
return false ;
}
2016-06-16 21:27:28 -04:00
EVP_PKEY * key_priv = EVP_PKEY_new ( ) ;
EVP_PKEY_assign_RSA ( key_priv , rsa_priv ) ;
2012-11-02 19:35:10 -04:00
/* calc and check signature */
EVP_MD_CTX * mdctx = EVP_MD_CTX_create ( ) ;
bool ok = EVP_SignInit ( mdctx , EVP_sha1 ( ) ) = = 1 ;
ok & = EVP_SignUpdate ( mdctx , data , data_len ) = = 1 ;
2016-06-16 21:27:28 -04:00
unsigned int siglen = EVP_PKEY_size ( key_priv ) ;
2012-11-02 19:35:10 -04:00
unsigned char sigbuf [ siglen ] ;
2016-06-16 21:27:28 -04:00
ok & = EVP_SignFinal ( mdctx , sigbuf , & siglen , key_priv ) = = 1 ;
2012-11-02 19:35:10 -04:00
// clean up
EVP_MD_CTX_destroy ( mdctx ) ;
2016-06-16 21:27:28 -04:00
EVP_PKEY_free ( key_priv ) ;
2012-11-02 19:35:10 -04:00
sign . signData . setBinData ( sigbuf , siglen ) ;
2014-06-12 06:28:23 -04:00
sign . keyId = RsGxsId ( privKey . keyId ) ;
2012-11-02 19:35:10 -04:00
return ok ;
}
2012-08-12 16:46:21 -04:00
2016-06-02 23:47:57 -04:00
bool GxsSecurity : : validateSignature ( const char * data , uint32_t data_len , const RsTlvPublicRSAKey & key , const RsTlvKeySignature & signature )
2014-03-29 10:18:05 -04:00
{
2016-06-02 23:47:57 -04:00
assert ( ! ( key . keyFlags & RSTLV_KEY_TYPE_FULL ) ) ;
RSA * rsakey = : : extractPublicKey ( key ) ;
2014-03-29 10:18:05 -04:00
2014-05-08 05:20:25 -04:00
if ( ! rsakey )
{
std : : cerr < < " GxsSecurity::validateSignature(): Cannot validate signature. Keydata is incomplete. " < < std : : endl ;
2014-06-12 06:28:23 -04:00
key . print ( std : : cerr , 0 ) ;
2014-05-08 05:20:25 -04:00
return false ;
}
2014-03-29 10:18:05 -04:00
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 , data , data_len ) ;
int signOk = EVP_VerifyFinal ( mdctx , ( unsigned char * ) signature . signData . bin_data , signature . signData . bin_len , signKey ) ;
/* clean up */
EVP_PKEY_free ( signKey ) ;
EVP_MD_CTX_destroy ( mdctx ) ;
return signOk ;
}
2016-06-02 23:47:57 -04:00
bool GxsSecurity : : validateNxsMsg ( const RsNxsMsg & msg , const RsTlvKeySignature & sign , const RsTlvPublicRSAKey & key )
2012-08-12 16:46:21 -04:00
{
2012-11-10 18:42:38 -05:00
# 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
2012-10-23 17:52:51 -04:00
2012-11-10 18:42:38 -05:00
RsGxsMsgMetaData & msgMeta = * ( msg . metaData ) ;
2012-10-23 17:52:51 -04:00
// /********************* check signature *******************/
2012-11-10 18:42:38 -05:00
/* check signature timeperiod */
2015-05-19 17:28:46 -04:00
if ( ( msgMeta . mPublishTs < key . startTS ) | | ( key . endTS ! = 0 & & msgMeta . mPublishTs > key . endTS ) )
2012-11-10 18:42:38 -05:00
{
# ifdef GXS_SECURITY_DEBUG
std : : cerr < < " GxsSecurity::validateNxsMsg() TS out of range " ;
std : : cerr < < std : : endl ;
# endif
return false ;
}
/* decode key */
const unsigned char * keyptr = ( const unsigned char * ) key . keyData . bin_data ;
long keylen = key . keyData . bin_len ;
unsigned int siglen = sign . signData . bin_len ;
unsigned char * sigbuf = ( unsigned char * ) sign . signData . bin_data ;
# ifdef DISTRIB_DEBUG
std : : cerr < < " GxsSecurity::validateNxsMsg() Decode Key " ;
std : : cerr < < " keylen: " < < keylen < < " siglen: " < < siglen ;
std : : cerr < < std : : endl ;
# endif
/* extract admin key */
2015-05-19 17:28:46 -04:00
RSA * rsakey = ( key . keyFlags & RSTLV_KEY_TYPE_FULL ) ? ( d2i_RSAPrivateKey ( NULL , & ( keyptr ) , keylen ) ) : ( d2i_RSAPublicKey ( NULL , & ( keyptr ) , keylen ) ) ;
2012-11-10 18:42:38 -05:00
if ( ! rsakey )
{
# ifdef GXS_SECURITY_DEBUG
std : : cerr < < " GxsSecurity::validateNxsMsg() " ;
std : : cerr < < " Invalid RSA Key " ;
std : : cerr < < std : : endl ;
key . print ( std : : cerr , 10 ) ;
# endif
}
RsTlvKeySignatureSet signSet = msgMeta . signSet ;
msgMeta . signSet . TlvClear ( ) ;
2013-02-07 18:04:16 -05:00
RsGxsMessageId msgId = msgMeta . mMsgId , origMsgId = msgMeta . mOrigMsgId ;
msgMeta . mOrigMsgId . clear ( ) ;
msgMeta . mMsgId . clear ( ) ;
2016-04-30 17:25:24 -04:00
int signOk = 0 ;
2013-02-07 18:04:16 -05:00
2016-04-30 17:25:24 -04:00
{
EVP_PKEY * signKey = EVP_PKEY_new ( ) ;
EVP_PKEY_assign_RSA ( signKey , rsakey ) ;
EVP_MD_CTX * mdctx = EVP_MD_CTX_create ( ) ;
2012-11-10 18:42:38 -05:00
2016-04-30 17:25:24 -04:00
uint32_t metaDataLen = msgMeta . serial_size ( ) ;
uint32_t allMsgDataLen = metaDataLen + msg . msg . bin_len ;
2012-11-10 18:42:38 -05:00
2016-04-30 17:25:24 -04:00
RsTemporaryMemory metaData ( metaDataLen ) ;
RsTemporaryMemory allMsgData ( allMsgDataLen ) ;
2012-11-10 18:42:38 -05:00
2016-04-30 17:25:24 -04:00
if ( ! metaData | | ! allMsgData )
return false ;
2016-04-30 17:33:47 -04:00
2016-04-30 17:25:24 -04:00
msgMeta . serialise ( metaData , & metaDataLen ) ;
2012-11-10 18:42:38 -05:00
2016-04-30 17:25:24 -04:00
// 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 ) ;
2012-11-10 18:42:38 -05:00
2016-04-30 17:25:24 -04:00
/* calc and check signature */
2012-11-10 18:42:38 -05:00
2016-04-30 17:25:24 -04:00
EVP_VerifyInit ( mdctx , EVP_sha1 ( ) ) ;
EVP_VerifyUpdate ( mdctx , allMsgData , allMsgDataLen ) ;
2012-11-10 18:42:38 -05:00
2016-04-30 17:25:24 -04:00
signOk = EVP_VerifyFinal ( mdctx , sigbuf , siglen , signKey ) ;
2014-05-15 17:55:34 -04:00
2016-04-30 17:25:24 -04:00
/* clean up */
EVP_PKEY_free ( signKey ) ;
EVP_MD_CTX_destroy ( mdctx ) ;
}
2012-11-10 18:42:38 -05:00
2013-02-07 18:04:16 -05:00
msgMeta . mOrigMsgId = origMsgId ;
msgMeta . mMsgId = msgId ;
msgMeta . signSet = signSet ;
2012-11-10 18:42:38 -05:00
if ( signOk = = 1 )
{
# ifdef GXS_SECURITY_DEBUG
std : : cerr < < " GxsSecurity::validateNxsMsg() Signature OK " ;
std : : cerr < < std : : endl ;
# endif
return true ;
}
# ifdef GXS_SECURITY_DEBUG
std : : cerr < < " GxsSecurity::validateNxsMsg() Signature invalid " ;
std : : cerr < < std : : endl ;
# endif
2012-10-23 17:52:51 -04:00
2012-11-02 19:35:10 -04:00
return false ;
2012-08-12 16:46:21 -04:00
}
2016-06-02 23:47:57 -04:00
bool GxsSecurity : : encrypt ( uint8_t * & out , uint32_t & outlen , const uint8_t * in , uint32_t inlen , const RsTlvPublicRSAKey & key )
2012-08-12 16:46:21 -04:00
{
# ifdef DISTRIB_DEBUG
2014-03-29 10:18:05 -04:00
std : : cerr < < " GxsSecurity::encrypt() " < < std : : endl ;
2012-08-12 16:46:21 -04:00
# endif
2016-01-01 21:37:27 -05:00
// Encrypts (in,inlen) into (out,outlen) using the given RSA public key.
// The format of the encrypted data is:
//
// [--- Encrypted session key length ---|--- Encrypted session key ---|--- IV ---|---- Encrypted data ---]
//
2012-08-12 16:46:21 -04:00
2016-04-21 19:46:47 -04:00
out = NULL ;
2016-01-01 21:37:27 -05:00
RSA * tmpkey = : : extractPublicKey ( key ) ;
RSA * rsa_publish_pub = RSAPublicKey_dup ( tmpkey ) ;
RSA_free ( tmpkey ) ;
2015-06-22 17:35:39 -04:00
2014-03-29 10:18:05 -04:00
EVP_PKEY * public_key = NULL ;
2012-08-12 16:46:21 -04:00
2014-03-29 10:18:05 -04:00
//RSA* rsa_publish = EVP_PKEY_get1_RSA(privateKey);
//rsa_publish_pub = RSAPublicKey_dup(rsa_publish);
2012-08-12 16:46:21 -04:00
2014-03-29 10:18:05 -04:00
if ( rsa_publish_pub ! = NULL )
{
public_key = EVP_PKEY_new ( ) ;
EVP_PKEY_assign_RSA ( public_key , rsa_publish_pub ) ;
2014-05-15 17:55:34 -04:00
}
else
{
2012-08-12 16:46:21 -04:00
# ifdef DISTRIB_DEBUG
2014-03-29 10:18:05 -04:00
std : : cerr < < " GxsSecurity(): Could not generate publish key " < < grpId
2016-01-01 21:37:27 -05:00
< < std : : endl ;
2012-08-12 16:46:21 -04:00
# endif
2014-03-29 10:18:05 -04:00
return false ;
}
2012-08-12 16:46:21 -04:00
2014-03-29 10:18:05 -04:00
EVP_CIPHER_CTX ctx ;
int eklen , net_ekl ;
unsigned char * ek ;
unsigned char iv [ EVP_MAX_IV_LENGTH ] ;
EVP_CIPHER_CTX_init ( & ctx ) ;
int out_currOffset = 0 ;
int out_offset = 0 ;
2012-08-12 16:46:21 -04:00
2014-03-29 10:18:05 -04:00
int max_evp_key_size = EVP_PKEY_size ( public_key ) ;
2016-01-12 21:43:04 -05:00
ek = ( unsigned char * ) rs_malloc ( max_evp_key_size ) ;
2016-01-11 23:49:00 -05:00
if ( ek = = NULL )
return false ;
2014-03-29 10:18:05 -04:00
const EVP_CIPHER * cipher = EVP_aes_128_cbc ( ) ;
int cipher_block_size = EVP_CIPHER_block_size ( cipher ) ;
int size_net_ekl = sizeof ( net_ekl ) ;
2012-08-12 16:46:21 -04:00
2014-03-29 10:18:05 -04:00
int max_outlen = inlen + cipher_block_size + EVP_MAX_IV_LENGTH + max_evp_key_size + size_net_ekl ;
2012-08-12 16:46:21 -04:00
2014-03-29 10:18:05 -04:00
// intialize context and send store encrypted cipher in ek
if ( ! EVP_SealInit ( & ctx , EVP_aes_128_cbc ( ) , & ek , & eklen , iv , & public_key , 1 ) ) return false ;
2012-08-12 16:46:21 -04:00
2014-03-29 10:18:05 -04:00
// now assign memory to out accounting for data, and cipher block size, key length, and key length val
2016-10-22 17:48:19 -04:00
out = ( uint8_t * ) rs_malloc ( inlen + cipher_block_size + size_net_ekl + eklen + EVP_MAX_IV_LENGTH ) ;
2015-01-23 10:16:04 -05:00
2016-10-22 17:48:19 -04:00
if ( out = = NULL )
return false ;
2012-08-12 16:46:21 -04:00
2014-03-29 10:18:05 -04:00
net_ekl = htonl ( eklen ) ;
memcpy ( ( unsigned char * ) out + out_offset , & net_ekl , size_net_ekl ) ;
out_offset + = size_net_ekl ;
2012-08-12 16:46:21 -04:00
2014-03-29 10:18:05 -04:00
memcpy ( ( unsigned char * ) out + out_offset , ek , eklen ) ;
out_offset + = eklen ;
2012-08-12 16:46:21 -04:00
2014-03-29 10:18:05 -04:00
memcpy ( ( unsigned char * ) out + out_offset , iv , EVP_MAX_IV_LENGTH ) ;
out_offset + = EVP_MAX_IV_LENGTH ;
2012-08-12 16:46:21 -04:00
2014-03-29 10:18:05 -04:00
// now encrypt actual data
2014-05-15 17:55:34 -04:00
if ( ! EVP_SealUpdate ( & ctx , ( unsigned char * ) out + out_offset , & out_currOffset , ( unsigned char * ) in , inlen ) )
{
2016-01-01 21:37:27 -05:00
free ( out ) ;
2014-05-15 17:55:34 -04:00
out = NULL ;
return false ;
}
2012-08-12 16:46:21 -04:00
2014-03-29 10:18:05 -04:00
// move along to partial block space
out_offset + = out_currOffset ;
2012-08-12 16:46:21 -04:00
2014-03-29 10:18:05 -04:00
// add padding
2014-05-15 17:55:34 -04:00
if ( ! EVP_SealFinal ( & ctx , ( unsigned char * ) out + out_offset , & out_currOffset ) )
{
2016-01-01 21:37:27 -05:00
free ( out ) ;
2014-05-15 17:55:34 -04:00
out = NULL ;
return false ;
}
2012-08-12 16:46:21 -04:00
2014-03-29 10:18:05 -04:00
// move to end
out_offset + = out_currOffset ;
2016-04-21 19:41:21 -04:00
2014-03-29 10:18:05 -04:00
// make sure offset has not gone passed valid memory bounds
2014-05-15 17:55:34 -04:00
if ( out_offset > max_outlen )
{
2016-01-01 21:37:27 -05:00
free ( out ) ;
2014-05-15 17:55:34 -04:00
out = NULL ;
return false ;
}
2012-08-12 16:46:21 -04:00
2014-03-29 10:18:05 -04:00
// free encrypted key data
free ( ek ) ;
2012-08-12 16:46:21 -04:00
2016-04-21 19:41:21 -04:00
EVP_CIPHER_CTX_cleanup ( & ctx ) ;
2014-03-29 10:18:05 -04:00
outlen = out_offset ;
return true ;
2012-08-12 16:46:21 -04:00
}
2016-06-02 23:47:57 -04:00
bool GxsSecurity : : encrypt ( uint8_t * & out , uint32_t & outlen , const uint8_t * in , uint32_t inlen , const std : : vector < RsTlvPublicRSAKey > & keys )
2016-02-16 22:36:22 -05:00
{
# ifdef DISTRIB_DEBUG
std : : cerr < < " GxsSecurity::encrypt() " < < std : : endl ;
# endif
// Encrypts (in,inlen) into (out,outlen) using the given RSA public key.
// The format of the encrypted data is:
//
2016-02-18 23:38:07 -05:00
// [--- ID ---|--- number of encrypted keys---| n * (--- Encrypted session keys ---) |--- IV ---|---- Encrypted data ---]
// 2 bytes 2 byte = n 256 bytes EVP_MAX_IV_LENGTH Rest of packet
2016-02-16 22:36:22 -05:00
//
out = NULL ;
2016-04-21 19:41:21 -04:00
EVP_CIPHER_CTX ctx ;
EVP_CIPHER_CTX_init ( & ctx ) ;
2016-04-22 17:30:55 -04:00
std : : vector < EVP_PKEY * > public_keys ( keys . size ( ) , NULL ) ;
2016-02-16 22:36:22 -05:00
try
{
for ( uint32_t i = 0 ; i < keys . size ( ) ; + + i )
{
RSA * tmpkey = : : extractPublicKey ( keys [ i ] ) ;
RSA * rsa_publish_pub = RSAPublicKey_dup ( tmpkey ) ;
RSA_free ( tmpkey ) ;
if ( rsa_publish_pub ! = NULL )
{
public_keys [ i ] = EVP_PKEY_new ( ) ;
EVP_PKEY_assign_RSA ( public_keys [ i ] , rsa_publish_pub ) ;
}
else
{
std : : cerr < < " GxsSecurity(): Could not generate public key for key id " < < keys [ i ] . keyId < < std : : endl ;
throw std : : runtime_error ( " Cannot extract public key " ) ;
}
}
unsigned char iv [ EVP_MAX_IV_LENGTH ] ;
std : : vector < unsigned char * > ek ( keys . size ( ) , NULL ) ;
std : : vector < int > eklen ( keys . size ( ) , 0 ) ;
for ( uint32_t i = 0 ; i < keys . size ( ) ; + + i )
{
int max_evp_key_size = EVP_PKEY_size ( public_keys [ i ] ) ;
2016-02-18 23:38:07 -05:00
if ( max_evp_key_size ! = MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE )
throw std : : runtime_error ( " EVP_PKEY_size should be equal to 256. It's not! " ) ;
2016-02-16 22:36:22 -05:00
ek [ i ] = ( unsigned char * ) rs_malloc ( max_evp_key_size ) ;
if ( ek [ i ] = = NULL )
throw std : : runtime_error ( " malloc error on encrypted keys " ) ;
}
const EVP_CIPHER * cipher = EVP_aes_128_cbc ( ) ;
int cipher_block_size = EVP_CIPHER_block_size ( cipher ) ;
// intialize context and send store encrypted cipher in ek
2016-02-18 23:38:07 -05:00
if ( ! EVP_SealInit ( & ctx , EVP_aes_128_cbc ( ) , ek . data ( ) , eklen . data ( ) , iv , public_keys . data ( ) , keys . size ( ) ) )
2016-02-16 22:36:22 -05:00
return false ;
2016-04-22 17:30:55 -04:00
// now we can release the encryption keys
for ( uint32_t i = 0 ; i < public_keys . size ( ) ; + + i )
EVP_PKEY_free ( public_keys [ i ] ) ;
public_keys . clear ( ) ;
2016-02-18 23:38:07 -05:00
int total_ek_size = MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE * keys . size ( ) ;
2016-02-16 22:36:22 -05:00
2016-02-18 21:30:52 -05:00
int max_outlen = MULTI_ENCRYPTION_FORMAT_v001_HEADER_SIZE + MULTI_ENCRYPTION_FORMAT_v001_NUMBER_OF_KEYS_SIZE + total_ek_size + EVP_MAX_IV_LENGTH + ( inlen + cipher_block_size ) ;
2016-02-16 22:36:22 -05:00
// now assign memory to out accounting for data, and cipher block size, key length, and key length val
out = ( uint8_t * ) rs_malloc ( max_outlen ) ;
if ( out = = NULL )
return false ;
int out_offset = 0 ;
// header
2016-02-18 21:30:52 -05:00
out [ out_offset + + ] = MULTI_ENCRYPTION_FORMAT_v001_HEADER & 0xff ;
out [ out_offset + + ] = ( MULTI_ENCRYPTION_FORMAT_v001_HEADER > > 8 ) & 0xff ;
2016-02-16 22:36:22 -05:00
// number of keys
out [ out_offset + + ] = keys . size ( ) & 0xff ;
out [ out_offset + + ] = ( keys . size ( ) > > 8 ) & 0xff ;
// encrypted keys, each preceeded with its length
for ( uint32_t i = 0 ; i < keys . size ( ) ; + + i )
{
2016-02-18 23:38:07 -05:00
if ( eklen [ i ] ! = MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE )
2016-02-16 22:36:22 -05:00
{
std : : cerr < < " (EE) eklen[i]= " < < eklen [ i ] < < " in " < < __PRETTY_FUNCTION__ < < " for key id " < < keys [ i ] . keyId < < " . This is unexpected. Cannot encrypt. " < < std : : endl ;
throw std : : runtime_error ( " Encryption error " ) ;
}
memcpy ( ( unsigned char * ) out + out_offset , ek [ i ] , eklen [ i ] ) ;
out_offset + = eklen [ i ] ;
}
memcpy ( ( unsigned char * ) out + out_offset , iv , EVP_MAX_IV_LENGTH ) ;
out_offset + = EVP_MAX_IV_LENGTH ;
int out_currOffset = 0 ;
// now encrypt actual data
if ( ! EVP_SealUpdate ( & ctx , ( unsigned char * ) out + out_offset , & out_currOffset , ( unsigned char * ) in , inlen ) )
throw std : : runtime_error ( " Encryption error in SealUpdate() " ) ;
// move along to partial block space
out_offset + = out_currOffset ;
// add padding
if ( ! EVP_SealFinal ( & ctx , ( unsigned char * ) out + out_offset , & out_currOffset ) )
throw std : : runtime_error ( " Encryption error in SealFinal() " ) ;
// move to end
out_offset + = out_currOffset ;
// make sure offset has not gone passed valid memory bounds
if ( out_offset > max_outlen )
throw std : : runtime_error ( " Memory used by encryption exceeds allocated memory block " ) ;
// free encrypted key data
for ( uint32_t i = 0 ; i < keys . size ( ) ; + + i )
if ( ek [ i ] ) free ( ek [ i ] ) ;
outlen = out_offset ;
2016-04-21 19:41:21 -04:00
EVP_CIPHER_CTX_cleanup ( & ctx ) ;
2016-02-16 22:36:22 -05:00
return true ;
}
catch ( std : : exception & e )
{
std : : cerr < < " (EE) Exception caught while encrypting: " < < e . what ( ) < < std : : endl ;
2016-04-21 19:41:21 -04:00
EVP_CIPHER_CTX_cleanup ( & ctx ) ;
2016-02-16 22:36:22 -05:00
if ( out ) free ( out ) ;
out = NULL ;
2016-04-22 17:30:55 -04:00
for ( uint32_t i = 0 ; i < public_keys . size ( ) ; + + i )
EVP_PKEY_free ( public_keys [ i ] ) ;
public_keys . clear ( ) ;
2016-02-16 22:36:22 -05:00
return false ;
}
}
2016-02-18 21:30:52 -05:00
2016-06-02 23:47:57 -04:00
bool GxsSecurity : : decrypt ( uint8_t * & out , uint32_t & outlen , const uint8_t * in , uint32_t inlen , const RsTlvPrivateRSAKey & key )
2012-08-12 16:46:21 -04:00
{
2016-01-01 21:37:27 -05:00
// Decrypts (in,inlen) into (out,outlen) using the given RSA public key.
// The format of the encrypted data (in) is:
//
// [--- Encrypted session key length ---|--- Encrypted session key ---|--- IV ---|---- Encrypted data ---]
//
// This method can be used to decrypt multi-encrypted data, if passing he correct encrypted key block (corresponding to the given key)
2012-08-12 16:46:21 -04:00
2016-04-21 19:46:47 -04:00
out = NULL ;
2016-02-20 17:53:03 -05:00
# ifdef GXS_SECURITY_DEBUG
2014-03-29 10:18:05 -04:00
std : : cerr < < " GxsSecurity::decrypt() " < < std : : endl ;
2012-08-12 16:46:21 -04:00
# endif
2016-01-01 21:37:27 -05:00
RSA * rsa_publish = extractPrivateKey ( key ) ;
2014-03-29 10:18:05 -04:00
EVP_PKEY * privateKey = NULL ;
//RSA* rsa_publish = EVP_PKEY_get1_RSA(privateKey);
//rsa_publish_pub = RSAPublicKey_dup(rsa_publish);
if ( rsa_publish ! = NULL )
{
privateKey = EVP_PKEY_new ( ) ;
EVP_PKEY_assign_RSA ( privateKey , rsa_publish ) ;
}
else
{
2016-02-20 17:53:03 -05:00
# ifdef GXS_SECURITY_DEBUG
2014-03-29 10:18:05 -04:00
std : : cerr < < " GxsSecurity(): Could not generate publish key " < < grpId
< < std : : endl ;
# endif
return false ;
}
2012-08-12 16:46:21 -04:00
EVP_CIPHER_CTX ctx ;
int eklen = 0 , net_ekl = 0 ;
2016-01-12 21:43:04 -05:00
unsigned char * ek = ( unsigned char * ) rs_malloc ( EVP_PKEY_size ( privateKey ) ) ;
2016-01-11 23:49:00 -05:00
if ( ek = = NULL )
return false ;
2016-01-12 21:10:11 -05:00
2012-08-12 16:46:21 -04:00
unsigned char iv [ EVP_MAX_IV_LENGTH ] ;
EVP_CIPHER_CTX_init ( & ctx ) ;
int in_offset = 0 , out_currOffset = 0 ;
int size_net_ekl = sizeof ( net_ekl ) ;
memcpy ( & net_ekl , ( unsigned char * ) in , size_net_ekl ) ;
eklen = ntohl ( net_ekl ) ;
in_offset + = size_net_ekl ;
2015-01-05 14:26:50 -05:00
// Conservative limits to detect weird errors due to corrupted encoding.
2015-09-24 18:03:19 -04:00
if ( eklen < 0 | | eklen > 512 | | eklen + in_offset > ( int ) inlen )
2015-01-05 14:26:50 -05:00
{
std : : cerr < < " Error while deserialising encryption key length: eklen = " < < std : : dec < < eklen < < " . Giving up decryption. " < < std : : endl ;
free ( ek ) ;
return false ;
}
2014-09-14 15:23:23 -04:00
2012-08-12 16:46:21 -04:00
memcpy ( ek , ( unsigned char * ) in + in_offset , eklen ) ;
in_offset + = eklen ;
memcpy ( iv , ( unsigned char * ) in + in_offset , EVP_MAX_IV_LENGTH ) ;
in_offset + = EVP_MAX_IV_LENGTH ;
const EVP_CIPHER * cipher = EVP_aes_128_cbc ( ) ;
2015-10-01 23:37:50 -04:00
if ( ! EVP_OpenInit ( & ctx , cipher , ek , eklen , iv , privateKey ) )
{
std : : cerr < < " (EE) Cannot decrypt data. Most likely reason: private GXS key is missing. " < < std : : endl ;
return false ;
}
2012-08-12 16:46:21 -04:00
2016-02-18 21:30:52 -05:00
if ( inlen < ( uint32_t ) in_offset )
2014-05-15 17:55:34 -04:00
{
std : : cerr < < " Severe error in " < < __PRETTY_FUNCTION__ < < " : cannot encrypt. " < < std : : endl ;
return false ;
}
2016-01-12 21:43:04 -05:00
out = ( uint8_t * ) rs_malloc ( inlen - in_offset ) ;
2015-01-23 10:16:04 -05:00
if ( out = = NULL )
return false ;
2012-08-12 16:46:21 -04:00
2014-05-15 17:55:34 -04:00
if ( ! EVP_OpenUpdate ( & ctx , ( unsigned char * ) out , & out_currOffset , ( unsigned char * ) in + in_offset , inlen - in_offset ) )
{
2015-01-23 10:16:04 -05:00
free ( out ) ;
2014-05-15 17:55:34 -04:00
out = NULL ;
return false ;
}
2012-08-12 16:46:21 -04:00
2015-03-14 10:33:23 -04:00
outlen = out_currOffset ;
2012-08-12 16:46:21 -04:00
2014-05-15 17:55:34 -04:00
if ( ! EVP_OpenFinal ( & ctx , ( unsigned char * ) out + out_currOffset , & out_currOffset ) )
{
2015-01-23 10:16:04 -05:00
free ( out ) ;
2014-05-15 17:55:34 -04:00
out = NULL ;
return false ;
}
2012-08-12 16:46:21 -04:00
outlen + = out_currOffset ;
free ( ek ) ;
2016-04-21 19:41:21 -04:00
EVP_CIPHER_CTX_cleanup ( & ctx ) ;
2014-05-15 17:55:34 -04:00
return true ;
2012-08-12 16:46:21 -04:00
}
2016-06-02 23:47:57 -04:00
bool GxsSecurity : : decrypt ( uint8_t * & out , uint32_t & outlen , const uint8_t * in , uint32_t inlen , const std : : vector < RsTlvPrivateRSAKey > & keys )
2016-02-18 21:30:52 -05:00
{
// Decrypts (in,inlen) into (out,outlen) using one of the given RSA public keys, trying them all in a row.
// The format of the encrypted data is:
//
2016-02-18 23:38:07 -05:00
// [--- ID ---|--- number of encrypted keys---| n * (--- Encrypted session keys ---) |--- IV ---|---- Encrypted data ---]
// 2 bytes 2 byte = n 256 bytes EVP_MAX_IV_LENGTH Rest of packet
2016-02-18 21:30:52 -05:00
//
// This method can be used to decrypt multi-encrypted data, if passing he correct encrypted key block (corresponding to the given key)
# ifdef DISTRIB_DEBUG
std : : cerr < < " GxsSecurity::decrypt() " < < std : : endl ;
# endif
2016-04-21 19:41:21 -04:00
EVP_CIPHER_CTX ctx ;
EVP_CIPHER_CTX_init ( & ctx ) ;
2016-02-18 21:30:52 -05:00
try
{
2016-04-21 19:41:21 -04:00
out = NULL ;
2016-02-18 21:30:52 -05:00
// check that the input block has a valid format.
uint32_t offset = 0 ;
uint16_t format_id = in [ offset ] + ( in [ offset + 1 ] < < 8 ) ;
if ( format_id ! = MULTI_ENCRYPTION_FORMAT_v001_HEADER )
{
std : : cerr < < " Unrecognised format in encrypted block. Header id = " < < std : : hex < < format_id < < std : : dec < < std : : endl ;
throw std : : runtime_error ( " Unrecognised format in encrypted block. " ) ;
}
offset + = MULTI_ENCRYPTION_FORMAT_v001_HEADER_SIZE ;
// read number of encrypted keys
uint32_t number_of_keys = in [ offset ] + ( in [ offset + 1 ] < < 8 ) ;
offset + = MULTI_ENCRYPTION_FORMAT_v001_NUMBER_OF_KEYS_SIZE ;
// reach the actual data offset
uint32_t encrypted_keys_offset = offset ;
uint32_t encrypted_block_size = 0 ;
2016-02-18 23:38:07 -05:00
uint32_t IV_offset = offset + number_of_keys * MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE ;
uint32_t encrypted_block_offset = IV_offset + EVP_MAX_IV_LENGTH ;
2016-02-18 21:30:52 -05:00
// read IV offset
2016-02-18 23:38:07 -05:00
if ( encrypted_block_offset > = inlen )
throw std : : runtime_error ( " Offset error " ) ;
2016-02-18 21:30:52 -05:00
encrypted_block_size = inlen - encrypted_block_offset ;
2016-02-20 17:53:03 -05:00
# ifdef GXS_SECURITY_DEBUG
2016-02-18 21:30:52 -05:00
std : : cerr < < " number of keys in envelop: " < < number_of_keys < < std : : endl ;
std : : cerr < < " IV offset : " < < IV_offset < < std : : endl ;
std : : cerr < < " encrypted block offset : " < < encrypted_block_offset < < std : : endl ;
std : : cerr < < " encrypted block size : " < < encrypted_block_size < < std : : endl ;
2016-02-20 17:53:03 -05:00
# endif
2016-02-18 21:30:52 -05:00
// decrypt
bool succeed = false ;
for ( uint32_t j = 0 ; j < keys . size ( ) & & ! succeed ; + + j )
{
RSA * rsa_private = extractPrivateKey ( keys [ j ] ) ;
EVP_PKEY * privateKey = NULL ;
2016-02-20 17:53:03 -05:00
# ifdef GXS_SECURITY_DEBUG
2016-02-18 21:30:52 -05:00
std : : cerr < < " trying key " < < keys [ j ] . keyId < < std : : endl ;
2016-02-20 17:53:03 -05:00
# endif
2016-02-18 21:30:52 -05:00
if ( rsa_private ! = NULL )
{
privateKey = EVP_PKEY_new ( ) ;
EVP_PKEY_assign_RSA ( privateKey , rsa_private ) ;
}
else
{
RSA_free ( rsa_private ) ;
std : : cerr < < " (EE) Cannot extract private key from key Id " < < keys [ j ] . keyId < < " . This is a bug. Non owned key? " < < std : : endl ;
continue ;
}
for ( uint32_t i = 0 ; i < number_of_keys & & ! succeed ; + + i )
{
2016-02-18 23:38:07 -05:00
succeed = EVP_OpenInit ( & ctx , EVP_aes_128_cbc ( ) , in + encrypted_keys_offset + i * MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE , MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE , in + IV_offset , privateKey ) ;
2016-02-18 21:30:52 -05:00
2016-04-22 17:30:55 -04:00
if ( ! succeed )
EVP_CIPHER_CTX_cleanup ( & ctx ) ;
2016-02-20 17:53:03 -05:00
# ifdef GXS_SECURITY_DEBUG
2016-02-19 20:55:27 -05:00
std : : cerr < < " encrypted key at offset " < < encrypted_keys_offset + i * MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE < < " : " < < succeed < < std : : endl ;
2016-02-20 17:53:03 -05:00
# endif
2016-02-18 21:30:52 -05:00
}
EVP_PKEY_free ( privateKey ) ;
}
if ( ! succeed )
throw std : : runtime_error ( " No matching key available. " ) ;
2016-02-20 17:53:03 -05:00
# ifdef GXS_SECURITY_DEBUG
2016-02-18 21:30:52 -05:00
std : : cerr < < " now decrypting with the matching key. " < < std : : endl ;
2016-02-20 17:53:03 -05:00
# endif
2016-02-18 21:30:52 -05:00
out = ( uint8_t * ) rs_malloc ( encrypted_block_size ) ;
if ( out = = NULL )
throw std : : runtime_error ( " Memory allocation error " ) ;
int out_currOffset = 0 ;
2012-08-12 16:46:21 -04:00
2016-02-18 21:30:52 -05:00
if ( ! EVP_OpenUpdate ( & ctx , ( unsigned char * ) out , & out_currOffset , ( unsigned char * ) in + encrypted_block_offset , encrypted_block_size ) )
throw std : : runtime_error ( " Decryption error in EVP_OpenUpdate " ) ;
outlen = out_currOffset ;
if ( ! EVP_OpenFinal ( & ctx , ( unsigned char * ) out + out_currOffset , & out_currOffset ) )
throw std : : runtime_error ( " Decryption error in EVP_OpenFinal " ) ;
outlen + = out_currOffset ;
2016-02-20 17:53:03 -05:00
# ifdef GXS_SECURITY_DEBUG
2016-02-18 21:30:52 -05:00
std : : cerr < < " successfully decrypted block of size " < < outlen < < std : : endl ;
2016-02-20 17:53:03 -05:00
# endif
2016-04-21 19:41:21 -04:00
EVP_CIPHER_CTX_cleanup ( & ctx ) ;
2016-02-18 21:30:52 -05:00
return true ;
}
catch ( std : : exception & e )
{
// cleanup and return false
2016-02-21 11:34:49 -05:00
# ifdef GXS_SECURITY_DEBUG
2016-02-18 21:30:52 -05:00
std : : cerr < < " (EE) error caught: " < < e . what ( ) < < std : : endl ;
2016-02-21 11:34:49 -05:00
# endif
2016-02-18 21:30:52 -05:00
if ( out )
{
free ( out ) ;
out = NULL ;
}
2016-04-21 19:41:21 -04:00
EVP_CIPHER_CTX_cleanup ( & ctx ) ;
2016-02-18 21:30:52 -05:00
return false ;
}
}
2016-06-02 23:47:57 -04:00
bool GxsSecurity : : validateNxsGrp ( const RsNxsGrp & grp , const RsTlvKeySignature & sign , const RsTlvPublicRSAKey & key )
2012-08-12 16:46:21 -04:00
{
2013-03-10 11:08:04 -04:00
# ifdef GXS_SECURITY_DEBUG
2015-12-17 00:08:08 -05:00
std : : cerr < < " GxsSecurity::validateNxsGrp() " ;
std : : cerr < < std : : endl ;
std : : cerr < < " RsNxsGrp : " ;
std : : cerr < < std : : endl ;
grp . print ( std : : cerr , 10 ) ;
std : : cerr < < std : : endl ;
2013-03-10 11:08:04 -04:00
# endif
2015-12-17 00:08:08 -05:00
RsGxsGrpMetaData & grpMeta = * ( grp . metaData ) ;
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
/********************* check signature *******************/
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
/* check signature timeperiod */
if ( ( grpMeta . mPublishTs < key . startTS ) | | ( key . endTS ! = 0 & & grpMeta . mPublishTs > key . endTS ) )
{
2013-03-10 11:08:04 -04:00
# ifdef GXS_SECURITY_DEBUG
2015-12-17 00:08:08 -05:00
std : : cerr < < " GxsSecurity::validateNxsMsg() TS out of range " ;
std : : cerr < < std : : endl ;
2013-03-10 11:08:04 -04:00
# endif
2015-12-17 00:08:08 -05:00
return false ;
}
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
/* decode key */
const unsigned char * keyptr = ( const unsigned char * ) key . keyData . bin_data ;
long keylen = key . keyData . bin_len ;
unsigned int siglen = sign . signData . bin_len ;
unsigned char * sigbuf = ( unsigned char * ) sign . signData . bin_data ;
2013-03-10 11:08:04 -04:00
# ifdef DISTRIB_DEBUG
2015-12-17 00:08:08 -05:00
std : : cerr < < " GxsSecurity::validateNxsMsg() Decode Key " ;
std : : cerr < < " keylen: " < < keylen < < " siglen: " < < siglen ;
std : : cerr < < std : : endl ;
2013-03-10 11:08:04 -04:00
# endif
2015-12-17 00:08:08 -05:00
/* extract admin key */
2016-06-04 21:39:40 -04:00
RSA * rsakey = d2i_RSAPublicKey ( NULL , & ( keyptr ) , keylen ) ;
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
if ( ! rsakey )
{
2013-03-10 11:08:04 -04:00
# ifdef GXS_SECURITY_DEBUG
2015-12-17 00:08:08 -05:00
std : : cerr < < " GxsSecurity::validateNxsGrp() " ;
std : : cerr < < " Invalid RSA Key " ;
std : : cerr < < std : : endl ;
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
key . print ( std : : cerr , 10 ) ;
2013-03-10 11:08:04 -04:00
# endif
2015-12-17 00:08:08 -05:00
}
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
std : : vector < uint32_t > api_versions_to_check ;
api_versions_to_check . push_back ( RS_GXS_GRP_META_DATA_VERSION_ID_0002 ) ; // put newest first, for debug info purpose
api_versions_to_check . push_back ( RS_GXS_GRP_META_DATA_VERSION_ID_0001 ) ;
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
RsTlvKeySignatureSet signSet = grpMeta . signSet ;
grpMeta . signSet . TlvClear ( ) ;
int signOk = 0 ;
EVP_PKEY * signKey = EVP_PKEY_new ( ) ;
EVP_PKEY_assign_RSA ( signKey , rsakey ) ;
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
for ( uint32_t i = 0 ; i < api_versions_to_check . size ( ) & & 0 = = signOk ; + + i )
{
uint32_t metaDataLen = grpMeta . serial_size ( api_versions_to_check [ i ] ) ;
uint32_t allGrpDataLen = metaDataLen + grp . grp . bin_len ;
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
RsTemporaryMemory metaData ( metaDataLen ) ;
RsTemporaryMemory allGrpData ( allGrpDataLen ) ; // msgData + metaData
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
grpMeta . serialise ( metaData , metaDataLen , api_versions_to_check [ i ] ) ;
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
// copy msg data and meta in allmsgData buffer
memcpy ( allGrpData , grp . grp . bin_data , grp . grp . bin_len ) ;
memcpy ( allGrpData + ( grp . grp . bin_len ) , metaData , metaDataLen ) ;
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
/* calc and check signature */
2015-10-27 22:41:29 -04:00
EVP_MD_CTX * mdctx = EVP_MD_CTX_create ( ) ;
2013-03-10 11:08:04 -04:00
2015-10-27 22:41:29 -04:00
EVP_VerifyInit ( mdctx , EVP_sha1 ( ) ) ;
2015-12-17 00:08:08 -05:00
EVP_VerifyUpdate ( mdctx , allGrpData , allGrpDataLen ) ;
2015-10-27 22:41:29 -04:00
signOk = EVP_VerifyFinal ( mdctx , sigbuf , siglen , signKey ) ;
EVP_MD_CTX_destroy ( mdctx ) ;
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
if ( i > 0 )
std : : cerr < < " (WW) Checking group signature with old api version " < < i + 1 < < " : tag " < < std : : hex < < api_versions_to_check [ i ] < < std : : dec < < " result: " < < signOk < < std : : endl ;
2015-10-27 22:41:29 -04:00
}
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
/* clean up */
EVP_PKEY_free ( signKey ) ;
2014-05-15 17:55:34 -04:00
2015-12-17 00:08:08 -05:00
// restore data
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
grpMeta . signSet = signSet ;
2013-03-10 11:08:04 -04:00
2015-12-17 00:08:08 -05:00
if ( signOk = = 1 )
{
2013-03-10 11:08:04 -04:00
# ifdef GXS_SECURITY_DEBUG
2015-12-17 00:08:08 -05:00
std : : cerr < < " GxsSecurity::validateNxsGrp() Signature OK " ;
std : : cerr < < std : : endl ;
2013-03-10 11:08:04 -04:00
# endif
2015-12-17 00:08:08 -05:00
return true ;
}
2013-03-10 11:08:04 -04:00
# ifdef GXS_SECURITY_DEBUG
2015-12-17 00:08:08 -05:00
std : : cerr < < " GxsSecurity::validateNxsGrp() Signature invalid " ;
std : : cerr < < std : : endl ;
2013-03-10 11:08:04 -04:00
# endif
2015-12-17 00:08:08 -05:00
return false ;
2012-08-12 16:46:21 -04:00
}
2016-06-04 21:39:40 -04:00
void GxsSecurity : : createPublicKeysFromPrivateKeys ( RsTlvSecurityKeySet & keyset )
{
for ( std : : map < RsGxsId , RsTlvPrivateRSAKey > : : const_iterator it = keyset . private_keys . begin ( ) ; it ! = keyset . private_keys . end ( ) ; + + it )
if ( keyset . public_keys . find ( it - > second . keyId ) = = keyset . public_keys . end ( ) )
{
RsTlvPublicRSAKey pub_key ;
if ( ! extractPublicKey ( it - > second , pub_key ) )
{
std : : cerr < < " (EE) ERROR when trying to generate public key from private key for ID " < < it - > second . keyId < < " . This is probably a bug with security implications. " < < std : : endl ;
continue ;
}
keyset . public_keys [ it - > second . keyId ] = pub_key ;
std : : cerr < < " (II) Generated missing public key for ID " < < it - > second . keyId < < " from private key. " < < std : : endl ;
}
}