Skip to content

Commit

Permalink
Fixed CORE-5213
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexPeshkoff committed Jun 3, 2016
1 parent f9985fc commit 88748bd
Show file tree
Hide file tree
Showing 13 changed files with 138 additions and 19 deletions.
2 changes: 2 additions & 0 deletions lang_helpers/gds_codes.ftn
Expand Up @@ -1636,6 +1636,8 @@ C --
PARAMETER (GDS__wrong_prvlg = 335545111)
INTEGER*4 GDS__miss_prvlg
PARAMETER (GDS__miss_prvlg = 335545112)
INTEGER*4 GDS__crypt_checksum
PARAMETER (GDS__crypt_checksum = 335545113)
INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw
Expand Down
2 changes: 2 additions & 0 deletions lang_helpers/gds_codes.pas
Expand Up @@ -1631,6 +1631,8 @@
gds_wrong_prvlg = 335545111;
isc_miss_prvlg = 335545112;
gds_miss_prvlg = 335545112;
isc_crypt_checksum = 335545113;
gds_crypt_checksum = 335545113;
isc_gfix_db_name = 335740929;
gds_gfix_db_name = 335740929;
isc_gfix_invalid_sw = 335740930;
Expand Down
1 change: 1 addition & 0 deletions src/include/gen/codetext.h
Expand Up @@ -814,6 +814,7 @@ static const struct {
{"max_idx_depth", 335545110},
{"wrong_prvlg", 335545111},
{"miss_prvlg", 335545112},
{"crypt_checksum", 335545113},
{"gfix_db_name", 335740929},
{"gfix_invalid_sw", 335740930},
{"gfix_incmp_sw", 335740932},
Expand Down
6 changes: 4 additions & 2 deletions src/include/gen/iberror.h
Expand Up @@ -848,6 +848,7 @@ const ISC_STATUS isc_encrypt_error = 335545109L;
const ISC_STATUS isc_max_idx_depth = 335545110L;
const ISC_STATUS isc_wrong_prvlg = 335545111L;
const ISC_STATUS isc_miss_prvlg = 335545112L;
const ISC_STATUS isc_crypt_checksum = 335545113L;
const ISC_STATUS isc_gfix_db_name = 335740929L;
const ISC_STATUS isc_gfix_invalid_sw = 335740930L;
const ISC_STATUS isc_gfix_incmp_sw = 335740932L;
Expand Down Expand Up @@ -1319,7 +1320,7 @@ const ISC_STATUS isc_trace_switch_user_only = 337182757L;
const ISC_STATUS isc_trace_switch_param_miss = 337182758L;
const ISC_STATUS isc_trace_param_act_notcompat = 337182759L;
const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L;
const ISC_STATUS isc_err_max = 1263;
const ISC_STATUS isc_err_max = 1264;

#else /* c definitions */

Expand Down Expand Up @@ -2137,6 +2138,7 @@ const ISC_STATUS isc_err_max = 1263;
#define isc_max_idx_depth 335545110L
#define isc_wrong_prvlg 335545111L
#define isc_miss_prvlg 335545112L
#define isc_crypt_checksum 335545113L
#define isc_gfix_db_name 335740929L
#define isc_gfix_invalid_sw 335740930L
#define isc_gfix_incmp_sw 335740932L
Expand Down Expand Up @@ -2608,7 +2610,7 @@ const ISC_STATUS isc_err_max = 1263;
#define isc_trace_switch_param_miss 337182758L
#define isc_trace_param_act_notcompat 337182759L
#define isc_trace_mandatory_switch_miss 337182760L
#define isc_err_max 1263
#define isc_err_max 1264

#endif

Expand Down
1 change: 1 addition & 0 deletions src/include/gen/msgs.h
Expand Up @@ -817,6 +817,7 @@ Data source : @4"}, /* eds_statement */
{335545110, "Maximum index depth (@1 levels) is reached"}, /* max_idx_depth */
{335545111, "System privilege @1 does not exist"}, /* wrong_prvlg */
{335545112, "Unable to perform operation: system privilege @1 is missing"}, /* miss_prvlg */
{335545113, "Invalid or missing checksum of encrypted database"}, /* crypt_checksum */
{335740929, "data base file name (@1) already given"}, /* gfix_db_name */
{335740930, "invalid switch @1"}, /* gfix_invalid_sw */
{335740932, "incompatible switch combination"}, /* gfix_incmp_sw */
Expand Down
1 change: 1 addition & 0 deletions src/include/gen/sql_code.h
Expand Up @@ -813,6 +813,7 @@ static const struct {
{335545110, -904}, /* 790 max_idx_depth */
{335545111, -901}, /* 791 wrong_prvlg */
{335545112, -902}, /* 792 miss_prvlg */
{335545113, -902}, /* 793 crypt_checksum */
{335740929, -901}, /* 1 gfix_db_name */
{335740930, -901}, /* 2 gfix_invalid_sw */
{335740932, -901}, /* 4 gfix_incmp_sw */
Expand Down
1 change: 1 addition & 0 deletions src/include/gen/sql_state.h
Expand Up @@ -813,6 +813,7 @@ static const struct {
{335545110, "54000"}, // 790 max_idx_depth
{335545111, "0A000"}, // 791 wrong_prvlg
{335545112, "28000"}, // 792 miss_prvlg
{335545113, "XX000"}, // 793 crypt_checksum
{335740929, "00000"}, // 1 gfix_db_name
{335740930, "00000"}, // 2 gfix_invalid_sw
{335740932, "00000"}, // 4 gfix_incmp_sw
Expand Down
120 changes: 108 additions & 12 deletions src/jrd/CryptoManager.cpp
Expand Up @@ -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;

This comment has been minimized.

Copy link
@asfernandes

asfernandes Jun 6, 2016

Member

Why did we have this additional constant apparently related to others about metadata length?

This comment has been minimized.

Copy link
@AlexPeshkoff

AlexPeshkoff Jun 6, 2016

Author Member

I do not remember why I've added plugin name as a string in the fixed part of header, not as clumplet. Why it was made 31 is clear - plugin name comes from SQL operator and can't be longer. Why constant is separate is also clear - it affects ODS.

At the first look nothing prevents moving plugin name into variable part of header in ODS13.

}


namespace Jrd {

class Header
{
protected:
Expand All @@ -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);
}
Expand Down Expand Up @@ -224,17 +235,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),
Expand Down Expand Up @@ -344,6 +344,9 @@ namespace Jrd {
(Arg::Gds(isc_bad_crypt_key) << keyName).raise();
}
}

if (flags & CRYPT_HDR_INIT)
checkDigitalSignature(hdr);
}

void CryptoManager::loadPlugin(const char* pluginName)
Expand Down Expand Up @@ -526,6 +529,8 @@ namespace Jrd {
header->hdr_crypt_page = 1;
header->hdr_flags |= Ods::hdr_crypt_process;
process = true;

digitalySignDatabase(hdr);
}
catch (const Exception&)
{
Expand Down Expand Up @@ -865,6 +870,8 @@ namespace Jrd {
hdr.setClumplets(hc);
}
}

digitalySignDatabase(hdr);
}

bool CryptoManager::read(thread_db* tdbb, FbStatusVector* sv, Ods::pag* page, IOCallback* io)
Expand Down Expand Up @@ -1172,4 +1179,93 @@ 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))
{
ClumpletWriter hc(ClumpletWriter::UnTagged, hdr->hdr_page_size);
hdr.getClumplets(hc);
if (!hc.find(Ods::HDR_crypt_checksum))
Arg::Gds(isc_crypt_checksum).raise();

string sig1, sig2;
hc.getString(sig1);
calcDigitalSignature(sig2, hdr);
if (sig1 != sig2)
Arg::Gds(isc_crypt_checksum).raise();
}
}

} // namespace Jrd
15 changes: 14 additions & 1 deletion src/jrd/CryptoManager.h
Expand Up @@ -46,7 +46,15 @@
class Config;

namespace Ods {
struct pag;

struct pag;

}

namespace Firebird {

class ClumpletReader;

}

namespace Jrd {
Expand Down Expand Up @@ -363,6 +371,11 @@ class CryptoManager FB_FINAL : public Firebird::PermanentStorage, public BarSync
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;
Expand Down
4 changes: 1 addition & 3 deletions src/jrd/ods.h
Expand Up @@ -413,7 +413,6 @@ struct header_page
ULONG hdr_oldest_snapshot; // Oldest snapshot of active transactions
SLONG hdr_backup_pages; // The amount of pages in files locked for backup
ULONG hdr_crypt_page; // Page at which processing is in progress
ULONG hdr_top_crypt; // Last page to crypt
TEXT hdr_crypt_plugin[32]; // Name of plugin used to crypt this DB
SLONG hdr_att_high; // High word of the next attachment counter
USHORT hdr_tra_high[4]; // High words of the transaction counters
Expand All @@ -433,7 +432,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
Expand All @@ -444,7 +443,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
Expand Down
2 changes: 1 addition & 1 deletion src/msgs/facilities2.sql
@@ -1,7 +1,7 @@
/* MAX_NUMBER is the next number to be used, always one more than the highest message number. */
set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?);
--
('2016-05-26 12:14:49', 'JRD', 0, 793)
('2016-06-03 14:53:38', 'JRD', 0, 794)
('2015-03-17 18:33:00', 'QLI', 1, 533)
('2015-01-07 18:01:51', 'GFIX', 3, 134)
('1996-11-07 13:39:40', 'GPRE', 4, 1)
Expand Down
1 change: 1 addition & 0 deletions src/msgs/messages2.sql
Expand Up @@ -900,6 +900,7 @@ Data source : @4', NULL, NULL)
('max_idx_depth', NULL, 'btr.cpp', NULL, 0, 790, NULL, 'Maximum index depth (@1 levels) is reached', NULL, NULL);
('wrong_prvlg', 'SCL_convert_privilege', 'scl.epp', NULL, 0, 791, NULL, 'System privilege @1 does not exist', NULL, NULL);
('miss_prvlg', 'validateAccess', 'jrd.cpp', NULL, 0, 792, NULL, 'Unable to perform operation: system privilege @1 is missing', NULL, NULL);
('crypt_checksum', 'CryptoManager::checkDigitalSignature', 'CryptoManager.cpp', NULL, 0, 793, NULL, 'Invalid or missing checksum of encrypted database', NULL, NULL);
-- QLI
(NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL);
(NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL);
Expand Down
1 change: 1 addition & 0 deletions src/msgs/system_errors2.sql
Expand Up @@ -799,6 +799,7 @@ set bulk_insert INSERT INTO SYSTEM_ERRORS (SQL_CODE, SQL_CLASS, SQL_SUBCLASS, FA
(-904, '54', '000', 0, 790, 'max_idx_depth', NULL, NULL)
(-901, '0A', '000', 0, 791, 'wrong_prvlg', NULL, NULL)
(-902, '28', '000', 0, 792, 'miss_prvlg', NULL, NULL)
(-902, 'XX', '000', 0, 793, 'crypt_checksum', NULL, NULL)
-- GFIX
(-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL)
(-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL)
Expand Down

0 comments on commit 88748bd

Please sign in to comment.