Skip to content

Commit

Permalink
Implemented CORE-5100: Improve control over database crypt keys
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexPeshkoff committed Feb 3, 2016
1 parent 91f7b5e commit bebf1d5
Show file tree
Hide file tree
Showing 25 changed files with 272 additions and 80 deletions.
93 changes: 66 additions & 27 deletions examples/dbcrypt/CryptKeyHolder.cpp
Expand Up @@ -85,7 +85,7 @@ class CryptKeyHolder : public IKeyHolderPluginImpl<CryptKeyHolder, CheckStatusWr
{
public:
explicit CryptKeyHolder(IPluginConfig* cnf) throw()
: callbackInterface(this), config(cnf), key(0), owner(NULL)
: callbackInterface(this), named(NULL), config(cnf), key(0), owner(NULL)
{
config->addRef();
}
Expand Down Expand Up @@ -139,12 +139,12 @@ class CryptKeyHolder : public IKeyHolderPluginImpl<CryptKeyHolder, CheckStatusWr
{
public:
explicit CallbackInterface(CryptKeyHolder* p)
: parent(p)
: holder(p)
{ }

unsigned int callback(unsigned int, const void*, unsigned int length, void* buffer)
{
UCHAR k = parent->getKey();
UCHAR k = holder->getKey();
if (!k)
{
return 0;
Expand All @@ -157,35 +157,60 @@ class CryptKeyHolder : public IKeyHolderPluginImpl<CryptKeyHolder, CheckStatusWr
return 1;
}

IPluginModule* getModule()
private:
CryptKeyHolder* holder;
};

class NamedCallback : public ICryptKeyCallbackImpl<NamedCallback, CheckStatusWrapper>
{
public:
NamedCallback(NamedCallback *n, const char* nm, UCHAR k)
: next(n), key(k)
{
return &module;
strncpy(name, nm, sizeof(name));
name[sizeof(name) - 1] = 0;
}

private:
CryptKeyHolder* parent;
unsigned int callback(unsigned int, const void*, unsigned int length, void* buffer)
{
memcpy(buffer, &key, 1);
return 1;
}

~NamedCallback()
{
delete next;
}

char name[32];
NamedCallback* next;
UCHAR key;
};

CallbackInterface callbackInterface;
NamedCallback *named;

IPluginConfig* config;
UCHAR key;

AtomicCounter refCounter;
IReferenceCounted* owner;

void noKeyError(CheckStatusWrapper* status);
IConfigEntry* getEntry(CheckStatusWrapper* status, const char* entryName);
};

void CryptKeyHolder::noKeyError(CheckStatusWrapper* status)
IConfigEntry* CryptKeyHolder::getEntry(CheckStatusWrapper* status, const char* entryName)
{
ISC_STATUS_ARRAY vector;
vector[0] = isc_arg_gds;
vector[1] = isc_random;
vector[2] = isc_arg_string;
vector[3] = (ISC_STATUS) "Key not set";
vector[4] = isc_arg_end;
status->setErrors(vector);
IConfig* def = config->getDefaultConfig(status);
if (status->getState() & Firebird::IStatus::STATE_ERRORS)
return NULL;

IConfigEntry* confEntry = def->find(status, entryName);
def->release();
if (status->getState() & Firebird::IStatus::STATE_ERRORS)
return NULL;

return confEntry;
}

int CryptKeyHolder::keyCallback(CheckStatusWrapper* status, ICryptKeyCallback* callback)
Expand All @@ -195,14 +220,7 @@ int CryptKeyHolder::keyCallback(CheckStatusWrapper* status, ICryptKeyCallback* c
if (key != 0)
return 1;

IConfig* def = config->getDefaultConfig(status);
if (status->getState() & Firebird::IStatus::STATE_ERRORS)
return 1;

IConfigEntry* confEntry = def->find(status, "Auto");
def->release();
if (status->getState() & Firebird::IStatus::STATE_ERRORS)
return 1;
IConfigEntry* confEntry = getEntry(status, "Auto");

if (confEntry)
{
Expand All @@ -226,12 +244,33 @@ int CryptKeyHolder::keyCallback(CheckStatusWrapper* status, ICryptKeyCallback* c

ICryptKeyCallback* CryptKeyHolder::keyHandle(CheckStatusWrapper* status, const char* keyName)
{
if (strcmp(keyName, "sample") != 0)
if (keyName[0] == 0)
return &callbackInterface;

for (NamedCallback* n = named; n; n = n->next)
{
return NULL;
if (strcmp(keyName, n->name) == 0)
return n;
}

char kn[40];
strcpy(kn, "Key");
strncat(kn, keyName, sizeof(kn));
kn[sizeof(kn) - 1] = 0;

IConfigEntry* confEntry = getEntry(status, kn);
if (confEntry)
{
UCHAR k = confEntry->getIntValue();
confEntry->release();
if (k > 0 && k < 256)
{
named = new NamedCallback(named, keyName, static_cast<UCHAR>(k));
return named;
}
}

return &callbackInterface;
return NULL;
}

class Factory : public IPluginFactoryImpl<Factory, CheckStatusWrapper>
Expand Down
23 changes: 19 additions & 4 deletions examples/dbcrypt/DbCrypt.cpp
Expand Up @@ -95,7 +95,8 @@ class DbCrypt : public IDbCryptPluginImpl<DbCrypt, CheckStatusWrapper>
// ICryptPlugin implementation
void encrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to);
void decrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to);
void setKey(CheckStatusWrapper* status, unsigned int length, IKeyHolderPlugin** sources);
void setKey(CheckStatusWrapper* status, const char* keyName,
unsigned int length, IKeyHolderPlugin** sources);

int release()
{
Expand Down Expand Up @@ -129,6 +130,7 @@ class DbCrypt : public IDbCryptPluginImpl<DbCrypt, CheckStatusWrapper>

private:
IPluginConfig* config;
char savedKeyName[32];
UCHAR key;

AtomicCounter refCounter;
Expand All @@ -139,11 +141,20 @@ class DbCrypt : public IDbCryptPluginImpl<DbCrypt, CheckStatusWrapper>

void DbCrypt::noKeyError(CheckStatusWrapper* status)
{
char msg[100];
strcpy(msg, "Crypt key ");
if (savedKeyName[0])
{
strcat(msg, savedKeyName);
strcat(msg, " ");
}
strcat(msg, "not set");

ISC_STATUS_ARRAY vector;
vector[0] = isc_arg_gds;
vector[1] = isc_random;
vector[2] = isc_arg_string;
vector[3] = (ISC_STATUS)"Key not set";
vector[3] = (ISC_STATUS)msg;
vector[4] = isc_arg_end;
status->setErrors(vector);
}
Expand Down Expand Up @@ -186,13 +197,17 @@ void DbCrypt::decrypt(CheckStatusWrapper* status, unsigned int length, const voi
}
}

void DbCrypt::setKey(CheckStatusWrapper* status, unsigned int length, IKeyHolderPlugin** sources)
void DbCrypt::setKey(CheckStatusWrapper* status, const char* keyName,
unsigned int length, IKeyHolderPlugin** sources)
{
status->init();

if (key != 0)
return;

strncpy(savedKeyName, keyName ? keyName : "", sizeof(savedKeyName));
savedKeyName[sizeof(savedKeyName) - 1] = 0;

IConfig* def = config->getDefaultConfig(status);
if (status->getState() & Firebird::IStatus::STATE_ERRORS)
return;
Expand Down Expand Up @@ -230,7 +245,7 @@ void DbCrypt::setKey(CheckStatusWrapper* status, unsigned int length, IKeyHolder

for (unsigned n = 0; n < length; ++n)
{
ICryptKeyCallback* callback = sources[n]->keyHandle(status, "sample");
ICryptKeyCallback* callback = sources[n]->keyHandle(status, savedKeyName);
if (status->getState() & Firebird::IStatus::STATE_ERRORS)
return;

Expand Down
4 changes: 4 additions & 0 deletions lang_helpers/gds_codes.ftn
Expand Up @@ -1626,6 +1626,10 @@ C --
PARAMETER (GDS__login_error = 335545106)
INTEGER*4 GDS__already_opened
PARAMETER (GDS__already_opened = 335545107)
INTEGER*4 GDS__bad_crypt_key
PARAMETER (GDS__bad_crypt_key = 335545108)
INTEGER*4 GDS__encrypt_error
PARAMETER (GDS__encrypt_error = 335545109)
INTEGER*4 GDS__gfix_db_name
PARAMETER (GDS__gfix_db_name = 335740929)
INTEGER*4 GDS__gfix_invalid_sw
Expand Down
4 changes: 4 additions & 0 deletions lang_helpers/gds_codes.pas
Expand Up @@ -1621,6 +1621,10 @@
gds_login_error = 335545106;
isc_already_opened = 335545107;
gds_already_opened = 335545107;
isc_bad_crypt_key = 335545108;
gds_bad_crypt_key = 335545108;
isc_encrypt_error = 335545109;
gds_encrypt_error = 335545109;
isc_gfix_db_name = 335740929;
gds_gfix_db_name = 335740929;
isc_gfix_invalid_sw = 335740930;
Expand Down
9 changes: 9 additions & 0 deletions src/common/classes/ClumpletReader.cpp
Expand Up @@ -29,6 +29,7 @@
#include "firebird.h"

#include "../common/classes/ClumpletReader.h"
#include "../common/classes/MetaName.h"
#include "fb_exception.h"

#include "../jrd/ibase.h"
Expand Down Expand Up @@ -784,6 +785,14 @@ string& ClumpletReader::getString(string& str) const
return str;
}

MetaName& ClumpletReader::getString(MetaName& str) const
{
const UCHAR* ptr = getBytes();
const FB_SIZE_T length = getClumpLength();
str.assign(reinterpret_cast<const char*>(ptr), length);
return str;
}

PathName& ClumpletReader::getPath(PathName& str) const
{
const UCHAR* ptr = getBytes();
Expand Down
3 changes: 3 additions & 0 deletions src/common/classes/ClumpletReader.h
Expand Up @@ -40,6 +40,8 @@

namespace Firebird {

class MetaName;

// This class provides read access for clumplet structure
// Note: it doesn't make a copy of buffer it reads
class ClumpletReader : protected AutoStorage
Expand Down Expand Up @@ -100,6 +102,7 @@ class ClumpletReader : protected AutoStorage
bool getBoolean() const;
SINT64 getBigInt() const;
string& getString(string& str) const;
MetaName& getString(MetaName& str) const;
PathName& getPath(PathName& str) const;
void getData(UCharBuffer& data) const;
const UCHAR* getBytes() const;
Expand Down
15 changes: 13 additions & 2 deletions src/common/classes/ClumpletWriter.cpp
Expand Up @@ -30,6 +30,7 @@
#include "firebird.h"

#include "../common/classes/ClumpletWriter.h"
#include "../common/classes/MetaName.h"
#include "fb_exception.h"

#include "../jrd/ibase.h"
Expand Down Expand Up @@ -183,7 +184,7 @@ void ClumpletWriter::reset(const UCHAR* buffer, const FB_SIZE_T buffLen)
}
else
{
UCHAR tag = (kind == SpbStart || kind == UnTagged || kind == WideUnTagged) ? getBufferTag() : 0;
UCHAR tag = (kind == SpbStart || kind == UnTagged || kind == WideUnTagged) ? 0 : getBufferTag();
initNewBuffer(tag);
}
rewind();
Expand Down Expand Up @@ -250,16 +251,26 @@ void ClumpletWriter::insertString(UCHAR tag, const string& str)
insertString(tag, str.c_str(), str.length());
}

void ClumpletWriter::insertPath(UCHAR tag, const PathName& str)
void ClumpletWriter::insertString(UCHAR tag, const MetaName& str)
{
insertString(tag, str.c_str(), str.length());
}

void ClumpletWriter::insertString(UCHAR tag, const char* str)
{
insertString(tag, str, strlen(str));
}

void ClumpletWriter::insertString(UCHAR tag, const char* str, FB_SIZE_T length)
{
insertBytesLengthCheck(tag, str, length);
}

void ClumpletWriter::insertPath(UCHAR tag, const PathName& str)
{
insertString(tag, str.c_str(), str.length());
}

void ClumpletWriter::insertBytes(UCHAR tag, const void* bytes, FB_SIZE_T length)
{
insertBytesLengthCheck(tag, bytes, length);
Expand Down
2 changes: 2 additions & 0 deletions src/common/classes/ClumpletWriter.h
Expand Up @@ -73,7 +73,9 @@ class ClumpletWriter : public ClumpletReader
void insertBigInt(UCHAR tag, const SINT64 value);
void insertBytes(UCHAR tag, const void* bytes, FB_SIZE_T length);
void insertString(UCHAR tag, const string& str);
void insertString(UCHAR tag, const MetaName& str);
void insertPath(UCHAR tag, const PathName& str);
void insertString(UCHAR tag, const char* str);
void insertString(UCHAR tag, const char* str, FB_SIZE_T length);
void insertByte(UCHAR tag, const UCHAR byte);
void insertTag(UCHAR tag);
Expand Down
3 changes: 2 additions & 1 deletion src/dsql/DdlNodes.epp
Expand Up @@ -11577,6 +11577,7 @@ string AlterDatabaseNode::internalPrint(NodePrinter& printer) const
NODE_PRINT(printer, setDefaultCollation);
NODE_PRINT(printer, files);
NODE_PRINT(printer, cryptPlugin);
NODE_PRINT(printer, keyName);

return "AlterDatabaseNode";
}
Expand Down Expand Up @@ -11660,7 +11661,7 @@ void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
if (clauses & CLAUSE_CRYPT)
{
Database* const db = tdbb->getDatabase();
db->dbb_crypto_manager->prepareChangeCryptState(tdbb, cryptPlugin);
db->dbb_crypto_manager->prepareChangeCryptState(tdbb, cryptPlugin, keyName);

DFW_post_work(transaction, dfw_db_crypt, cryptPlugin.c_str(), 0);
}
Expand Down
4 changes: 3 additions & 1 deletion src/dsql/DdlNodes.h
Expand Up @@ -2228,7 +2228,8 @@ class AlterDatabaseNode : public DdlNode
setDefaultCharSet(p),
setDefaultCollation(p),
files(p),
cryptPlugin(p)
cryptPlugin(p),
keyName(p)
{
}

Expand Down Expand Up @@ -2263,6 +2264,7 @@ class AlterDatabaseNode : public DdlNode
Firebird::MetaName setDefaultCollation;
Firebird::Array<NestConst<DbFileClause> > files;
Firebird::MetaName cryptPlugin;
Firebird::MetaName keyName;
};


Expand Down
8 changes: 7 additions & 1 deletion src/dsql/parse.y
Expand Up @@ -3961,7 +3961,7 @@ db_alter_clause($alterDatabaseNode)
{ $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_END_BACKUP; }
| SET DEFAULT CHARACTER SET symbol_character_set_name
{ $alterDatabaseNode->setDefaultCharSet = *$5; }
| ENCRYPT WITH valid_symbol_name
| ENCRYPT WITH valid_symbol_name crypt_key_clause($alterDatabaseNode)
{
setClauseFlag($alterDatabaseNode->clauses, AlterDatabaseNode::CLAUSE_CRYPT, "CRYPT");
$alterDatabaseNode->cryptPlugin = *$3;
Expand All @@ -3974,6 +3974,12 @@ db_alter_clause($alterDatabaseNode)
{ $alterDatabaseNode->linger = 0; }
;

%type crypt_key_clause(<alterDatabaseNode>)
crypt_key_clause($alterDatabaseNode)
: /* nothing */
| KEY valid_symbol_name
{ $alterDatabaseNode->keyName = *$2; }
;

// ALTER TRIGGER

Expand Down

0 comments on commit bebf1d5

Please sign in to comment.