/* 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 #include #include #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