diff options
-rw-r--r-- | runtime/libgcry.c | 27 | ||||
-rw-r--r-- | runtime/libgcry.h | 4 | ||||
-rw-r--r-- | runtime/lmcry_gcry.c | 31 | ||||
-rw-r--r-- | runtime/stream.c | 5 | ||||
-rw-r--r-- | tools/Makefile.am | 17 | ||||
-rw-r--r-- | tools/omfile.c | 18 | ||||
-rw-r--r-- | tools/rscryutil.c | 236 | ||||
-rw-r--r-- | tools/rscryutil.rst | 80 |
8 files changed, 386 insertions, 32 deletions
diff --git a/runtime/libgcry.c b/runtime/libgcry.c index 8184c160..5f1dbf58 100644 --- a/runtime/libgcry.c +++ b/runtime/libgcry.c @@ -27,6 +27,7 @@ #include "rsyslog.h" #include "libgcry.h" +#define GCRY_CIPHER GCRY_CIPHER_3DES // TODO: make configurable static inline gcryfile gcryfileConstruct(gcryctx ctx) @@ -98,20 +99,34 @@ removePadding(char *buf, size_t *plen) done: return; } +/* returns 0 on succes, positive if key length does not match and key + * of return value size is required. + */ +int +rsgcrySetKey(gcryctx ctx, unsigned char *key, uint16_t keyLen) +{ + uint16_t reqKeyLen = gcry_cipher_get_algo_keylen(GCRY_CIPHER); + int r; + + if(keyLen != reqKeyLen) + r = reqKeyLen; + ctx->keyLen = keyLen; + ctx->key = malloc(keyLen); + memcpy(ctx->key, key, keyLen); + r = 0; +done: return r; +} + rsRetVal rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, int gcry_mode, char *iniVector) { - #define GCRY_CIPHER GCRY_CIPHER_3DES // TODO: make configurable - size_t keyLength; - char *aesSymKey = "123456789012345678901234"; // TODO: TEST ONLY - gcry_error_t gcryError; + gcry_error_t gcryError; gcryfile gf = NULL; DEFiRet; CHKmalloc(gf = gcryfileConstruct(ctx)); gf->blkLength = gcry_cipher_get_algo_blklen(GCRY_CIPHER); - keyLength = gcry_cipher_get_algo_keylen(GCRY_CIPHER); gcryError = gcry_cipher_open( &gf->chd, // gcry_cipher_hd_t * @@ -125,7 +140,7 @@ rsgcryInitCrypt(gcryctx ctx, gcryfile *pgf, int gcry_mode, char *iniVector) ABORT_FINALIZE(RS_RET_ERR); } - gcryError = gcry_cipher_setkey(gf->chd, aesSymKey, keyLength); + gcryError = gcry_cipher_setkey(gf->chd, gf->ctx->key, gf->ctx->keyLen); if (gcryError) { dbgprintf("gcry_cipher_setkey failed: %s/%s\n", gcry_strsource(gcryError), diff --git a/runtime/libgcry.h b/runtime/libgcry.h index 0405162f..608abd6c 100644 --- a/runtime/libgcry.h +++ b/runtime/libgcry.h @@ -24,7 +24,8 @@ struct gcryctx_s { - void *usrptr; /* for error function */ + uchar *key; + size_t keyLen; }; typedef struct gcryctx_s *gcryctx; typedef struct gcryfile_s *gcryfile; @@ -38,6 +39,7 @@ struct gcryfile_s { int rsgcryInit(void); void rsgcryExit(void); +int rsgcrySetKey(gcryctx ctx, unsigned char *key, uint16_t keyLen); gcryctx gcryCtxNew(void); void rsgcryCtxDel(gcryctx ctx); int gcryfileDestruct(gcryfile gf); diff --git a/runtime/lmcry_gcry.c b/runtime/lmcry_gcry.c index 6800055d..ce0fef2f 100644 --- a/runtime/lmcry_gcry.c +++ b/runtime/lmcry_gcry.c @@ -44,6 +44,7 @@ DEFobjCurrIf(glbl) /* tables for interfacing with the v6 config system */ static struct cnfparamdescr cnfpdescr[] = { + { "cry.key", eCmdHdlrGetWord, 0 }, { "cry.mode", eCmdHdlrGetWord, 0 }, /* CBC, ECB, etc */ { "cry.algo", eCmdHdlrGetWord, 0 } }; @@ -83,12 +84,13 @@ ENDobjDestruct(lmcry_gcry) * after construction, but before the OnFileOpen() entry point. * Defaults are expected to have been set during construction. */ -rsRetVal +static rsRetVal SetCnfParam(void *pT, struct nvlst *lst) { lmcry_gcry_t *pThis = (lmcry_gcry_t*) pT; - int i; + int i, r; uchar *cstr; + uchar *key = NULL; struct cnfparamvals *pvals; pvals = nvlstGetParams(lst, &pblk, NULL); if(Debug) { @@ -99,14 +101,9 @@ SetCnfParam(void *pT, struct nvlst *lst) for(i = 0 ; i < pblk.nParams ; ++i) { if(!pvals[i].bUsed) continue; + if(!strcmp(pblk.descr[i].name, "cry.key")) { + key = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); #if 0 - if(!strcmp(pblk.descr[i].name, "sig.hashfunction")) { - cstr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); - if(gcrySetHashFunction(pThis->ctx, (char*)cstr) != 0) { - errmsg.LogError(0, RS_RET_ERR, "Hash function " - "'%s' unknown - using default", cstr); - } - free(cstr); } else if(!strcmp(pblk.descr[i].name, "sig.timestampservice")) { cstr = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); gcrySetTimestamper(pThis->ctx, (char*) cstr); @@ -120,10 +117,24 @@ SetCnfParam(void *pT, struct nvlst *lst) } else { DBGPRINTF("lmcry_gcry: program error, non-handled " "param '%s'\n", pblk.descr[i].name); - } #endif + } } + if(key != NULL) { + errmsg.LogError(0, RS_RET_ERR, "Note: specifying an actual key directly from the " + "config file is highly insecure - DO NOT USE FOR PRODUCTION"); + r = rsgcrySetKey(pThis->ctx, key, strlen((char*)key)); + if(r > 0) { + errmsg.LogError(0, RS_RET_ERR, "Key length %d expected, but " + "key of length %d given", r, strlen((char*)key)); + } + } + cnfparamvalsDestruct(pvals, &pblk); + if(key != NULL) { + memset(key, 0, strlen((char*)key)); + free(key); + } return RS_RET_OK; } diff --git a/runtime/stream.c b/runtime/stream.c index 941fc39d..b31520b0 100644 --- a/runtime/stream.c +++ b/runtime/stream.c @@ -256,9 +256,8 @@ doPhysOpen(strm_t *pThis) dbgprintf("DDDD: cryprov %p\n", pThis->cryprov); if(pThis->cryprov != NULL) { - iRet = pThis->cryprov->OnFileOpen(pThis->cryprovData, - pThis->pszCurrFName, &pThis->cryprovFileData); -dbgprintf("DDDD: iREt cryprov->onFileOpen: %d\n", iRet); + CHKiRet(pThis->cryprov->OnFileOpen(pThis->cryprovData, + pThis->pszCurrFName, &pThis->cryprovFileData)); } finalize_it: RETiRet; diff --git a/tools/Makefile.am b/tools/Makefile.am index be093957..8957d713 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -42,6 +42,7 @@ rsyslogd_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) # potentially incomplete build, a problem we had several times...) rsyslogd_LDADD = ../grammar/libgrammar.la ../runtime/librsyslog.la $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBEE_LIBS) $(LIBLOGNORM_LIBS) $(LIBUUID_LIBS) rsyslogd_LDFLAGS = -export-dynamic `libgcrypt-config --libs` +#rsyslogd_LDFLAGS = -export-dynamic $(LIBGCRYPT_LIBS) EXTRA_DIST = $(man_MANS) \ rsgtutil.rst \ @@ -64,10 +65,6 @@ logctl_LDADD = $(LIBMONGO_CLIENT_LIBS) endif if ENABLE_GUARDTIME bin_PROGRAMS += rsgtutil -#bin_PROGRAMS += logsigner rsgtutil -#logsigner = logsigner.c -#logsigner_CPPFLAGS = $(RSRT_CFLAGS) $(GUARDTIME_CFLAGS) -#logsigner_LDADD = ../runtime/librsgt.la $(GUARDTIME_LIBS) rsgtutil = rsgtutil.c rsgtutil_CPPFLAGS = $(RSRT_CFLAGS) $(GUARDTIME_CFLAGS) rsgtutil_LDADD = ../runtime/librsgt.la $(GUARDTIME_LIBS) @@ -77,4 +74,16 @@ man1_MANS = rsgtutil.1 CLEANFILES = rsgtutil.1 EXTRA_DIST+= rsgtutil.1 endif +if ENABLE_LIBGCRYPT +bin_PROGRAMS += rscryutil +rscryutil = rscryutil.c +rscryutil_CPPFLAGS = $(RSRT_CFLAGS) $(LIBGCRYPT_CFLAGS) +rscryutil_LDFLAGS = `libgcrypt-config --libs` +#rscryutil_LDFLAGS = $(LIBGCRYPT_LIBS) +rscryutil.1: rscryutil.rst + $(AM_V_GEN) $(RST2MAN) $< $@ +man1_MANS = rscryutil.1 +CLEANFILES = rscryutil.1 +EXTRA_DIST+= rscryutil.1 +endif endif diff --git a/tools/omfile.c b/tools/omfile.c index dfd52d80..46d882bf 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -1054,17 +1054,18 @@ initSigprov(instanceData *pData, struct nvlst *lst) done: return; } -static inline void +static inline rsRetVal initCryprov(instanceData *pData, struct nvlst *lst) { uchar szDrvrName[1024]; + DEFiRet; if(snprintf((char*)szDrvrName, sizeof(szDrvrName), "lmcry_%s", pData->cryprovName) == sizeof(szDrvrName)) { errmsg.LogError(0, RS_RET_ERR, "omfile: crypto provider " "name is too long: '%s' - encryption disabled", pData->cryprovName); - goto done; + ABORT_FINALIZE(RS_RET_ERR); } pData->cryprovNameFull = ustrdup(szDrvrName); @@ -1079,21 +1080,22 @@ initCryprov(instanceData *pData, struct nvlst *lst) errmsg.LogError(0, RS_RET_LOAD_ERROR, "omfile: could not load " "crypto provider '%s' - encryption disabled", szDrvrName); - goto done; + ABORT_FINALIZE(RS_RET_CRYPROV_ERR); } if(pData->cryprov.Construct(&pData->cryprovData) != RS_RET_OK) { - errmsg.LogError(0, RS_RET_SIGPROV_ERR, "omfile: error constructing " + errmsg.LogError(0, RS_RET_CRYPROV_ERR, "omfile: error constructing " "crypto provider %s dataset - encryption disabled", szDrvrName); - goto done; + ABORT_FINALIZE(RS_RET_CRYPROV_ERR); } - pData->cryprov.SetCnfParam(pData->cryprovData, lst); + CHKiRet(pData->cryprov.SetCnfParam(pData->cryprovData, lst)); dbgprintf("loaded crypto provider %s, data instance at %p\n", szDrvrName, pData->cryprovData); pData->useCryprov = 1; -done: return; +finalize_it: + RETiRet; } BEGINnewActInst @@ -1184,7 +1186,7 @@ CODESTARTnewActInst } if(pData->cryprovName != NULL) { - initCryprov(pData, lst); + CHKiRet(initCryprov(pData, lst)); } tplToUse = ustrdup((pData->tplName == NULL) ? getDfltTpl() : pData->tplName); diff --git a/tools/rscryutil.c b/tools/rscryutil.c new file mode 100644 index 00000000..755371f2 --- /dev/null +++ b/tools/rscryutil.c @@ -0,0 +1,236 @@ +/* This is a tool for dumpoing the content of GuardTime TLV + * files in a (somewhat) human-readable manner. + * + * Copyright 2013 Adiscon GmbH + * + * This file is part of rsyslog. + * + * 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 exprs or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> +#include <getopt.h> +#include <gcrypt.h> + + +static enum { MD_DECRYPT +} mode = MD_DECRYPT; +static int verbose = 0; +static gcry_cipher_hd_t gcry_chd; +static size_t blkLength; + +static int +initCrypt(int gcry_mode, char *iv, char *key) +{ + #define GCRY_CIPHER GCRY_CIPHER_3DES // TODO: make configurable + int r = 0; + gcry_error_t gcryError; + + blkLength = gcry_cipher_get_algo_blklen(GCRY_CIPHER); + size_t keyLength = gcry_cipher_get_algo_keylen(GCRY_CIPHER); + if(strlen(key) != keyLength) { + fprintf(stderr, "invalid key lengtjh; key is %u characters, but " + "exactly %u characters are required\n", strlen(key), + keyLength); + r = 1; goto done; + } + + gcryError = gcry_cipher_open(&gcry_chd, GCRY_CIPHER, gcry_mode, 0); + if (gcryError) { + printf("gcry_cipher_open failed: %s/%s\n", + gcry_strsource(gcryError), + gcry_strerror(gcryError)); + r = 1; goto done; + } + + gcryError = gcry_cipher_setkey(gcry_chd, key, keyLength); + if (gcryError) { + printf("gcry_cipher_setkey failed: %s/%s\n", + gcry_strsource(gcryError), + gcry_strerror(gcryError)); + r = 1; goto done; + } + + gcryError = gcry_cipher_setiv(gcry_chd, iv, blkLength); + if (gcryError) { + printf("gcry_cipher_setiv failed: %s/%s\n", + gcry_strsource(gcryError), + gcry_strerror(gcryError)); + r = 1; goto done; + } +done: return r; +} + +static inline void +removePadding(char *buf, size_t *plen) +{ + unsigned len = (unsigned) *plen; + unsigned iSrc, iDst; + char *frstNUL; + + frstNUL = strchr(buf, 0x00); + if(frstNUL == NULL) + goto done; + iDst = iSrc = frstNUL - buf; + + while(iSrc < len) { + if(buf[iSrc] != 0x00) + buf[iDst++] = buf[iSrc]; + ++iSrc; + } + + *plen = iDst; +done: return; +} + +static void +doDeCrypt(FILE *fpin, FILE *fpout) +{ + gcry_error_t gcryError; + char buf[64*1024]; + size_t nRead, nWritten; + size_t nPad; + + while(1) { + nRead = fread(buf, 1, sizeof(buf), fpin); + if(nRead == 0) + break; + nPad = (blkLength - nRead % blkLength) % blkLength; + fprintf(stderr, "--->read %d chars, blkLength %d, mod %d, pad %d\n", nRead, blkLength, + nRead % blkLength, nPad); + gcryError = gcry_cipher_decrypt( + gcry_chd, // gcry_cipher_hd_t + buf, // void * + nRead, // size_t + NULL, // const void * + 0); // size_t + if (gcryError) { + fprintf(stderr, "gcry_cipher_encrypt failed: %s/%s\n", + gcry_strsource(gcryError), + gcry_strerror(gcryError)); + return; + } + removePadding(buf, &nRead); + nWritten = fwrite(buf, 1, nRead, fpout); + if(nWritten != nRead) { + perror("fpout"); + return; + } + } +} + + +static void +decrypt(char *name, char *key) +{ + FILE *logfp = NULL; + //, *sigfp = NULL; + int r = 0; + //char sigfname[4096]; + + if(!strcmp(name, "-")) { + fprintf(stderr, "decrypt mode cannot work on stdin\n"); + goto err; + } else { + if((logfp = fopen(name, "r")) == NULL) { + perror(name); + goto err; + } +#if 0 + snprintf(sigfname, sizeof(sigfname), "%s.gtsig", name); + sigfname[sizeof(sigfname)-1] = '\0'; + if((sigfp = fopen(sigfname, "r")) == NULL) { + perror(sigfname); + goto err; + } +#endif + } + + if(initCrypt(GCRY_CIPHER_MODE_CBC, "TODO: init value", key) != 0) + goto err; + doDeCrypt(logfp, stdout); + gcry_cipher_close(gcry_chd); + fclose(logfp); logfp = NULL; + return; + +err: + fprintf(stderr, "error %d processing file %s\n", r, name); + if(logfp != NULL) + fclose(logfp); +} + + +static struct option long_options[] = +{ + {"verbose", no_argument, NULL, 'v'}, + {"version", no_argument, NULL, 'V'}, + {"decrypt", no_argument, NULL, 'd'}, + {"key", required_argument, NULL, 'k'}, + {NULL, 0, NULL, 0} +}; + +int +main(int argc, char *argv[]) +{ + int i; + int opt; + char *key = ""; + + while(1) { + opt = getopt_long(argc, argv, "dk:vV", long_options, NULL); + if(opt == -1) + break; + switch(opt) { + case 'd': + mode = MD_DECRYPT; + break; + case 'k': + fprintf(stderr, "WARNING: specifying the actual key " + "via the command line is highly insecure\n" + "Do NOT use this for PRODUCTION use.\n"); + key = optarg; + break; + case 'v': + verbose = 1; + break; + case 'V': + fprintf(stderr, "rsgtutil " VERSION "\n"); + exit(0); + break; + case '?': + break; + default:fprintf(stderr, "getopt_long() returns unknown value %d\n", opt); + return 1; + } + } + + if(optind == argc) + decrypt("-", key); + else { + for(i = optind ; i < argc ; ++i) + decrypt(argv[i], key); /* currently only mode ;) */ + } + + memset(key, 0, strlen(key)); /* zero-out key store */ + return 0; +} + //char *aesSymKey = "123456789012345678901234"; // TODO: TEST ONLY diff --git a/tools/rscryutil.rst b/tools/rscryutil.rst new file mode 100644 index 00000000..7e3ab5b4 --- /dev/null +++ b/tools/rscryutil.rst @@ -0,0 +1,80 @@ +========= +rscryutil +========= + +-------------------------- +Manage Encrypted Log Files +-------------------------- + +:Author: Rainer Gerhards <rgerhards@adiscon.com> +:Date: 2013-04-08 +:Manual section: 1 + +SYNOPSIS +======== + +:: + + rscryutil [OPTIONS] [FILE] ... + + +DESCRIPTION +=========== + +This tool performs various operations on encrypted log files. +Most importantly, it provides the ability to decrypt them. + + +OPTIONS +======= + +-d, --decrypt + Select decryption mode. This is the default mode. + +-v, --verbose + Select verbose mode. + +-k, --key <KEY> + TESTING AID, NOT FOR PRODUCTION USE. This uses the KEY specified + on the command line. This is the actual key, and as such this mode + is highly insecure. However, it can be useful for intial testing + steps. This option may be removed in the future. + + +OPERATION MODES +=============== + +The operation mode specifies what exactly the tool does with the provided +files. The default operation mode is "dump", but this may change in the future. +Thus, it is recommended to always set the operations mode explicitely. If +multiple operations mode are set on the command line, results are +unpredictable. + +decrypt +------- + +The provided log files are decrypted. + +EXIT CODES +========== + +The command returns an exit code of 0 if everything went fine, and some +other code in case of failures. + + +EXAMPLES +======== + +**rscryutil logfile** + +Decrypts "logfile" and sends data to stdout. + +SEE ALSO +======== +**rsyslogd(8)** + +COPYRIGHT +========= + +This page is part of the *rsyslog* project, and is available under +LGPLv2. |