mirror of
https://github.com/rsyslog/rsyslog.git
synced 2025-12-16 16:50:40 +01:00
Async service send timeout is not configurable and request cache size is too small to handle large amount of signing requests with small amount of permitted requests per aggregation round. For example user with max_requests = 4 results cache size 5 * max_requests or at least 256. When signing 300 log files cache will be too small resulting several unsigned blocks. When signing 200 log file cache will be adequate, but with rate of 4 signatures per second, it is only possible to sign 4 * 10 blocks before all requests that are not sent out will timeout. Fix for the issue is to make send timeout configurable and make the size of the cache depend on the value of send timeout. New configuration value sig.block.signtimeout="time, s" introduced that defines the time window wherein the block has to be signed. The size of the request cache is increased to 3 * max_requests * sign_timeout or at least 256.
347 lines
12 KiB
C
347 lines
12 KiB
C
/* lmsig_ksi-ls12.c
|
|
*
|
|
* An implementation of the sigprov interface for KSI-LS12.
|
|
*
|
|
* Copyright 2013-2017 Adiscon GmbH and Guardtime, Inc.
|
|
*
|
|
* This file is part of the rsyslog runtime library.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
* -or-
|
|
* see COPYING.ASL20 in the source distribution
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#include "config.h"
|
|
|
|
#include "rsyslog.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "module-template.h"
|
|
#include "glbl.h"
|
|
#include "errmsg.h"
|
|
#include "sigprov.h"
|
|
#include "lmsig_ksi-ls12.h"
|
|
|
|
MODULE_TYPE_LIB
|
|
MODULE_TYPE_NOKEEP
|
|
|
|
/* static data */
|
|
DEFobjStaticHelpers
|
|
DEFobjCurrIf(glbl)
|
|
|
|
/* tables for interfacing with the v6 config system */
|
|
static struct cnfparamdescr cnfpdescr[] = {
|
|
{ "sig.hashfunction", eCmdHdlrGetWord, 0 },
|
|
{ "sig.aggregator.url", eCmdHdlrGetWord, CNFPARAM_REQUIRED},
|
|
{ "sig.aggregator.user", eCmdHdlrGetWord, 0},
|
|
{ "sig.aggregator.key", eCmdHdlrGetWord, 0},
|
|
{ "sig.aggregator.hmacAlg", eCmdHdlrGetWord, 0 },
|
|
{ "sig.block.levelLimit", eCmdHdlrSize, CNFPARAM_REQUIRED},
|
|
{ "sig.block.timeLimit", eCmdHdlrInt, 0},
|
|
{ "sig.block.signtimeout", eCmdHdlrInt, 0},
|
|
{ "sig.confinterval", eCmdHdlrInt, 0},
|
|
{ "sig.keeprecordhashes", eCmdHdlrBinary, 0 },
|
|
{ "sig.keeptreehashes", eCmdHdlrBinary, 0},
|
|
{ "sig.fileformat", eCmdHdlrString, 0},
|
|
{ "sig.syncmode", eCmdHdlrString, 0},
|
|
{ "sig.randomsource", eCmdHdlrString, 0},
|
|
{ "sig.debugfile", eCmdHdlrString, 0},
|
|
{ "sig.debuglevel", eCmdHdlrInt, 0},
|
|
{ "dirowner", eCmdHdlrUID, 0}, /* legacy: dirowner */
|
|
{ "dirownernum", eCmdHdlrInt, 0 }, /* legacy: dirownernum */
|
|
{ "dirgroup", eCmdHdlrGID, 0 }, /* legacy: dirgroup */
|
|
{ "dirgroupnum", eCmdHdlrInt, 0 }, /* legacy: dirgroupnum */
|
|
{ "fileowner", eCmdHdlrUID, 0 }, /* legacy: fileowner */
|
|
{ "fileownernum", eCmdHdlrInt, 0 }, /* legacy: fileownernum */
|
|
{ "filegroup", eCmdHdlrGID, 0 }, /* legacy: filegroup */
|
|
{ "filegroupnum", eCmdHdlrInt, 0 }, /* legacy: filegroupnum */
|
|
{ "dircreatemode", eCmdHdlrFileCreateMode, 0 }, /* legacy: dircreatemode */
|
|
{ "filecreatemode", eCmdHdlrFileCreateMode, 0 } /* legacy: filecreatemode */
|
|
};
|
|
static struct cnfparamblk pblk =
|
|
{ CNFPARAMBLK_VERSION,
|
|
sizeof(cnfpdescr)/sizeof(struct cnfparamdescr),
|
|
cnfpdescr
|
|
};
|
|
|
|
|
|
static void
|
|
errfunc(__attribute__((unused)) void *usrptr, uchar *emsg)
|
|
{
|
|
LogError(0, RS_RET_SIGPROV_ERR, "KSI Signature Provider"
|
|
"Error: %s", emsg);
|
|
}
|
|
|
|
static void
|
|
logfunc(__attribute__((unused)) void *usrptr, uchar *emsg)
|
|
{
|
|
LogMsg(0, RS_RET_NO_ERRCODE, LOG_INFO,
|
|
"KSI/LS12 Signature Provider: %s", emsg);
|
|
}
|
|
|
|
|
|
/* Standard-Constructor
|
|
*/
|
|
BEGINobjConstruct(lmsig_ksi_ls12)
|
|
pThis->ctx = rsksiCtxNew();
|
|
rsksisetErrFunc(pThis->ctx, errfunc, NULL);
|
|
rsksisetLogFunc(pThis->ctx, logfunc, NULL);
|
|
ENDobjConstruct(lmsig_ksi_ls12)
|
|
|
|
|
|
/* destructor for the lmsig_ksi object */
|
|
BEGINobjDestruct(lmsig_ksi_ls12) /* be sure to specify the object type also in END and CODESTART macros! */
|
|
CODESTARTobjDestruct(lmsig_ksi_ls12)
|
|
rsksiCtxDel(pThis->ctx);
|
|
ENDobjDestruct(lmsig_ksi_ls12)
|
|
|
|
#define REPORT_PARAM_MISSING(param) \
|
|
do { \
|
|
pThis->ctx->disabled = true; \
|
|
LogError(0, RS_RET_ERR, "%s missing - signing disabled", param); \
|
|
/* TODO: ABORT_FINALIZE actually is useless because the return value is not checked by the caller*/ \
|
|
ABORT_FINALIZE(RS_RET_KSI_ERR); \
|
|
} while(0)
|
|
|
|
|
|
|
|
/* apply all params from param block to us. This must be called
|
|
* after construction, but before the OnFileOpen() entry point.
|
|
* Defaults are expected to have been set during construction.
|
|
*/
|
|
static rsRetVal
|
|
SetCnfParam(void *pT, struct nvlst *lst)
|
|
{
|
|
char *ag_uri = NULL, *ag_loginid = NULL, *ag_key = NULL;
|
|
char *hash=NULL, *hmac = NULL;
|
|
lmsig_ksi_ls12_t *pThis = (lmsig_ksi_ls12_t*) pT;
|
|
int i;
|
|
uchar *cstr;
|
|
struct cnfparamvals *pvals;
|
|
DEFiRet;
|
|
pvals = nvlstGetParams(lst, &pblk, NULL);
|
|
if(pvals == NULL) {
|
|
LogError(0, RS_RET_ERR, "Failed to load configuration - signing disabled");
|
|
pThis->ctx->disabled=true;
|
|
ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
|
|
}
|
|
if(Debug) {
|
|
dbgprintf("sig param blk in lmsig_ksi:\n");
|
|
cnfparamsPrint(&pblk, pvals);
|
|
}
|
|
|
|
for(i = 0 ; i < pblk.nParams ; ++i) {
|
|
if(!pvals[i].bUsed)
|
|
continue;
|
|
if(!strcmp(pblk.descr[i].name, "sig.hashfunction")) {
|
|
hash = (char*) es_str2cstr(pvals[i].val.d.estr, NULL);
|
|
} else if (!strcmp(pblk.descr[i].name, "sig.aggregator.url")) {
|
|
ag_uri = es_str2cstr(pvals[i].val.d.estr, NULL);
|
|
} else if(!strcmp(pblk.descr[i].name, "sig.aggregator.user")) {
|
|
ag_loginid = es_str2cstr(pvals[i].val.d.estr, NULL);
|
|
} else if (!strcmp(pblk.descr[i].name, "sig.aggregator.key")) {
|
|
ag_key = es_str2cstr(pvals[i].val.d.estr, NULL);
|
|
} else if(!strcmp(pblk.descr[i].name, "sig.aggregator.hmacAlg")) {
|
|
hmac = (char*) es_str2cstr(pvals[i].val.d.estr, NULL);
|
|
} else if (!strcmp(pblk.descr[i].name, "sig.block.levelLimit")) {
|
|
if (pvals[i].val.d.n < 2) {
|
|
LogError(0, RS_RET_ERR, "sig.block.levelLimit "
|
|
"%llu invalid - signing disabled", pvals[i].val.d.n);
|
|
pThis->ctx->disabled = true;
|
|
} else {
|
|
rsksiSetBlockLevelLimit(pThis->ctx, pvals[i].val.d.n);
|
|
}
|
|
} else if (!strcmp(pblk.descr[i].name, "sig.block.timeLimit")) {
|
|
if (pvals[i].val.d.n < 0) {
|
|
LogError(0, RS_RET_ERR, "sig.block.timeLimit "
|
|
"%llu invalid - signing disabled", pvals[i].val.d.n);
|
|
pThis->ctx->disabled = true;
|
|
} else {
|
|
rsksiSetBlockTimeLimit(pThis->ctx, pvals[i].val.d.n);
|
|
}
|
|
} else if (!strcmp(pblk.descr[i].name, "sig.confinterval")) {
|
|
if (pvals[i].val.d.n < 0) {
|
|
LogError(0, RS_RET_ERR, "sig.confinterval "
|
|
"%llu invalid - signing disabled", pvals[i].val.d.n);
|
|
pThis->ctx->disabled = true;
|
|
} else {
|
|
rsksiSetConfInterval(pThis->ctx, pvals[i].val.d.n);
|
|
}
|
|
} else if (!strcmp(pblk.descr[i].name, "sig.keeprecordhashes")) {
|
|
rsksiSetKeepRecordHashes(pThis->ctx, pvals[i].val.d.n);
|
|
} else if (!strcmp(pblk.descr[i].name, "sig.block.signtimeout")) {
|
|
if (pvals[i].val.d.n < 0) {
|
|
LogError(0, RS_RET_ERR, "sig.block.signtimeout "
|
|
"%llu invalid - signing disabled", pvals[i].val.d.n);
|
|
pThis->ctx->disabled = true;
|
|
} else {
|
|
rsksiSetBlockSigTimeout(pThis->ctx, pvals[i].val.d.n);
|
|
}
|
|
} else if(!strcmp(pblk.descr[i].name, "sig.keeptreehashes")) {
|
|
rsksiSetKeepTreeHashes(pThis->ctx, pvals[i].val.d.n);
|
|
} else if (!strcmp(pblk.descr[i].name, "sig.syncmode")) {
|
|
cstr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
|
|
if (!strcasecmp((char*) cstr, "sync")) rsksiSetSyncMode(pThis->ctx, LOGSIG_SYNCHRONOUS);
|
|
else if (!strcasecmp((char*) cstr, "async")) rsksiSetSyncMode(pThis->ctx, LOGSIG_ASYNCHRONOUS);
|
|
else LogError(0, RS_RET_ERR, "sig.syncmode '%s' unknown - using default", cstr);
|
|
free(cstr);
|
|
} else if (!strcmp(pblk.descr[i].name, "sig.randomsource")) {
|
|
cstr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
|
|
rsksiSetRandomSource(pThis->ctx, (char*) cstr);
|
|
free(cstr);
|
|
} else if (!strcmp(pblk.descr[i].name, "sig.debugfile")) {
|
|
cstr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
|
|
rsksiSetDebugFile(pThis->ctx, (char*) cstr);
|
|
free(cstr);
|
|
} else if (!strcmp(pblk.descr[i].name, "sig.debuglevel")) {
|
|
rsksiSetDebugLevel(pThis->ctx, pvals[i].val.d.n);
|
|
} else if (!strcmp(pblk.descr[i].name, "dirowner")) {
|
|
rsksiSetDirUID(pThis->ctx, pvals[i].val.d.n);
|
|
} else if (!strcmp(pblk.descr[i].name, "dirownernum")) {
|
|
rsksiSetDirUID(pThis->ctx, pvals[i].val.d.n);
|
|
} else if (!strcmp(pblk.descr[i].name, "dirgroup")) {
|
|
rsksiSetDirGID(pThis->ctx, pvals[i].val.d.n);
|
|
} else if (!strcmp(pblk.descr[i].name, "dirgroupnum")) {
|
|
rsksiSetDirGID(pThis->ctx, pvals[i].val.d.n);
|
|
} else if (!strcmp(pblk.descr[i].name, "fileowner")) {
|
|
rsksiSetFileUID(pThis->ctx, pvals[i].val.d.n);
|
|
} else if (!strcmp(pblk.descr[i].name, "fileownernum")) {
|
|
rsksiSetFileUID(pThis->ctx, pvals[i].val.d.n);
|
|
} else if (!strcmp(pblk.descr[i].name, "filegroup")) {
|
|
rsksiSetFileGID(pThis->ctx, pvals[i].val.d.n);
|
|
} else if (!strcmp(pblk.descr[i].name, "filegroupnum")) {
|
|
rsksiSetFileGID(pThis->ctx, pvals[i].val.d.n);
|
|
} else if (!strcmp(pblk.descr[i].name, "dircreatemode")) {
|
|
rsksiSetDirCreateMode(pThis->ctx, pvals[i].val.d.n);
|
|
} else if (!strcmp(pblk.descr[i].name, "filecreatemode")) {
|
|
rsksiSetCreateMode(pThis->ctx, pvals[i].val.d.n);
|
|
} else {
|
|
DBGPRINTF("lmsig_ksi: program error, non-handled "
|
|
"param '%s'\n", pblk.descr[i].name);
|
|
}
|
|
}
|
|
|
|
if(rsksiSetHashFunction(pThis->ctx, hash ? hash : (char*) "default") != KSI_OK) {
|
|
ABORT_FINALIZE(RS_RET_KSI_ERR);
|
|
}
|
|
|
|
if(rsksiSetHmacFunction(pThis->ctx, hmac ? hmac : (char*) "default") != KSI_OK) {
|
|
ABORT_FINALIZE(RS_RET_KSI_ERR);
|
|
}
|
|
|
|
if(rsksiSetAggregator(pThis->ctx, ag_uri, ag_loginid, ag_key) != KSI_OK) {
|
|
ABORT_FINALIZE(RS_RET_KSI_ERR);
|
|
}
|
|
|
|
finalize_it:
|
|
free(ag_uri);
|
|
free(ag_loginid);
|
|
free(ag_key);
|
|
free(hash);
|
|
free(hmac);
|
|
|
|
if(pvals != NULL)
|
|
cnfparamvalsDestruct(pvals, &pblk);
|
|
RETiRet;
|
|
}
|
|
|
|
|
|
static rsRetVal
|
|
OnFileOpen(void *pT, uchar *fn, void *pGF) {
|
|
lmsig_ksi_ls12_t *pThis = (lmsig_ksi_ls12_t*) pT;
|
|
ksifile *pgf = (ksifile*) pGF;
|
|
DEFiRet;
|
|
/* note: if *pgf is set to NULL, this auto-disables GT functions */
|
|
*pgf = rsksiCtxOpenFile(pThis->ctx, fn);
|
|
sigblkInitKSI(*pgf);
|
|
RETiRet;
|
|
}
|
|
|
|
/* Note: we assume that the record is terminated by a \n.
|
|
* As of the GuardTime paper, \n is not part of the signed
|
|
* message, so we subtract one from the record size. This
|
|
* may cause issues with non-standard formats, but let's
|
|
* see how things evolve (the verifier will not work in
|
|
* any case when the records are not \n delimited...).
|
|
* rgerhards, 2013-03-17
|
|
*/
|
|
static rsRetVal
|
|
OnRecordWrite(void *pF, uchar *rec, rs_size_t lenRec)
|
|
{
|
|
DEFiRet;
|
|
DBGPRINTF("lmsig_ksi-ls12: onRecordWrite (%d): %s\n", lenRec - 1, rec);
|
|
sigblkAddRecordKSI(pF, rec, lenRec - 1);
|
|
|
|
RETiRet;
|
|
}
|
|
|
|
static rsRetVal
|
|
OnFileClose(void *pF)
|
|
{
|
|
DEFiRet;
|
|
DBGPRINTF("lmsig_ksi_ls12: onFileClose\n");
|
|
rsksifileDestruct(pF);
|
|
|
|
RETiRet;
|
|
}
|
|
|
|
BEGINobjQueryInterface(lmsig_ksi_ls12)
|
|
CODESTARTobjQueryInterface(lmsig_ksi_ls12)
|
|
if (pIf->ifVersion != sigprovCURR_IF_VERSION) {/* check for current version, increment on each change */
|
|
ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED);
|
|
}
|
|
pIf->Construct = (rsRetVal(*)(void*)) lmsig_ksi_ls12Construct;
|
|
pIf->SetCnfParam = SetCnfParam;
|
|
pIf->Destruct = (rsRetVal(*)(void*)) lmsig_ksi_ls12Destruct;
|
|
pIf->OnFileOpen = OnFileOpen;
|
|
pIf->OnRecordWrite = OnRecordWrite;
|
|
pIf->OnFileClose = OnFileClose;
|
|
finalize_it:
|
|
ENDobjQueryInterface(lmsig_ksi_ls12)
|
|
|
|
|
|
BEGINObjClassExit(lmsig_ksi_ls12, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MACRO! */
|
|
CODESTARTObjClassExit(lmsig_ksi_ls12)
|
|
/* release objects we no longer need */
|
|
objRelease(glbl, CORE_COMPONENT);
|
|
ENDObjClassExit(lmsig_ksi_ls12)
|
|
|
|
|
|
BEGINObjClassInit(lmsig_ksi_ls12, 1, OBJ_IS_LOADABLE_MODULE) /* class, version */
|
|
/* request objects we use */
|
|
CHKiRet(objUse(glbl, CORE_COMPONENT));
|
|
ENDObjClassInit(lmsig_ksi_ls12)
|
|
|
|
|
|
/* --------------- here now comes the plumbing that makes as a library module --------------- */
|
|
|
|
|
|
BEGINmodExit
|
|
CODESTARTmodExit
|
|
lmsig_ksi_ls12ClassExit();
|
|
ENDmodExit
|
|
|
|
|
|
BEGINqueryEtryPt
|
|
CODESTARTqueryEtryPt
|
|
CODEqueryEtryPt_STD_LIB_QUERIES
|
|
ENDqueryEtryPt
|
|
|
|
|
|
BEGINmodInit()
|
|
CODESTARTmodInit
|
|
*ipIFVersProvided = CURR_MOD_IF_VERSION;
|
|
CHKiRet(lmsig_ksi_ls12ClassInit(pModInfo));
|
|
ENDmodInit
|