8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 07:23:03 +01:00

Backported fix for CORE-5213

This commit is contained in:
Alexander Peshkov 2016-06-03 16:03:03 +03:00
parent 984a9aab1e
commit 5fbbae63fa
3 changed files with 127 additions and 15 deletions

View File

@ -63,6 +63,17 @@ namespace {
return 0; return 0;
} }
const UCHAR CRYPT_RELEASE = LCK_SR;
const UCHAR CRYPT_NORMAL = LCK_PR;
const UCHAR CRYPT_CHANGE = LCK_PW;
const UCHAR CRYPT_INIT = LCK_EX;
const int MAX_PLUGIN_NAME_LEN = 31;
}
namespace Jrd {
class Header class Header
{ {
protected: protected:
@ -88,7 +99,7 @@ namespace {
// This routine is getting clumplets from header page but is not ready to handle continuation // This routine is getting clumplets from header page but is not ready to handle continuation
// Fortunately, modern pages of size 4k and bigger can fit everything on one page. // Fortunately, modern pages of size 4k and bigger can fit everything on one page.
void getClumplets(ClumpletWriter& writer) void getClumplets(ClumpletWriter& writer) const
{ {
writer.reset(header->hdr_data, header->hdr_end - HDR_SIZE); writer.reset(header->hdr_data, header->hdr_end - HDR_SIZE);
} }
@ -233,17 +244,6 @@ namespace {
AutoPtr<UCHAR, ArrayDelete<UCHAR> > buffer; AutoPtr<UCHAR, ArrayDelete<UCHAR> > buffer;
}; };
const UCHAR CRYPT_RELEASE = LCK_SR;
const UCHAR CRYPT_NORMAL = LCK_PR;
const UCHAR CRYPT_CHANGE = LCK_PW;
const UCHAR CRYPT_INIT = LCK_EX;
const int MAX_PLUGIN_NAME_LEN = 31;
}
namespace Jrd {
CryptoManager::CryptoManager(thread_db* tdbb) CryptoManager::CryptoManager(thread_db* tdbb)
: PermanentStorage(*tdbb->getDatabase()->dbb_permanent), : PermanentStorage(*tdbb->getDatabase()->dbb_permanent),
sync(this), sync(this),
@ -353,6 +353,9 @@ namespace Jrd {
(Arg::Gds(isc_bad_crypt_key) << keyName).raise(); (Arg::Gds(isc_bad_crypt_key) << keyName).raise();
} }
} }
if (flags & CRYPT_HDR_INIT)
checkDigitalSignature(hdr);
} }
void CryptoManager::loadPlugin(const char* pluginName) void CryptoManager::loadPlugin(const char* pluginName)
@ -533,6 +536,8 @@ namespace Jrd {
header->hdr_crypt_page = 1; header->hdr_crypt_page = 1;
header->hdr_flags |= Ods::hdr_crypt_process; header->hdr_flags |= Ods::hdr_crypt_process;
process = true; process = true;
digitalySignDatabase(hdr);
} }
catch (const Exception&) catch (const Exception&)
{ {
@ -870,6 +875,8 @@ namespace Jrd {
hdr.setClumplets(hc); hdr.setClumplets(hc);
} }
} }
digitalySignDatabase(hdr);
} }
bool CryptoManager::read(thread_db* tdbb, FbStatusVector* sv, Ods::pag* page, IOCallback* io) bool CryptoManager::read(thread_db* tdbb, FbStatusVector* sv, Ods::pag* page, IOCallback* io)
@ -1177,4 +1184,97 @@ namespace Jrd {
st.check(); st.check();
} }
void CryptoManager::addClumplet(string& signature, ClumpletReader& block, UCHAR tag)
{
if (block.find(tag))
{
string tmp;
block.getString(tmp);
signature += ' ';
signature += tmp;
}
}
void CryptoManager::calcDigitalSignature(string& signature, const Header& hdr)
{
/*
We use the following items to calculate digital signature (hash of encrypted string)
for database:
hdr_flags & (hdr_crypt_process | hdr_encrypted)
hdr_crypt_page
hdr_crypt_plugin
HDR_crypt_key
HDR_crypt_hash
*/
signature.printf("%d %d %d %s",
hdr->hdr_flags & Ods::hdr_crypt_process ? 1 : 0,
hdr->hdr_flags & Ods::hdr_encrypted ? 1 : 0,
hdr->hdr_crypt_page,
hdr->hdr_crypt_plugin);
ClumpletWriter hc(ClumpletWriter::UnTagged, hdr->hdr_page_size);
hdr.getClumplets(hc);
addClumplet(signature, hc, Ods::HDR_crypt_key);
addClumplet(signature, hc, Ods::HDR_crypt_hash);
const unsigned QUANTUM = 16;
signature += string(QUANTUM - 1, '$');
unsigned len = signature.length();
len &= ~(QUANTUM - 1);
loadPlugin(hdr->hdr_crypt_plugin);
string enc;
FbLocalStatus sv;
cryptPlugin->encrypt(&sv, len, signature.c_str(), enc.getBuffer(len));
if (sv->getState() & IStatus::STATE_ERRORS)
Arg::StatusVector(&sv).raise();
Sha1::hashBased64(signature, enc);
}
void CryptoManager::digitalySignDatabase(CchHdr& hdr)
{
ClumpletWriter hc(ClumpletWriter::UnTagged, hdr->hdr_page_size);
hdr.getClumplets(hc);
bool wf = hc.find(Ods::HDR_crypt_checksum);
hc.deleteWithTag(Ods::HDR_crypt_checksum);
if (hdr->hdr_flags & (Ods::hdr_crypt_process | Ods::hdr_encrypted))
{
wf = true;
string signature;
calcDigitalSignature(signature, hdr);
hc.insertString(Ods::HDR_crypt_checksum, signature);
}
if (wf)
hdr.setClumplets(hc);
}
void CryptoManager::checkDigitalSignature(const Header& hdr)
{
// if (hdr->hdr_flags & (Ods::hdr_crypt_process | Ods::hdr_encrypted))
// Restricted check to ensure compatibility with 3.0.0 databases - only for active crypt process
if (hdr->hdr_flags & Ods::hdr_crypt_process)
{
const char* message = "Invalid or missing checksum of encrypted database";
ClumpletWriter hc(ClumpletWriter::UnTagged, hdr->hdr_page_size);
hdr.getClumplets(hc);
if (!hc.find(Ods::HDR_crypt_checksum))
(Arg::Gds(isc_random) << message).raise();
string sig1, sig2;
hc.getString(sig1);
calcDigitalSignature(sig2, hdr);
if (sig1 != sig2)
(Arg::Gds(isc_random) << message).raise();
}
}
} // namespace Jrd } // namespace Jrd

View File

@ -46,7 +46,15 @@
class Config; class Config;
namespace Ods { namespace Ods {
struct pag;
struct pag;
}
namespace Firebird {
class ClumpletReader;
} }
namespace Jrd { namespace Jrd {
@ -363,6 +371,11 @@ private:
static const unsigned CRYPT_HDR_INIT = 0x01; static const unsigned CRYPT_HDR_INIT = 0x01;
static const unsigned CRYPT_HDR_NOWAIT = 0x02; static const unsigned CRYPT_HDR_NOWAIT = 0x02;
void addClumplet(Firebird::string& value, Firebird::ClumpletReader& block, UCHAR tag);
void calcDigitalSignature(Firebird::string& signature, const class Header& hdr);
void digitalySignDatabase(class CchHdr& hdr);
void checkDigitalSignature(const class Header& hdr);
BarSync sync; BarSync sync;
Firebird::MetaName keyName; Firebird::MetaName keyName;
ULONG currentPage; ULONG currentPage;

View File

@ -426,7 +426,7 @@ const UCHAR HDR_root_file_name = 1; // Original name of root file
const UCHAR HDR_file = 2; // Secondary file const UCHAR HDR_file = 2; // Secondary file
const UCHAR HDR_last_page = 3; // Last logical page number of file const UCHAR HDR_last_page = 3; // Last logical page number of file
const UCHAR HDR_sweep_interval = 4; // Transactions between sweeps const UCHAR HDR_sweep_interval = 4; // Transactions between sweeps
const UCHAR HDR_password_file_key = 5; // Key to compare to password db const UCHAR HDR_crypt_checksum = 5; // Checksum of critical crypt parameters
const UCHAR HDR_difference_file = 6; // Delta file that is used during backup lock const UCHAR HDR_difference_file = 6; // Delta file that is used during backup lock
const UCHAR HDR_backup_guid = 7; // UID generated on each switch into backup mode const UCHAR HDR_backup_guid = 7; // UID generated on each switch into backup mode
const UCHAR HDR_crypt_key = 8; // Name of a key used to crypt database const UCHAR HDR_crypt_key = 8; // Name of a key used to crypt database
@ -437,7 +437,6 @@ const UCHAR HDR_max = 10; // Maximum HDR_clump value
const USHORT hdr_active_shadow = 0x1; // 1 file is an active shadow file const USHORT hdr_active_shadow = 0x1; // 1 file is an active shadow file
const USHORT hdr_force_write = 0x2; // 2 database is forced write const USHORT hdr_force_write = 0x2; // 2 database is forced write
// const USHORT hdr_no_checksums = 0x4; // 4 don't calculate checksums, not used since ODS 12
const USHORT hdr_crypt_process = 0x4; // 4 Encryption status is changing now const USHORT hdr_crypt_process = 0x4; // 4 Encryption status is changing now
const USHORT hdr_no_reserve = 0x8; // 8 don't reserve space for versions const USHORT hdr_no_reserve = 0x8; // 8 don't reserve space for versions
const USHORT hdr_SQL_dialect_3 = 0x10; // 16 database SQL dialect 3 const USHORT hdr_SQL_dialect_3 = 0x10; // 16 database SQL dialect 3