diff options
-rw-r--r-- | runtime/cryprov.h | 2 | ||||
-rw-r--r-- | runtime/libgcry.c | 6 | ||||
-rw-r--r-- | runtime/libgcry.h | 3 | ||||
-rw-r--r-- | tools/Makefile.am | 2 | ||||
-rw-r--r-- | tools/rscryutil.c | 189 |
5 files changed, 173 insertions, 29 deletions
diff --git a/runtime/cryprov.h b/runtime/cryprov.h index 5b694f46..8496b745 100644 --- a/runtime/cryprov.h +++ b/runtime/cryprov.h @@ -36,6 +36,4 @@ BEGINinterface(cryprov) /* name must also be changed in ENDinterface macro! */ rsRetVal (*OnFileClose)(void *pFileInstData, off64_t offsLogfile); ENDinterface(cryprov) #define cryprovCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ -rsRetVal initCrypt(int gcry_mode, char * iniVector); -rsRetVal doCrypt(char *buf, size_t *len); #endif /* #ifndef INCLUDED_CRYPROV_H */ diff --git a/runtime/libgcry.c b/runtime/libgcry.c index 94e087ac..5fd55360 100644 --- a/runtime/libgcry.c +++ b/runtime/libgcry.c @@ -14,9 +14,11 @@ * For the current implementation, there must always be an IV record * followed by an END record. Each records is LF-terminated. Record * types can simply be extended in the future by specifying new - * keywords (like "IV") before the colon. + * types (like "IV") before the colon. * To identify a file as rsyslog encryption info file, it must start with * the line "FILETYPE:rsyslog-enrcyption-info" + * There are some size constraints: the recordtype must be 31 bytes at + * most and the actual value (between : and LF) must be 1023 bytes at most. * * This file is part of rsyslog. * @@ -191,7 +193,7 @@ gcryfileConstruct(gcryctx ctx, gcryfile *pgf, uchar *logfn) CHKmalloc(gf = calloc(1, sizeof(struct gcryfile_s))); gf->ctx = ctx; - snprintf(fn, sizeof(fn), "%s.encinfo", logfn); + snprintf(fn, sizeof(fn), "%s%s", logfn, ENCINFO_SUFFIX); fn[MAXFNAME] = '\0'; /* be on save side */ gf->eiName = (uchar*) strdup(fn); *pgf = gf; diff --git a/runtime/libgcry.h b/runtime/libgcry.h index 6e677130..857d2352 100644 --- a/runtime/libgcry.h +++ b/runtime/libgcry.h @@ -52,6 +52,9 @@ int rsgcryEncrypt(gcryfile pF, uchar *buf, size_t *len); #define RSGCRYE_EI_OPEN 1 /* error opening .encinfo file */ #define RSGCRYE_OOM 4 /* ran out of memory */ +#define EIF_MAX_RECTYPE_LEN 31 /* max length of record types */ +#define EIF_MAX_VALUE_LEN 1023 /* max length of value types */ #define RSGCRY_FILETYPE_NAME "rsyslog-enrcyption-info" +#define ENCINFO_SUFFIX ".encinfo" #endif /* #ifndef INCLUDED_LIBGCRY_H */ diff --git a/tools/Makefile.am b/tools/Makefile.am index 8957d713..0f2bb57e 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -77,7 +77,7 @@ endif if ENABLE_LIBGCRYPT bin_PROGRAMS += rscryutil rscryutil = rscryutil.c -rscryutil_CPPFLAGS = $(RSRT_CFLAGS) $(LIBGCRYPT_CFLAGS) +rscryutil_CPPFLAGS = -I../runtime $(RSRT_CFLAGS) $(LIBGCRYPT_CFLAGS) rscryutil_LDFLAGS = `libgcrypt-config --libs` #rscryutil_LDFLAGS = $(LIBGCRYPT_LIBS) rscryutil.1: rscryutil.rst diff --git a/tools/rscryutil.c b/tools/rscryutil.c index 755371f2..e57eb625 100644 --- a/tools/rscryutil.c +++ b/tools/rscryutil.c @@ -1,5 +1,4 @@ -/* This is a tool for dumpoing the content of GuardTime TLV - * files in a (somewhat) human-readable manner. +/* This is a tool for processing rsyslog encrypted log files. * * Copyright 2013 Adiscon GmbH * @@ -31,6 +30,9 @@ #include <getopt.h> #include <gcrypt.h> +#include "rsyslog.h" +#include "libgcry.h" + static enum { MD_DECRYPT } mode = MD_DECRYPT; @@ -38,17 +40,135 @@ static int verbose = 0; static gcry_cipher_hd_t gcry_chd; static size_t blkLength; + +/* rectype/value must be EIF_MAX_*_LEN+1 long! + * returns 0 on success or something else on error/EOF + */ +static int +eiGetRecord(FILE *eifp, char *rectype, char *value) +{ + int r; + unsigned short i, j; + char buf[EIF_MAX_RECTYPE_LEN+EIF_MAX_VALUE_LEN+128]; + /* large enough for any valid record */ + + if(fgets(buf, sizeof(buf), eifp) == NULL) { + r = 1; goto done; + } + + for(i = 0 ; i < EIF_MAX_RECTYPE_LEN && buf[i] != ':' ; ++i) + if(buf[i] == '\0') { + r = 2; goto done; + } else + rectype[i] = buf[i]; + rectype[i] = '\0'; + j = 0; + for(++i ; i < EIF_MAX_VALUE_LEN && buf[i] != '\n' ; ++i, ++j) + if(buf[i] == '\0') { + r = 3; goto done; + } else + value[j] = buf[i]; + value[j] = '\0'; + r = 0; +done: return r; +} + +static int +eiCheckFiletype(FILE *eifp) +{ + char rectype[EIF_MAX_RECTYPE_LEN+1]; + char value[EIF_MAX_VALUE_LEN+1]; + int r; + + if((r = eiGetRecord(eifp, rectype, value)) != 0) goto done; + if(strcmp(rectype, "FILETYPE") || strcmp(value, RSGCRY_FILETYPE_NAME)) { + fprintf(stderr, "invalid filetype \"cookie\" in encryption " + "info file\n"); + fprintf(stderr, "\trectype: '%s', value: '%s'\n", rectype, value); + r = 1; goto done; + } + r = 0; +done: return r; +} + static int -initCrypt(int gcry_mode, char *iv, char *key) +eiGetIV(FILE *eifp, char *iv, size_t leniv) +{ + char rectype[EIF_MAX_RECTYPE_LEN+1]; + char value[EIF_MAX_VALUE_LEN+1]; + size_t valueLen; + unsigned short i, j; + int r; + unsigned char nibble; + + if((r = eiGetRecord(eifp, rectype, value)) != 0) goto done; + if(strcmp(rectype, "IV")) { + fprintf(stderr, "no IV record found when expected, record type " + "seen is '%s'\n", rectype); + r = 1; goto done; + } + valueLen = strlen(value); + if(valueLen/2 != leniv) { + fprintf(stderr, "length of IV is %d, expected %d\n", + valueLen/2, leniv); + r = 1; goto done; + } + + for(i = j = 0 ; i < valueLen ; ++i) { + if(value[i] >= '0' && value[i] <= '9') + nibble = value[i] - '0'; + else if(value[i] >= 'a' && value[i] <= 'f') + nibble = value[i] - 'a' + 10; + else { + fprintf(stderr, "invalid IV '%s'\n", value); + r = 1; goto done; + } + if(i % 2 == 0) + iv[j] = nibble << 4; + else + iv[j++] |= nibble; + } + r = 0; +done: return r; +} + +static int +eiGetEND(FILE *eifp, off64_t *offs) +{ + char rectype[EIF_MAX_RECTYPE_LEN+1]; + char value[EIF_MAX_VALUE_LEN+1]; + int r; + + if((r = eiGetRecord(eifp, rectype, value)) != 0) goto done; + if(strcmp(rectype, "END")) { + fprintf(stderr, "no END record found when expected, record type " + "seen is '%s'\n", rectype); + r = 1; goto done; + } + *offs = atoll(value); + r = 0; +done: return r; +} + +static int +initCrypt(FILE *eifp, int gcry_mode, char *key) { #define GCRY_CIPHER GCRY_CIPHER_3DES // TODO: make configurable int r = 0; gcry_error_t gcryError; + char iv[4096]; blkLength = gcry_cipher_get_algo_blklen(GCRY_CIPHER); + if(blkLength > sizeof(iv)) { + fprintf(stderr, "internal error[%s:%d]: block length %d too large for " + "iv buffer\n", __FILE__, __LINE__, blkLength); + r = 1; goto done; + } + if((r = eiGetIV(eifp, iv, blkLength)) != 0) goto done; + size_t keyLength = gcry_cipher_get_algo_keylen(GCRY_CIPHER); if(strlen(key) != keyLength) { - fprintf(stderr, "invalid key lengtjh; key is %u characters, but " + fprintf(stderr, "invalid key length; key is %u characters, but " "exactly %u characters are required\n", strlen(key), keyLength); r = 1; goto done; @@ -87,7 +207,7 @@ removePadding(char *buf, size_t *plen) unsigned iSrc, iDst; char *frstNUL; - frstNUL = strchr(buf, 0x00); + frstNUL = memchr(buf, 0x00, *plen); if(frstNUL == NULL) goto done; iDst = iSrc = frstNUL - buf; @@ -103,20 +223,24 @@ done: return; } static void -doDeCrypt(FILE *fpin, FILE *fpout) +decryptBlock(FILE *fpin, FILE *fpout, off64_t blkEnd, off64_t *pCurrOffs) { gcry_error_t gcryError; - char buf[64*1024]; - size_t nRead, nWritten; + size_t nRead, nWritten; + size_t toRead; size_t nPad; + size_t leftTillBlkEnd; + char buf[64*1024]; + leftTillBlkEnd = blkEnd - *pCurrOffs; while(1) { - nRead = fread(buf, 1, sizeof(buf), fpin); + toRead = sizeof(buf) <= leftTillBlkEnd ? sizeof(buf) : leftTillBlkEnd; + toRead = toRead - toRead % blkLength; + nRead = fread(buf, 1, toRead, fpin); if(nRead == 0) break; + leftTillBlkEnd -= nRead, *pCurrOffs += nRead; 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 * @@ -139,13 +263,31 @@ doDeCrypt(FILE *fpin, FILE *fpout) } +static int +doDecrypt(FILE *logfp, FILE *eifp, FILE *outfp, char *key) +{ + off64_t blkEnd; + off64_t currOffs = 0; + int r; + + while(1) { + /* process block */ + if(initCrypt(eifp, GCRY_CIPHER_MODE_CBC, key) != 0) + goto done; + if((r = eiGetEND(eifp, &blkEnd)) != 0) goto done; + decryptBlock(logfp, outfp, blkEnd, &currOffs); + gcry_cipher_close(gcry_chd); + } + r = 0; +done: return r; +} + static void decrypt(char *name, char *key) { - FILE *logfp = NULL; - //, *sigfp = NULL; + FILE *logfp = NULL, *eifp = NULL; int r = 0; - //char sigfname[4096]; + char eifname[4096]; if(!strcmp(name, "-")) { fprintf(stderr, "decrypt mode cannot work on stdin\n"); @@ -155,21 +297,20 @@ decrypt(char *name, char *key) 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); + snprintf(eifname, sizeof(eifname), "%s%s", name, ENCINFO_SUFFIX); + eifname[sizeof(eifname)-1] = '\0'; + if((eifp = fopen(eifname, "r")) == NULL) { + perror(eifname); goto err; } -#endif + if(eiCheckFiletype(eifp) != 0) + goto err; } - if(initCrypt(GCRY_CIPHER_MODE_CBC, "TODO: init value", key) != 0) - goto err; - doDeCrypt(logfp, stdout); - gcry_cipher_close(gcry_chd); + doDecrypt(logfp, eifp, stdout, key); + fclose(logfp); logfp = NULL; + fclose(eifp); eifp = NULL; return; err: |