/* * libretroshare/src/gxs: gxssecurity.cc * * * Copyright 2008-2010 by Robert Fernie * 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 * 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" #include "util/rsdir.h" #include "util/rsmemory.h" //#include "retroshare/rspeers.h" /**** * #define GXS_SECURITY_DEBUG 1 ***/ 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 ; static const uint32_t MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE = 256 ; static RsGxsId getRsaKeyFingerprint_old_insecure_method(RSA *pubkey) { #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) int lenn = BN_num_bytes(pubkey -> n); RsTemporaryMemory tmp(lenn) ; BN_bn2bin(pubkey -> n, tmp); #else const BIGNUM *nn=NULL,*ee=NULL ; RSA_get0_key(pubkey,&nn,&ee,NULL) ; int lenn = BN_num_bytes(nn); RsTemporaryMemory tmp(lenn) ; BN_bn2bin(nn, tmp); #endif // 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) ; } static RsGxsId getRsaKeyFingerprint(RSA *pubkey) { #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) int lenn = BN_num_bytes(pubkey -> n); int lene = BN_num_bytes(pubkey -> e); RsTemporaryMemory tmp(lenn+lene) ; BN_bn2bin(pubkey -> n, tmp); BN_bn2bin(pubkey -> e, &tmp[lenn]); #else const BIGNUM *nn=NULL,*ee=NULL ; RSA_get0_key(pubkey,&nn,&ee,NULL) ; int lenn = BN_num_bytes(nn); int lene = BN_num_bytes(ee); RsTemporaryMemory tmp(lenn+lene) ; BN_bn2bin(nn, tmp); BN_bn2bin(ee, &tmp[lenn]); #endif Sha1CheckSum s = RsDirUtil::sha1sum(tmp,lenn+lene) ; // 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) ; return RsGxsId(s.toStdString().substr(0,2*CERTSIGNLEN)); } static RSA *extractPrivateKey(const RsTlvPrivateRSAKey& key) { 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; } static RSA *extractPublicKey(const RsTlvPublicRSAKey& key) { 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_RSAPublicKey(NULL, &(keyptr), keylen); return rsakey; } static void setRSAPublicKeyData(RsTlvPublicRSAKey& key, RSA *rsa_pub) { assert(!(key.keyFlags & RSTLV_KEY_TYPE_FULL)) ; 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); free(data) ; } static void setRSAPrivateKeyData(RsTlvPrivateRSAKey& key, RSA *rsa_priv) { assert(key.keyFlags & RSTLV_KEY_TYPE_FULL) ; unsigned char *data = NULL ; // this works for OpenSSL > 0.9.7 int reqspace = i2d_RSAPrivateKey(rsa_priv, &data); key.keyData.setBinData(data, reqspace); key.keyId = getRsaKeyFingerprint(rsa_priv); free(data) ; } bool GxsSecurity::checkFingerprint(const RsTlvPublicRSAKey& key) { RSA *rsa_pub = ::extractPublicKey(key) ; bool res = (key.keyId == getRsaKeyFingerprint(rsa_pub)) ; RSA_free(rsa_pub) ; return res ; } bool GxsSecurity::checkPrivateKey(const RsTlvPrivateRSAKey& key) { #ifdef GXS_SECURITY_DEBUG std::cerr << "Checking private key " << key.keyId << " ..." << std::endl; #endif 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) { if(key.keyId == getRsaKeyFingerprint_old_insecure_method(rsa_pub)) { #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 RSA_free(rsa_pub) ; // The policy is to *accept* these private keys, but the public key that corresponds will be rejected anyway, as it can easily be faked. return true ; } else { std::cerr << "(WW) GxsSecurity::checkPrivateKey(): key " << key.keyId << " has wrong fingerprint " << recomputed_key_id << std::endl; RSA_free(rsa_pub) ; return false ; } } RSA_free(rsa_pub) ; return true ; } bool GxsSecurity::checkPublicKey(const RsTlvPublicRSAKey &key) { #ifdef GXS_SECURITY_DEBUG std::cerr << "Checking public key " << key.keyId << " ..." << std::endl; #endif 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 ; } // 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 ; } 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) { 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) ; // 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. 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) ; return false ; } RSA_free(rsa_pub) ; return true ; } bool GxsSecurity::generateKeyPair(RsTlvPublicRSAKey& public_key,RsTlvPrivateRSAKey& private_key) { // admin keys BIGNUM *ebn = BN_new(); BN_set_word(ebn, 65537); RSA *rsa = RSA_new(); RSA_generate_key_ex(rsa, 2048, ebn, NULL); RSA *rsa_pub = RSAPublicKey_dup(rsa); public_key.keyFlags = RSTLV_KEY_TYPE_PUBLIC_ONLY ; private_key.keyFlags = RSTLV_KEY_TYPE_FULL ; setRSAPublicKeyData(public_key, rsa_pub); setRSAPrivateKeyData(private_key, rsa); public_key.startTS = time(NULL); public_key.endTS = public_key.startTS + 60 * 60 * 24 * 365 * 5; /* approx 5 years */ private_key.startTS = public_key.startTS; private_key.endTS = 0; /* no end */ // clean up RSA_free(rsa); RSA_free(rsa_pub); if(!(private_key.checkKey() && public_key.checkKey())) { std::cerr << "(EE) ERROR while generating keys. Something inconsistent in flags. This is probably a bad sign!" << std::endl; return false ; } return true ; } bool GxsSecurity::extractPublicKey(const RsTlvPrivateRSAKey &private_key, RsTlvPublicRSAKey &public_key) { public_key.TlvClear() ; if(!(private_key.keyFlags & RSTLV_KEY_TYPE_FULL)) return false ; RSA *rsaPrivKey = extractPrivateKey(private_key); if(!rsaPrivKey) return false ; RSA *rsaPubKey = RSAPublicKey_dup(rsaPrivKey); RSA_free(rsaPrivKey); if(!rsaPubKey) return false ; setRSAPublicKeyData(public_key, rsaPubKey); RSA_free(rsaPubKey); 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 */ // 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; std::cerr << " that is unsecure (can be faked easily). You should delete it!" << std::endl; std::cerr << std::endl; public_key.keyId = private_key.keyId ; } return true ; } bool GxsSecurity::getSignature(const char *data, uint32_t data_len, const RsTlvPrivateRSAKey &privKey, RsTlvKeySignature& sign) { RSA* rsa_priv = extractPrivateKey(privKey); if(!rsa_priv) { std::cerr << "GxsSecurity::getSignature(): Cannot create signature. Keydata is incomplete." << std::endl; return false ; } EVP_PKEY *key_priv = EVP_PKEY_new(); EVP_PKEY_assign_RSA(key_priv, rsa_priv); /* 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; unsigned int siglen = EVP_PKEY_size(key_priv); unsigned char sigbuf[siglen]; ok &= EVP_SignFinal(mdctx, sigbuf, &siglen, key_priv) == 1; // clean up EVP_MD_CTX_destroy(mdctx); EVP_PKEY_free(key_priv); sign.signData.setBinData(sigbuf, siglen); sign.keyId = RsGxsId(privKey.keyId); return ok; } bool GxsSecurity::validateSignature(const char *data, uint32_t data_len, const RsTlvPublicRSAKey &key, const RsTlvKeySignature& signature) { assert(!(key.keyFlags & RSTLV_KEY_TYPE_FULL)) ; RSA *rsakey = ::extractPublicKey(key) ; if(!rsakey) { std::cerr << "GxsSecurity::validateSignature(): Cannot validate signature. Keydata is incomplete." << std::endl; key.print(std::cerr,0) ; return false ; } 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; } bool GxsSecurity::validateNxsMsg(const RsNxsMsg& msg, const RsTlvKeySignature& sign, const RsTlvPublicRSAKey& key) { #ifdef GXS_SECURITY_DEBUG std::cerr << "GxsSecurity::validateNxsMsg()"; std::cerr << std::endl; std::cerr << "RsNxsMsg :"; std::cerr << std::endl; const_cast(&msg)->print(std::cerr, 10); std::cerr << std::endl; #endif RsGxsMsgMetaData& msgMeta = *(msg.metaData); // /********************* check signature *******************/ /* check signature timeperiod */ if ((msgMeta.mPublishTs < key.startTS) || (key.endTS != 0 && msgMeta.mPublishTs > key.endTS)) { #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 */ RSA *rsakey = (key.keyFlags & RSTLV_KEY_TYPE_FULL)? (d2i_RSAPrivateKey(NULL, &(keyptr), keylen)) : (d2i_RSAPublicKey(NULL, &(keyptr), keylen)); 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(); RsGxsMessageId msgId = msgMeta.mMsgId, origMsgId = msgMeta.mOrigMsgId; if(msgMeta.mOrigMsgId == msgMeta.mMsgId) // message is not versionned, then the signature was made with mOrigMsgId==NULL msgMeta.mOrigMsgId.clear(); msgMeta.mMsgId.clear(); int signOk = 0 ; { EVP_PKEY *signKey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(signKey, rsakey); EVP_MD_CTX *mdctx = EVP_MD_CTX_create(); uint32_t metaDataLen = msgMeta.serial_size(); uint32_t allMsgDataLen = metaDataLen + msg.msg.bin_len; RsTemporaryMemory metaData(metaDataLen) ; RsTemporaryMemory allMsgData(allMsgDataLen) ; if(!metaData || !allMsgData) return false ; msgMeta.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); /* calc and check signature */ EVP_VerifyInit(mdctx, EVP_sha1()); EVP_VerifyUpdate(mdctx, allMsgData, allMsgDataLen); signOk = EVP_VerifyFinal(mdctx, sigbuf, siglen, signKey); /* clean up */ EVP_PKEY_free(signKey); EVP_MD_CTX_destroy(mdctx); } msgMeta.mOrigMsgId = origMsgId; msgMeta.mMsgId = msgId; msgMeta.signSet = signSet; 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 return false; } bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, uint32_t inlen, const RsTlvPublicRSAKey& key) { #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: // // [--- Encrypted session key length ---|--- Encrypted session key ---|--- IV ---|---- Encrypted data ---] // out = NULL ; RSA *tmpkey = ::extractPublicKey(key) ; RSA *rsa_publish_pub = RSAPublicKey_dup(tmpkey) ; RSA_free(tmpkey) ; EVP_PKEY *public_key = NULL; //RSA* rsa_publish = EVP_PKEY_get1_RSA(privateKey); //rsa_publish_pub = RSAPublicKey_dup(rsa_publish); if(rsa_publish_pub != NULL) { public_key = EVP_PKEY_new(); EVP_PKEY_assign_RSA(public_key, rsa_publish_pub); } else { #ifdef DISTRIB_DEBUG std::cerr << "GxsSecurity(): Could not generate publish key " << grpId << std::endl; #endif return false; } EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); int eklen, net_ekl; unsigned char *ek; unsigned char iv[EVP_MAX_IV_LENGTH]; int out_currOffset = 0; int out_offset = 0; int max_evp_key_size = EVP_PKEY_size(public_key); ek = (unsigned char*)rs_malloc(max_evp_key_size); if(ek == NULL) return false ; const EVP_CIPHER *cipher = EVP_aes_128_cbc(); int cipher_block_size = EVP_CIPHER_block_size(cipher); int size_net_ekl = sizeof(net_ekl); int max_outlen = inlen + cipher_block_size + EVP_MAX_IV_LENGTH + max_evp_key_size + size_net_ekl; // 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; // now assign memory to out accounting for data, and cipher block size, key length, and key length val out = (uint8_t*)rs_malloc(inlen + cipher_block_size + size_net_ekl + eklen + EVP_MAX_IV_LENGTH) ; if (out == NULL) return false; net_ekl = htonl(eklen); memcpy((unsigned char*)out + out_offset, &net_ekl, size_net_ekl); out_offset += size_net_ekl; memcpy((unsigned char*)out + out_offset, ek, eklen); out_offset += eklen; memcpy((unsigned char*)out + out_offset, iv, EVP_MAX_IV_LENGTH); out_offset += EVP_MAX_IV_LENGTH; // now encrypt actual data if(!EVP_SealUpdate(ctx, (unsigned char*) out + out_offset, &out_currOffset, (unsigned char*) in, inlen)) { free(out) ; out = NULL ; return false; } // move along to partial block space out_offset += out_currOffset; // add padding if(!EVP_SealFinal(ctx, (unsigned char*) out + out_offset, &out_currOffset)) { free(out) ; out = NULL ; return false; } // move to end out_offset += out_currOffset; // make sure offset has not gone passed valid memory bounds if(out_offset > max_outlen) { free(out) ; out = NULL ; return false; } // free encrypted key data free(ek); EVP_CIPHER_CTX_free(ctx); outlen = out_offset; return true; } bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, uint32_t inlen, const std::vector &keys) { #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: // // [--- 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 // out = NULL ; EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); std::vector public_keys(keys.size(),NULL); try { for(uint32_t i=0;i ek(keys.size(),NULL) ; std::vector eklen(keys.size(),0) ; for(uint32_t i=0;i> 8) & 0xff ; // 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 max_outlen) throw std::runtime_error("Memory used by encryption exceeds allocated memory block") ; // free encrypted key data for(uint32_t i=0;i 512 || eklen+in_offset > (int)inlen) { std::cerr << "Error while deserialising encryption key length: eklen = " << std::dec << eklen << ". Giving up decryption." << std::endl; free(ek); return false; } 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(); 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; } if(inlen < (uint32_t)in_offset) { std::cerr << "Severe error in " << __PRETTY_FUNCTION__ << ": cannot encrypt. " << std::endl; return false ; } out = (uint8_t*)rs_malloc(inlen - in_offset); if(out == NULL) return false; if(!EVP_OpenUpdate(ctx, (unsigned char*) out, &out_currOffset, (unsigned char*)in + in_offset, inlen - in_offset)) { free(out) ; out = NULL ; return false; } outlen = out_currOffset; if(!EVP_OpenFinal(ctx, (unsigned char*)out + out_currOffset, &out_currOffset)) { free(out) ; out = NULL ; return false; } outlen += out_currOffset; free(ek); EVP_CIPHER_CTX_free(ctx); return true; } bool GxsSecurity::decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in, uint32_t inlen, const std::vector &keys) { // 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: // // [--- 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 // // 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 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); try { out = NULL ; // 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 ; 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 ; // read IV offset if(encrypted_block_offset >= inlen) throw std::runtime_error("Offset error") ; encrypted_block_size = inlen - encrypted_block_offset ; #ifdef GXS_SECURITY_DEBUG 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; #endif // decrypt bool succeed = false; for(uint32_t j=0;j(&grp)->print(std::cerr, 10); std::cerr << std::endl; #endif RsGxsGrpMetaData& grpMeta = *(grp.metaData); /********************* check signature *******************/ /* check signature timeperiod */ if ((grpMeta.mPublishTs < key.startTS) || (key.endTS != 0 && grpMeta.mPublishTs > key.endTS)) { #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 */ RSA *rsakey = d2i_RSAPublicKey(NULL, &(keyptr), keylen); if (!rsakey) { #ifdef GXS_SECURITY_DEBUG std::cerr << "GxsSecurity::validateNxsGrp()"; std::cerr << " Invalid RSA Key"; std::cerr << std::endl; key.print(std::cerr, 10); #endif } std::vector 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) ; RsTlvKeySignatureSet signSet = grpMeta.signSet; grpMeta.signSet.TlvClear(); int signOk =0; EVP_PKEY *signKey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(signKey, rsakey); for(uint32_t i=0;i0) 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; } /* clean up */ EVP_PKEY_free(signKey); // restore data grpMeta.signSet = signSet; if (signOk == 1) { #ifdef GXS_SECURITY_DEBUG std::cerr << "GxsSecurity::validateNxsGrp() Signature OK"; std::cerr << std::endl; #endif return true; } #ifdef GXS_SECURITY_DEBUG std::cerr << "GxsSecurity::validateNxsGrp() Signature invalid"; std::cerr << std::endl; #endif return false; } void GxsSecurity::createPublicKeysFromPrivateKeys(RsTlvSecurityKeySet& keyset) { for( std::map::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; } }