mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 15:23:03 +01:00
Added a sample of authentication plugin based on shared secret key
This commit is contained in:
parent
696673bca1
commit
57e7035411
@ -98,6 +98,11 @@ $(FIREBIRD)/examples/README:
|
||||
$(CP) $(ROOT)/examples/*.* $(FIREBIRD)/examples/
|
||||
$(CP) $(ROOT)/examples/api/*.* $(FIREBIRD)/examples/api/
|
||||
$(CP) $(ROOT)/examples/dbcrypt/*.* $(FIREBIRD)/examples/dbcrypt/
|
||||
$(CP) $(ROOT)/examples/extauth/* $(FIREBIRD)/examples/extauth/
|
||||
ifeq ($(TOMCRYPT_BUILD_FLG),Y)
|
||||
mkdir -p $(FIREBIRD)/examples/extauth/tomcrypt.include
|
||||
$(CP) $(ROOT)/extern/libtomcrypt/src/headers/* $(FIREBIRD)/examples/extauth/tomcrypt.include
|
||||
endif
|
||||
$(CP) $(ROOT)/examples/include/*.* $(FIREBIRD)/examples/include/
|
||||
$(CP) $(ROOT)/examples/interfaces/*.* $(FIREBIRD)/examples/interfaces/
|
||||
$(CP) $(ROOT)/examples/package/*.* $(FIREBIRD)/examples/package/
|
||||
|
@ -1216,6 +1216,7 @@ dnl # output
|
||||
mkdir -p gen/\$fb_tgt/firebird/examples/api
|
||||
mkdir -p gen/\$fb_tgt/firebird/examples/dbcrypt
|
||||
mkdir -p gen/\$fb_tgt/firebird/examples/empbuild
|
||||
mkdir -p gen/\$fb_tgt/firebird/examples/extauth
|
||||
mkdir -p gen/\$fb_tgt/firebird/examples/include
|
||||
mkdir -p gen/\$fb_tgt/firebird/examples/interfaces
|
||||
mkdir -p gen/\$fb_tgt/firebird/examples/package
|
||||
|
452
examples/extauth/ExtAuth.cpp
Normal file
452
examples/extauth/ExtAuth.cpp
Normal file
@ -0,0 +1,452 @@
|
||||
/*
|
||||
* Simple shared-key based authentication plugin
|
||||
* Each node (firebird server) contains same key which is used to authenticate cross-server
|
||||
* connections. Each connection coming from one node to another has on target same
|
||||
* login as it was on source node.
|
||||
*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* https://www.firebirdsql.org/en/initial-developer-s-public-license-version-1-0/
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Alexander Peshkoff
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2020 Alexander Peshkoff <peshkoff@mail.ru>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
|
||||
#include "TcWrapper.h"
|
||||
|
||||
#define HANDSHAKE_DEBUG(A)
|
||||
|
||||
const unsigned LOGINSIZE = 128u;
|
||||
const unsigned RANDSIZE = 32u;
|
||||
const unsigned SALTLEN = 8u;
|
||||
|
||||
typedef unsigned int ULong;
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
IMaster* master = NULL;
|
||||
|
||||
class PluginModule : public IPluginModuleImpl<PluginModule, ThrowStatusWrapper>
|
||||
{
|
||||
public:
|
||||
PluginModule()
|
||||
: pluginManager(NULL)
|
||||
{ }
|
||||
|
||||
~PluginModule()
|
||||
{
|
||||
if (pluginManager)
|
||||
{
|
||||
pluginManager->unregisterModule(this);
|
||||
doClean();
|
||||
}
|
||||
}
|
||||
|
||||
void registerMe(IPluginManager* m)
|
||||
{
|
||||
pluginManager = m;
|
||||
pluginManager->registerModule(this);
|
||||
}
|
||||
|
||||
void doClean()
|
||||
{
|
||||
pluginManager = NULL;
|
||||
}
|
||||
|
||||
void threadDetach()
|
||||
{ }
|
||||
|
||||
private:
|
||||
IPluginManager* pluginManager;
|
||||
};
|
||||
|
||||
|
||||
template <class P>
|
||||
class Factory : public IPluginFactoryImpl<Factory<P>, ThrowStatusWrapper>
|
||||
{
|
||||
public:
|
||||
// IPluginFactory implementation
|
||||
IPluginBase* createPlugin(ThrowStatusWrapper* status, IPluginConfig* factoryParameter)
|
||||
{
|
||||
IPluginBase* p = new P(status, factoryParameter);
|
||||
p->addRef();
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Common RSA helper
|
||||
//
|
||||
|
||||
class PluginData
|
||||
{
|
||||
public:
|
||||
PluginData(ThrowStatusWrapper* status, IPluginConfig* cnf)
|
||||
: refCounter(0), owner(NULL), iniLvl(0)
|
||||
{
|
||||
hash.init(status);
|
||||
iniLvl = 1;
|
||||
pseudoRand.init(status);
|
||||
iniLvl = 2;
|
||||
|
||||
AutoRelease<IConfig> conf(cnf->getDefaultConfig(status));
|
||||
if (!conf)
|
||||
return;
|
||||
AutoRelease<IConfigEntry> ce(conf->find(status, "Key"));
|
||||
if (!ce)
|
||||
return;
|
||||
|
||||
// import a key
|
||||
unsigned char key[4096];
|
||||
unsigned keySize = readHexKey(status, ce->getValue(), key, sizeof(key));
|
||||
check(status, rsa_import(key, keySize, &privateKey),
|
||||
"ExtAuth plugin failed to initialize - error importing private RSA key");
|
||||
iniLvl = 3;
|
||||
}
|
||||
|
||||
~PluginData()
|
||||
{
|
||||
if (iniLvl >= 3)
|
||||
rsa_free(&privateKey);
|
||||
if (iniLvl >= 2)
|
||||
pseudoRand.fini();
|
||||
if (iniLvl >= 1)
|
||||
hash.fini();
|
||||
}
|
||||
|
||||
protected:
|
||||
atomic<int> refCounter;
|
||||
IReferenceCounted* owner;
|
||||
|
||||
PseudoRandom pseudoRand;
|
||||
HashSha256 hash;
|
||||
rsa_key privateKey;
|
||||
int iniLvl;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Client plugin
|
||||
//
|
||||
|
||||
class ExtAuthClient : public IClientImpl<ExtAuthClient, ThrowStatusWrapper>, public PluginData
|
||||
{
|
||||
public:
|
||||
ExtAuthClient(ThrowStatusWrapper* status, IPluginConfig* cnf)
|
||||
: PluginData(status, cnf),
|
||||
ignorePassword(false),
|
||||
ignoreLogin(false)
|
||||
{
|
||||
AutoRelease<IConfig> conf(cnf->getDefaultConfig(status));
|
||||
if (conf)
|
||||
{
|
||||
AutoRelease<IConfigEntry> igPass(conf->find(status, "IgnorePassword"));
|
||||
if (igPass)
|
||||
ignorePassword = igPass->getBoolValue();
|
||||
AutoRelease<IConfigEntry> igLgn(conf->find(status, "IgnoreLogin"));
|
||||
if (igLgn)
|
||||
ignoreLogin = igLgn->getBoolValue();
|
||||
}
|
||||
}
|
||||
|
||||
// IClient implementation
|
||||
int authenticate(ThrowStatusWrapper* status, IClientBlock* cBlock);
|
||||
|
||||
int release()
|
||||
{
|
||||
if (--refCounter == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void addRef()
|
||||
{
|
||||
++refCounter;
|
||||
}
|
||||
|
||||
void setOwner(IReferenceCounted* o)
|
||||
{
|
||||
owner = o;
|
||||
}
|
||||
|
||||
IReferenceCounted* getOwner()
|
||||
{
|
||||
return owner;
|
||||
}
|
||||
|
||||
private:
|
||||
bool ignorePassword, ignoreLogin;
|
||||
};
|
||||
|
||||
int ExtAuthClient::authenticate(ThrowStatusWrapper* status, IClientBlock* cBlock)
|
||||
{
|
||||
try
|
||||
{
|
||||
// did we initialize correctly?
|
||||
if (iniLvl < 3)
|
||||
return AUTH_CONTINUE;
|
||||
|
||||
// check for missing login from the user
|
||||
if ((!ignoreLogin) && cBlock->getLogin())
|
||||
return AUTH_CONTINUE;
|
||||
|
||||
// check for missing password from the user
|
||||
if ((!ignorePassword) && cBlock->getPassword())
|
||||
return AUTH_CONTINUE;
|
||||
|
||||
// check for presence of authenticatiion block
|
||||
IAuthBlock* authBlock = cBlock->getAuthBlock(status);
|
||||
if (!authBlock)
|
||||
return AUTH_CONTINUE;
|
||||
if (!authBlock->first(status))
|
||||
return AUTH_CONTINUE;
|
||||
|
||||
// and for presence of user name in that authenticatiion block
|
||||
const char* login = NULL;
|
||||
do
|
||||
{
|
||||
const char* type = authBlock->getType();
|
||||
if (type && (strcmp(type, "USER") == 0))
|
||||
{
|
||||
login = authBlock->getName();
|
||||
if (login)
|
||||
break;
|
||||
}
|
||||
} while(authBlock->next(status));
|
||||
if (!login)
|
||||
return AUTH_CONTINUE;
|
||||
|
||||
// check if server started to talk to us
|
||||
unsigned dl = 0;
|
||||
const unsigned char* data = cBlock->getData(&dl);
|
||||
if (dl == 0 || !data)
|
||||
return AUTH_MORE_DATA;
|
||||
|
||||
// decrypt message
|
||||
unsigned char bytes[RANDSIZE + LOGINSIZE + 1];
|
||||
unsigned long outlen = RANDSIZE;
|
||||
int result = 0;
|
||||
check(status, rsa_decrypt_key(data, dl, bytes, &outlen, NULL, 0, hash.index, &result, &privateKey),
|
||||
"Error decrypting message");
|
||||
if (outlen < RANDSIZE)
|
||||
error(status, "Malformed data from server - missing random block");
|
||||
|
||||
// next append login to random block
|
||||
unsigned len = strlen(login);
|
||||
if (len > LOGINSIZE)
|
||||
len = LOGINSIZE;
|
||||
memcpy(&bytes[RANDSIZE], login, len);
|
||||
|
||||
// calc hash for whole block
|
||||
hash_state state;
|
||||
sha256_init(&state);
|
||||
check(status, sha256_process(&state, bytes, RANDSIZE + len), "Error hashing message");
|
||||
unsigned char digest[256 / 8];
|
||||
check(status, sha256_done(&state, digest), "Error extracting hash");
|
||||
|
||||
// build message
|
||||
unsigned char msg[4096];
|
||||
|
||||
// put login to it
|
||||
memcpy(msg, login, len);
|
||||
msg[len++] = 0;
|
||||
|
||||
// append sign of hash to it
|
||||
unsigned long signLen = sizeof(msg) - len;
|
||||
unsigned char* sign = &msg[len];
|
||||
check(status, rsa_sign_hash(digest, sizeof digest, sign, &signLen, &pseudoRand.state,
|
||||
pseudoRand.index, hash.index, SALTLEN, &privateKey), "Error signing message hash");
|
||||
|
||||
// send message
|
||||
cBlock->putData(status, len + signLen, msg);
|
||||
|
||||
// output the wire crypt key
|
||||
ICryptKey* cKey = cBlock->newKey(status);
|
||||
cKey->setSymmetric(status, "Symmetric", RANDSIZE, bytes);
|
||||
HANDSHAKE_DEBUG( fprintf(stderr, "Key ="); for (unsigned n = 0; n < RANDSIZE; ++n)
|
||||
fprintf(stderr, " %02u", bytes[n]); fprintf(stderr, "\n"); )
|
||||
|
||||
return AUTH_SUCCESS;
|
||||
}
|
||||
catch(const FbException& ex)
|
||||
{
|
||||
status->setErrors(ex.getStatus()->getErrors());
|
||||
return AUTH_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Server plugin
|
||||
//
|
||||
|
||||
class ExtAuthServer : public IServerImpl<ExtAuthServer, ThrowStatusWrapper>, public PluginData
|
||||
{
|
||||
public:
|
||||
ExtAuthServer(ThrowStatusWrapper* status, IPluginConfig* cnf)
|
||||
: PluginData(status, cnf), sentData(false)
|
||||
{ }
|
||||
|
||||
// IServer implementation
|
||||
int authenticate(ThrowStatusWrapper* status, IServerBlock* sBlock, IWriter* writerInterface);
|
||||
|
||||
void setDbCryptCallback(ThrowStatusWrapper* status, ICryptKeyCallback* cryptCallback)
|
||||
{ }
|
||||
|
||||
int release()
|
||||
{
|
||||
if (--refCounter == 0)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void addRef()
|
||||
{
|
||||
++refCounter;
|
||||
}
|
||||
|
||||
void setOwner(IReferenceCounted* o)
|
||||
{
|
||||
owner = o;
|
||||
}
|
||||
|
||||
IReferenceCounted* getOwner()
|
||||
{
|
||||
return owner;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned char msg[RANDSIZE + LOGINSIZE];
|
||||
bool sentData;
|
||||
};
|
||||
|
||||
|
||||
int ExtAuthServer::authenticate(ThrowStatusWrapper* status, IServerBlock* sBlock, IWriter* writerInterface)
|
||||
{
|
||||
try
|
||||
{
|
||||
// did we initialize correctly?
|
||||
if (iniLvl < 3)
|
||||
return AUTH_CONTINUE;
|
||||
|
||||
unsigned dl = 0;
|
||||
const unsigned char* data = sBlock->getData(&dl);
|
||||
if (!sentData)
|
||||
{
|
||||
// fbassert(dl == 0 && !data);
|
||||
|
||||
// build message: first of all get some randomness
|
||||
pseudoRand.getDsc()->read(msg, RANDSIZE, &pseudoRand.state);
|
||||
|
||||
// now encrypt that random block
|
||||
unsigned char encrypted[4096];
|
||||
unsigned long encLen = sizeof encrypted;
|
||||
check(status, rsa_encrypt_key(msg, RANDSIZE, encrypted, &encLen, NULL, 0,
|
||||
&pseudoRand.state, pseudoRand.index, hash.index, &privateKey), "Error encrypting message");
|
||||
|
||||
// send message
|
||||
sBlock->putData(status, encLen, encrypted);
|
||||
sentData = true;
|
||||
|
||||
return AUTH_MORE_DATA;
|
||||
}
|
||||
|
||||
// decompose message
|
||||
const char* login = reinterpret_cast<const char*>(data);
|
||||
unsigned len = strnlen(login, dl);
|
||||
if (len == dl)
|
||||
error(status, "Wrong data from client - no signature in a message");
|
||||
if (len == 0)
|
||||
error(status, "Wrong data from client - empty login");
|
||||
if (len > LOGINSIZE)
|
||||
error(status, "Wrong data from client - login too long");
|
||||
memcpy(&msg[RANDSIZE], data, len);
|
||||
const unsigned char* sign = &data[len + 1];
|
||||
unsigned long signLen = dl - (len + 1);
|
||||
|
||||
// calc hash for message
|
||||
hash_state state;
|
||||
sha256_init(&state);
|
||||
check(status, sha256_process(&state, msg, RANDSIZE + len), "Error hashing message");
|
||||
unsigned char digest[256 / 8];
|
||||
check(status, sha256_done(&state, digest), "Error extracting hash");
|
||||
|
||||
// validate signature
|
||||
int result = 0;
|
||||
int err = rsa_verify_hash(sign, signLen, digest, sizeof digest, hash.index, SALTLEN, &result, &privateKey);
|
||||
if (err != CRYPT_INVALID_PACKET)
|
||||
check(status, err, "Error verifying digital signature");
|
||||
else
|
||||
result = 0;
|
||||
if (!result)
|
||||
error(status, "Malformed data from client - invalid digital signature");
|
||||
|
||||
// output the wire crypt key
|
||||
ICryptKey* cKey = sBlock->newKey(status);
|
||||
cKey->setSymmetric(status, "Symmetric", RANDSIZE, msg);
|
||||
HANDSHAKE_DEBUG( fprintf(stderr, "Key ="); for (unsigned n = 0; n < RANDSIZE; ++n)
|
||||
fprintf(stderr, " %02x", msg[n]); fprintf(stderr, "\n"); )
|
||||
|
||||
// store received login name in auth block
|
||||
writerInterface->add(status, login);
|
||||
|
||||
return AUTH_SUCCESS;
|
||||
}
|
||||
catch(const FbException& ex)
|
||||
{
|
||||
status->setErrors(ex.getStatus()->getErrors());
|
||||
}
|
||||
return AUTH_FAILED;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Static variables
|
||||
//
|
||||
|
||||
PluginModule module;
|
||||
Factory<ExtAuthClient> clientFactory;
|
||||
Factory<ExtAuthServer> serverFactory;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define FB_DLL_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define FB_DLL_EXPORT
|
||||
#endif
|
||||
|
||||
extern "C" void FB_DLL_EXPORT FB_PLUGIN_ENTRY_POINT(IMaster* m)
|
||||
{
|
||||
master = m;
|
||||
IPluginManager* pluginManager = master->getPluginManager();
|
||||
|
||||
module.registerMe(pluginManager);
|
||||
pluginManager->registerPluginFactory(IPluginManager::TYPE_AUTH_CLIENT, "ExtAuth", &clientFactory);
|
||||
pluginManager->registerPluginFactory(IPluginManager::TYPE_AUTH_SERVER, "ExtAuth", &serverFactory);
|
||||
}
|
64
examples/extauth/INSTALL
Normal file
64
examples/extauth/INSTALL
Normal file
@ -0,0 +1,64 @@
|
||||
0. Brief description.
|
||||
|
||||
ExtAuth plugin is useful when you want to run 'execute statement on external' statement
|
||||
connecting to databases on non-local servers but do not wish to explicitly add login and
|
||||
password to your PL/SQL code. When 2 servers completely trust each other this plugin may
|
||||
be used to enable access to remote database without entering login and password in SQL
|
||||
code. To ensure that connection comes from trusted source shared secret key (placed into
|
||||
plugin's .conf file) is used. That means that the value of a "Key" parameter should be
|
||||
exacly the same for all trusting each other hosts. Pay attention - SQL name of connected
|
||||
user on remote host may not match local logon, it depends also upon mappings on remote
|
||||
host.
|
||||
|
||||
1. Before starting the build.
|
||||
|
||||
This authentication plugin is using TomCrypt (https://www.libtom.net/LibTomCrypt/) library.
|
||||
Firebird since v.4 is actively using it. Depending upon build type tomcrypt binary may be
|
||||
included or not included into your package. In a case when it's included you will find
|
||||
appropriate H-files in tomcrypt.include subdir. If not that means that native OS library
|
||||
is used and you should also work with it. Depending upon your OS you will may be need
|
||||
to install development package for tomcrypt.
|
||||
|
||||
2. Building plugin.
|
||||
|
||||
Type 'make' in this directory. Build system supposes that it was not moved out of standard
|
||||
firebird tree. In a case when you did it manually you will sooner of all have to change
|
||||
Makefile appropriately. If you use firebird with different operating systems and/or hardware
|
||||
you should build plugin for each used configuration.
|
||||
|
||||
3. Installing plugin.
|
||||
|
||||
Makefile has install target (make install) which may be used for current box. However
|
||||
this is not full solution because plugin is supposed to be used to connect at least two
|
||||
separate servers. See 'Testing' for more details.
|
||||
|
||||
4.Testing.
|
||||
|
||||
- imagine you have to hosts: host1 and host2;
|
||||
- generate configuration file using extauth_keygen utility on any of them (only ONCE -
|
||||
on ONE host !!!);
|
||||
- copy that file and plugin itself to $FIREBIRD/plugins directory on each host;
|
||||
- modife firebird.cond, it should contain something like:
|
||||
AuthServer = Srp256, ExtAuth
|
||||
AuthClient = Srp256, ExtAuth
|
||||
lines, certainly something else may be used instead recommended Srp256;
|
||||
- if you need WIN_SSPI plugin please add it AFTER ExtAuth;
|
||||
- do not forget to restart firebird after reconfiguring it;
|
||||
- create minimal required mapping on host1:
|
||||
CREATE MAPPING EXT USING PLUGIN EXTAUTH FROM ANY USER TO USER EXTUSER;
|
||||
- run the following script on host2:
|
||||
^SET TERM ^;
|
||||
EXECUTE BLOCK RETURNS(REMNAME CHAR(32)) AS BEGIN
|
||||
EXECUTE STATEMENT 'SELECT CURRENT_USER FROM RDB$DATABASE'
|
||||
ON EXTERNAL 'host1:employee' INTO :REMNAME;
|
||||
SUSPEND;
|
||||
END^
|
||||
SET TERM ;^
|
||||
you should get something like this:
|
||||
REMNAME
|
||||
==============================
|
||||
EXTUSER
|
||||
- explicitly specifying login and/or password in SQL statement normally deactivates
|
||||
this plugin but one can use IgnoreLogin and IgnorePassword parameters to change that.
|
||||
|
||||
|
78
examples/extauth/Makefile
Normal file
78
examples/extauth/Makefile
Normal file
@ -0,0 +1,78 @@
|
||||
# The contents of this file are subject to the Initial
|
||||
# Developer's Public License Version 1.0 (the "License");
|
||||
# you may not use this file except in compliance with the
|
||||
# License. You may obtain a copy of the License at
|
||||
# https://www.firebirdsql.org/en/initial-developer-s-public-license-version-1-0/
|
||||
#
|
||||
# Software distributed under the License is distributed AS IS,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing rights
|
||||
# and limitations under the License.
|
||||
#
|
||||
# The Original Code was created by Alexander Peshkoff
|
||||
# for the Firebird Open Source RDBMS project.
|
||||
#
|
||||
# Copyright (c) 2020 Alexander Peshkoff <peshkoff@mail.ru>
|
||||
# and all contributors signed below.
|
||||
#
|
||||
# All Rights Reserved.
|
||||
# Contributor(s): ______________________________________.
|
||||
|
||||
ROOT=../..
|
||||
#ROOT=$(shell cd ../..; pwd)
|
||||
|
||||
PLUGINS=$(ROOT)/plugins
|
||||
BIN=$(ROOT)/bin
|
||||
LIB=$(ROOT)/lib
|
||||
|
||||
LIB_PREFIX=lib
|
||||
SHRLIB_EXT=so
|
||||
|
||||
makePluginName=$(PLUGINS)/$(LIB_PREFIX)$(1).$(SHRLIB_EXT)
|
||||
|
||||
TOMCRYPT_COMPILE=-DLTC_PTHREAD -DUSE_LTM -DLTM_DESC
|
||||
OwnInclude=$(shell [ -d tomcrypt.include ] && echo Yes || echo No)
|
||||
ifeq ($(OwnInclude), Yes)
|
||||
TOMCRYPT_COMPILE += -Itomcrypt.include
|
||||
TOMCRYPT_LINK=-L$(LIB)/.tm
|
||||
endif
|
||||
BLD_SIMPLE_KEY_AUTH=libExtAuth.so
|
||||
SIMPLE_KEY_AUTH=$(call makePluginName,ExtAuth)
|
||||
BLD_KEYGEN=extauth_keygen
|
||||
KEYGEN=$(BIN)/$(BLD_KEYGEN)
|
||||
|
||||
KEYGEN_objects=keygen.o
|
||||
TCWRAP_objects=TcWrapper.o
|
||||
KEY_AUTH_objects=ExtAuth.o
|
||||
|
||||
CXXFLAGS=-std=c++11 -pthread -I$(ROOT)/include -fPIC $(TOMCRYPT_COMPILE)
|
||||
LDFLAGS=-pthread -L$(LIB) -Wl,-rpath,'$$ORIGIN/../lib' $(TOMCRYPT_LINK)
|
||||
|
||||
LINK=c++
|
||||
LINK_LIBS=-lfbclient -ltomcrypt
|
||||
|
||||
.PHONY: all keygen plugin install
|
||||
|
||||
all: keygen plugin
|
||||
|
||||
keygen: $(BLD_KEYGEN)
|
||||
|
||||
$(BLD_KEYGEN): $(KEYGEN_objects) $(TCWRAP_objects)
|
||||
$(LINK) $(LDFLAGS) $^ -o $@ $(LINK_LIBS)
|
||||
|
||||
plugin: $(BLD_SIMPLE_KEY_AUTH)
|
||||
|
||||
$(BLD_SIMPLE_KEY_AUTH): $(KEY_AUTH_objects) $(TCWRAP_objects)
|
||||
$(LINK) -shared $(LDFLAGS) $^ -o $@ $(LINK_LIBS)
|
||||
|
||||
clean:
|
||||
rm -f *.o* $(BLD_KEYGEN) $(BLD_SIMPLE_KEY_AUTH)
|
||||
|
||||
install: $(SIMPLE_KEY_AUTH) $(KEYGEN)
|
||||
|
||||
$(SIMPLE_KEY_AUTH): $(BLD_SIMPLE_KEY_AUTH)
|
||||
cp $^ $@
|
||||
|
||||
$(KEYGEN): $(BLD_KEYGEN)
|
||||
cp $^ $@
|
||||
|
122
examples/extauth/TcWrapper.cpp
Normal file
122
examples/extauth/TcWrapper.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Tomcrypt library <= firebird : c++ wrapper.
|
||||
*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* https://www.firebirdsql.org/en/initial-developer-s-public-license-version-1-0/
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Alexander Peshkoff
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2020 Alexander Peshkoff <peshkoff@mail.ru>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
#include "TcWrapper.h"
|
||||
|
||||
namespace {
|
||||
// LTC hack
|
||||
class GInit
|
||||
{
|
||||
public:
|
||||
GInit()
|
||||
{
|
||||
ltc_mp = ltm_desc;
|
||||
}
|
||||
};
|
||||
GInit gInit;
|
||||
}
|
||||
|
||||
void error(ThrowStatusWrapper* status, const char* text)
|
||||
{
|
||||
if (! status)
|
||||
throw text;
|
||||
|
||||
ISC_STATUS_ARRAY v;
|
||||
v[0] = isc_arg_gds;
|
||||
v[1] = isc_random;
|
||||
v[2] = isc_arg_string;
|
||||
v[3] = (ISC_STATUS) text;
|
||||
v[4] = isc_arg_end;
|
||||
|
||||
throw FbException(status, v);
|
||||
}
|
||||
|
||||
void check(ThrowStatusWrapper* status, int err, const char* text)
|
||||
{
|
||||
if (err == CRYPT_OK)
|
||||
return;
|
||||
|
||||
char buf[256];
|
||||
sprintf(buf, "%s: %s", text, error_to_string(err));
|
||||
error(status, buf);
|
||||
}
|
||||
|
||||
unsigned readHexKey(ThrowStatusWrapper* status, const char* hex, unsigned char* key, unsigned bufSize)
|
||||
{
|
||||
unsigned char* k = key;
|
||||
const char* const end = hex + strlen(hex) - 1;
|
||||
for (const char* s = hex; s < end; s += 2)
|
||||
{
|
||||
if (k - key >= bufSize)
|
||||
break;
|
||||
|
||||
// FF
|
||||
char ss[3];
|
||||
ss[0] = s[0];
|
||||
ss[1] = s[1];
|
||||
ss[2] = 0;
|
||||
unsigned c = strtoul(ss, NULL, 16);
|
||||
if (c > 255)
|
||||
error(status, "Key format error");
|
||||
*k++ = static_cast<unsigned char>(c);
|
||||
}
|
||||
return k - key;
|
||||
}
|
||||
|
||||
void PseudoRandom::init(ThrowStatusWrapper* status)
|
||||
{
|
||||
// LTC hack
|
||||
ltc_mp = ltm_desc;
|
||||
|
||||
// register yarrow
|
||||
index = register_prng(&yarrow_desc);
|
||||
if (index == -1)
|
||||
error(status, "Error registering PRNG yarrow");
|
||||
|
||||
// setup the PRNG
|
||||
check(status, yarrow_start(&state), "Error starting PRNG yarrow");
|
||||
check(status, rng_make_prng(64, index, &state, NULL), "Error setting up PRNG yarrow");
|
||||
}
|
||||
|
||||
void PseudoRandom::fini()
|
||||
{
|
||||
yarrow_done(&state);
|
||||
}
|
||||
|
||||
const PseudoRandom::PrngDescriptor* PseudoRandom::getDsc()
|
||||
{
|
||||
return &yarrow_desc;
|
||||
}
|
||||
|
||||
void Hash::init(ThrowStatusWrapper* status, const ltc_hash_descriptor* desc)
|
||||
{
|
||||
// LTC hack
|
||||
ltc_mp = ltm_desc;
|
||||
|
||||
/* register SHA256 */
|
||||
index = register_hash(desc);
|
||||
if (index == -1)
|
||||
error(status, "Error registering SHA256");
|
||||
}
|
||||
|
210
examples/extauth/TcWrapper.h
Normal file
210
examples/extauth/TcWrapper.h
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Tomcrypt library <= firebird : c++ wrapper.
|
||||
*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* https://www.firebirdsql.org/en/initial-developer-s-public-license-version-1-0/
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Alexander Peshkoff
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2020 Alexander Peshkoff <peshkoff@mail.ru>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
#include <tomcrypt.h>
|
||||
|
||||
#include <firebird/Interface.h>
|
||||
using namespace Firebird;
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void error(ThrowStatusWrapper* status, const char* text);
|
||||
void check(ThrowStatusWrapper* status, int err, const char* text);
|
||||
unsigned readHexKey(ThrowStatusWrapper* status, const char* hex, unsigned char* key, unsigned bufSize);
|
||||
|
||||
class PseudoRandom
|
||||
{
|
||||
public:
|
||||
#if CRYPT > 0x0100
|
||||
typedef ltc_prng_descriptor PrngDescriptor;
|
||||
#else
|
||||
typedef _prng_descriptor PrngDescriptor;
|
||||
#endif
|
||||
|
||||
void init(ThrowStatusWrapper* status);
|
||||
void fini();
|
||||
const PrngDescriptor* getDsc();
|
||||
|
||||
int index;
|
||||
prng_state state;
|
||||
};
|
||||
|
||||
class Hash
|
||||
{
|
||||
protected:
|
||||
void init(ThrowStatusWrapper* status, const ltc_hash_descriptor* desc);
|
||||
|
||||
public:
|
||||
void fini()
|
||||
{ }
|
||||
|
||||
int index;
|
||||
};
|
||||
|
||||
class HashSha1 : public Hash
|
||||
{
|
||||
public:
|
||||
void init(ThrowStatusWrapper* status)
|
||||
{
|
||||
Hash::init(status, &sha1_desc);
|
||||
}
|
||||
};
|
||||
|
||||
class HashSha256 : public Hash
|
||||
{
|
||||
public:
|
||||
void init(ThrowStatusWrapper* status)
|
||||
{
|
||||
Hash::init(status, &sha256_desc);
|
||||
}
|
||||
};
|
||||
|
||||
// controls reference counter of the object where points
|
||||
enum NoIncrement {NO_INCREMENT};
|
||||
template <typename T>
|
||||
class RefPtr
|
||||
{
|
||||
public:
|
||||
RefPtr() : ptr(NULL)
|
||||
{ }
|
||||
|
||||
explicit RefPtr(T* p) : ptr(p)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
ptr->addRef();
|
||||
}
|
||||
}
|
||||
|
||||
// This special form of ctor is used to create refcounted ptr from interface,
|
||||
// returned by a function (which increments counter on return)
|
||||
RefPtr(NoIncrement x, T* p) : ptr(p)
|
||||
{ }
|
||||
|
||||
RefPtr(const RefPtr& r) : ptr(r.ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
ptr->addRef();
|
||||
}
|
||||
}
|
||||
|
||||
~RefPtr()
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
ptr->release();
|
||||
}
|
||||
}
|
||||
|
||||
T* operator=(T* p)
|
||||
{
|
||||
return assign(p);
|
||||
}
|
||||
|
||||
T* operator=(const RefPtr& r)
|
||||
{
|
||||
return assign(r.ptr);
|
||||
}
|
||||
|
||||
operator T*()
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
T* operator->()
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
operator const T*() const
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const T* operator->() const
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool operator !() const
|
||||
{
|
||||
return !ptr;
|
||||
}
|
||||
|
||||
bool operator ==(const RefPtr& r) const
|
||||
{
|
||||
return ptr == r.ptr;
|
||||
}
|
||||
|
||||
bool operator !=(const RefPtr& r) const
|
||||
{
|
||||
return ptr != r.ptr;
|
||||
}
|
||||
|
||||
void clear() throw() // Used after detach/commit/close/etc., i.e. release() not needed
|
||||
{
|
||||
ptr = NULL;
|
||||
}
|
||||
|
||||
void assignNoIncrement(T* const p)
|
||||
{
|
||||
assign(NULL);
|
||||
ptr = p;
|
||||
}
|
||||
|
||||
private:
|
||||
T* assign(T* const p)
|
||||
{
|
||||
if (ptr != p)
|
||||
{
|
||||
if (p)
|
||||
{
|
||||
p->addRef();
|
||||
}
|
||||
|
||||
T* tmp = ptr;
|
||||
ptr = p;
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
tmp->release();
|
||||
}
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
T* ptr;
|
||||
};
|
||||
|
||||
// Often used form of RefPtr
|
||||
template <class R>
|
||||
class AutoRelease : public RefPtr<R>
|
||||
{
|
||||
public:
|
||||
AutoRelease(R* r)
|
||||
: RefPtr<R>(NO_INCREMENT, r)
|
||||
{ }
|
||||
};
|
73
examples/extauth/keygen.cpp
Normal file
73
examples/extauth/keygen.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* RSA key generate.
|
||||
*
|
||||
* The contents of this file are subject to the Initial
|
||||
* Developer's Public License Version 1.0 (the "License");
|
||||
* you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
* https://www.firebirdsql.org/en/initial-developer-s-public-license-version-1-0/
|
||||
*
|
||||
* Software distributed under the License is distributed AS IS,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing rights
|
||||
* and limitations under the License.
|
||||
*
|
||||
* The Original Code was created by Alexander Peshkoff
|
||||
* for the Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2020 Alexander Peshkoff <peshkoff@mail.ru>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
#include "TcWrapper.h"
|
||||
|
||||
int main(int ac, char** av)
|
||||
{
|
||||
try
|
||||
{
|
||||
int len = ac > 1 ? atoi(av[1]) : 2048;
|
||||
|
||||
PseudoRandom pseudoRand;
|
||||
pseudoRand.init(NULL);
|
||||
|
||||
rsa_key key;
|
||||
check(NULL, rsa_make_key(&pseudoRand.state, pseudoRand.index, len / 8, 65537, &key),
|
||||
"Error making RSA key");
|
||||
|
||||
unsigned char outbuf[4096];
|
||||
unsigned long outlen = sizeof outbuf;
|
||||
check(NULL, rsa_export(outbuf, &outlen, PK_PRIVATE, &key),
|
||||
"Error exporting private RSA key");
|
||||
|
||||
const char* const file = "ExtAuth.conf";
|
||||
FILE* conf = fopen(file, "w");
|
||||
if (!conf)
|
||||
{
|
||||
perror(file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(conf, "Key = ");
|
||||
for (unsigned i = 0; i < outlen; ++i)
|
||||
fprintf(conf, "%02x", outbuf[i]);
|
||||
fprintf(conf, "\n#IgnoreLogin = No\n#IgnorePassword = No\n");
|
||||
|
||||
if (fclose(conf) != 0)
|
||||
{
|
||||
perror(file);
|
||||
return 1;
|
||||
}
|
||||
printf("Wrote configuration file %s\n", file);
|
||||
}
|
||||
catch (const char* message)
|
||||
{
|
||||
fprintf(stderr, "%s\n", message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -65,7 +65,8 @@ stat12.e Event wait and signaling.
|
||||
stat12t.e
|
||||
|
||||
WHENEVER SQLERROR and BASED_ON clause are illustrated by many programs.
|
||||
^L
|
||||
|
||||
|
||||
|
||||
Embedded Dynamic SQL
|
||||
|
||||
@ -84,7 +85,8 @@ dyn5.e Demonstrate dynamic reallocation of SQLDA and 'describe' statement.
|
||||
dynfull.e A full_dsql program (process unknown statements).
|
||||
|
||||
VARY struct is used by dyn3.e, dynfull.e.
|
||||
^L
|
||||
|
||||
|
||||
|
||||
API Interface
|
||||
|
||||
@ -140,3 +142,42 @@ SQLCODE extraction from status is covered by several programs.
|
||||
Zero transaction handle is covered in several programs, ex. api14.e.
|
||||
|
||||
|
||||
|
||||
Object-oriented API (interfaces)
|
||||
|
||||
Program Description
|
||||
--------- --------------------------------------------------------
|
||||
01.create.cpp / A sample of creating new database and new table in it.
|
||||
01.create.pas Has pascal (delphi) implementation.
|
||||
|
||||
02.update.cpp UPDATE statement with parameters.
|
||||
|
||||
03.select.cpp SELECT statement without input parameters.
|
||||
|
||||
04.print_table.cpp Open cursor from attachment and access blob data.
|
||||
|
||||
05.user_metadata.cpp Cursor with user-implemented interface of message format.
|
||||
|
||||
06.fb_message.cpp Use of static messages and decfloat values.
|
||||
|
||||
07.blob.cpp Loading data into blob and reading it.
|
||||
|
||||
08.events.cpp Working with events.
|
||||
|
||||
09.service.cpp Using services: prints server version and db statistics.
|
||||
|
||||
10.backup.cpp Using services: backup database.
|
||||
|
||||
11.batch.cpp Working with batch interface.
|
||||
|
||||
12.batch_isc.cpp Working with batch interface from ISC API.
|
||||
|
||||
|
||||
FbSampleAtomic typedef required in many examples.
|
||||
|
||||
|
||||
|
||||
dbcrypt - a sample of XOR database encryption (do not use in production!!!)
|
||||
|
||||
extauth - authentication for cross-server connections based on having same secret key on all servers
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user