mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 03:23:03 +01:00
Backported fix for CORE-5213
This commit is contained in:
parent
984a9aab1e
commit
5fbbae63fa
@ -63,6 +63,17 @@ namespace {
|
||||
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
|
||||
{
|
||||
protected:
|
||||
@ -88,7 +99,7 @@ namespace {
|
||||
|
||||
// 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.
|
||||
void getClumplets(ClumpletWriter& writer)
|
||||
void getClumplets(ClumpletWriter& writer) const
|
||||
{
|
||||
writer.reset(header->hdr_data, header->hdr_end - HDR_SIZE);
|
||||
}
|
||||
@ -233,17 +244,6 @@ namespace {
|
||||
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)
|
||||
: PermanentStorage(*tdbb->getDatabase()->dbb_permanent),
|
||||
sync(this),
|
||||
@ -353,6 +353,9 @@ namespace Jrd {
|
||||
(Arg::Gds(isc_bad_crypt_key) << keyName).raise();
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & CRYPT_HDR_INIT)
|
||||
checkDigitalSignature(hdr);
|
||||
}
|
||||
|
||||
void CryptoManager::loadPlugin(const char* pluginName)
|
||||
@ -533,6 +536,8 @@ namespace Jrd {
|
||||
header->hdr_crypt_page = 1;
|
||||
header->hdr_flags |= Ods::hdr_crypt_process;
|
||||
process = true;
|
||||
|
||||
digitalySignDatabase(hdr);
|
||||
}
|
||||
catch (const Exception&)
|
||||
{
|
||||
@ -870,6 +875,8 @@ namespace Jrd {
|
||||
hdr.setClumplets(hc);
|
||||
}
|
||||
}
|
||||
|
||||
digitalySignDatabase(hdr);
|
||||
}
|
||||
|
||||
bool CryptoManager::read(thread_db* tdbb, FbStatusVector* sv, Ods::pag* page, IOCallback* io)
|
||||
@ -1177,4 +1184,97 @@ namespace Jrd {
|
||||
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
|
||||
|
@ -46,7 +46,15 @@
|
||||
class Config;
|
||||
|
||||
namespace Ods {
|
||||
struct pag;
|
||||
|
||||
struct pag;
|
||||
|
||||
}
|
||||
|
||||
namespace Firebird {
|
||||
|
||||
class ClumpletReader;
|
||||
|
||||
}
|
||||
|
||||
namespace Jrd {
|
||||
@ -363,6 +371,11 @@ private:
|
||||
static const unsigned CRYPT_HDR_INIT = 0x01;
|
||||
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;
|
||||
Firebird::MetaName keyName;
|
||||
ULONG currentPage;
|
||||
|
@ -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_last_page = 3; // Last logical page number of file
|
||||
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_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
|
||||
@ -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_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_no_reserve = 0x8; // 8 don't reserve space for versions
|
||||
const USHORT hdr_SQL_dialect_3 = 0x10; // 16 database SQL dialect 3
|
||||
|
Loading…
Reference in New Issue
Block a user