summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog1
-rw-r--r--runtime/lmcry_gcry.c30
-rw-r--r--tools/rscryutil.c114
-rw-r--r--tools/rscryutil.rst77
4 files changed, 179 insertions, 43 deletions
diff --git a/ChangeLog b/ChangeLog
index 97114227..a8f6b475 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,7 @@
Version 7.3.10 [devel] 2013-04-??
- added RainerScript re_extract() function
- templates now permit substring extraction relative to end-of-string
+- added support for encrypting log files
- bugfix: imuxsock aborted under some conditions
regression from ratelimiting enhancements
---------------------------------------------------------------------------
diff --git a/runtime/lmcry_gcry.c b/runtime/lmcry_gcry.c
index cc65051f..bcc001fc 100644
--- a/runtime/lmcry_gcry.c
+++ b/runtime/lmcry_gcry.c
@@ -45,6 +45,7 @@ DEFobjCurrIf(glbl)
/* tables for interfacing with the v6 config system */
static struct cnfparamdescr cnfpdescr[] = {
{ "cry.key", eCmdHdlrGetWord, 0 },
+ { "cry.keyfile", eCmdHdlrGetWord, 0 },
{ "cry.mode", eCmdHdlrGetWord, 0 }, /* CBC, ECB, etc */
{ "cry.algo", eCmdHdlrGetWord, 0 }
};
@@ -89,7 +90,9 @@ SetCnfParam(void *pT, struct nvlst *lst)
{
lmcry_gcry_t *pThis = (lmcry_gcry_t*) pT;
int i, r;
+ unsigned keylen;
uchar *key = NULL;
+ uchar *keyfile = NULL;
uchar *algo = NULL;
uchar *mode = NULL;
struct cnfparamvals *pvals;
@@ -106,6 +109,8 @@ SetCnfParam(void *pT, struct nvlst *lst)
continue;
if(!strcmp(pblk.descr[i].name, "cry.key")) {
key = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
+ } else if(!strcmp(pblk.descr[i].name, "cry.keyfile")) {
+ keyfile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else if(!strcmp(pblk.descr[i].name, "cry.mode")) {
mode = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else if(!strcmp(pblk.descr[i].name, "cry.algo")) {
@@ -130,22 +135,39 @@ SetCnfParam(void *pT, struct nvlst *lst)
}
}
/* note: key must be set AFTER algo/mode is set (as it depends on them) */
+ if(key != NULL && keyfile != NULL) {
+ errmsg.LogError(0, RS_RET_INVALID_PARAMS, "only one of the following "
+ "parameters can be specified: cry.key, cry.keyfile\n");
+ ABORT_FINALIZE(RS_RET_INVALID_PARAMS);
+ }
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_INVALID_PARAMS, "Key length %d expected, but "
- "key of length %d given", r, strlen((char*)key));
+ keylen = strlen((char*)key);
+ }
+ if(keyfile != NULL) {
+ r = gcryGetKeyFromFile((char*)keyfile, (char**)&key, &keylen);
+ if(r != 0) {
+ errmsg.LogError(0, RS_RET_ERR, "error %d reading keyfile %s\n",
+ r, keyfile);
ABORT_FINALIZE(RS_RET_INVALID_PARAMS);
}
}
+ /* if we reach this point, we have a valid key */
+ r = rsgcrySetKey(pThis->ctx, key, keylen);
+ if(r > 0) {
+ errmsg.LogError(0, RS_RET_INVALID_PARAMS, "Key length %d expected, but "
+ "key of length %d given", r, keylen);
+ ABORT_FINALIZE(RS_RET_INVALID_PARAMS);
+ }
+
cnfparamvalsDestruct(pvals, &pblk);
if(key != NULL) {
memset(key, 0, strlen((char*)key));
free(key);
}
+ free(keyfile);
free(algo);
free(mode);
finalize_it:
diff --git a/tools/rscryutil.c b/tools/rscryutil.c
index 9290db4d..be14cde9 100644
--- a/tools/rscryutil.c
+++ b/tools/rscryutil.c
@@ -28,6 +28,9 @@
#include <unistd.h>
#include <stdio.h>
#include <getopt.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <gcrypt.h>
#include "rsyslog.h"
@@ -40,10 +43,13 @@ static int verbose = 0;
static gcry_cipher_hd_t gcry_chd;
static size_t blkLength;
+static char *keyfile = NULL;
+static int randomKeyLen = -1;
static char *cry_key = NULL;
static unsigned cry_keylen = 0;
static int cry_algo = GCRY_CIPHER_AES128;
static int cry_mode = GCRY_CIPHER_MODE_CBC;
+static int optionForce = 0;
/* rectype/value must be EIF_MAX_*_LEN+1 long!
* returns 0 on success or something else on error/EOF
@@ -321,27 +327,70 @@ err:
}
static void
-write_keyfile(char *keyfile)
+write_keyfile(char *fn)
{
- FILE *fp;
-
- if(cry_key == NULL) {
- fprintf(stderr, "ERROR: key must be set via some method\n");
+ int fd;
+ int r;
+ mode_t fmode;
+
+ fmode = O_WRONLY|O_CREAT;
+ if(!optionForce)
+ fmode |= O_EXCL;
+ if((fd = open(fn, fmode, S_IRUSR)) == -1) {
+ fprintf(stderr, "error opening keyfile ");
+ perror(fn);
exit(1);
}
- if(keyfile == NULL) {
- fprintf(stderr, "ERROR: keyfile must be set\n");
+ if((r = write(fd, cry_key, cry_keylen)) != (ssize_t)cry_keylen) {
+ fprintf(stderr, "error writing keyfile (ret=%d) ", r);
+ perror(fn);
exit(1);
}
- if((fp = fopen(keyfile, "w")) == NULL) {
- perror(keyfile);
+ close(fd);
+}
+
+static void
+getKeyFromFile(char *fn)
+{
+ int r;
+ r = gcryGetKeyFromFile(fn, &cry_key, &cry_keylen);
+ if(r != 0) {
+ fprintf(stderr, "Error %d reading key from file '%s'\n", r, fn);
exit(1);
}
- if(fwrite(cry_key, cry_keylen, 1, fp) != 1) {
- perror(keyfile);
+}
+
+static void
+getRandomKey(void)
+{
+ int fd;
+ cry_keylen = randomKeyLen;
+ cry_key = malloc(randomKeyLen); /* do NOT zero-out! */
+ /* if we cannot obtain data from /dev/urandom, we use whatever
+ * is present at the current memory location as random data. Of
+ * course, this is very weak and we should consider a different
+ * option, especially when not running under Linux (for Linux,
+ * unavailability of /dev/urandom is just a theoretic thing, it
+ * will always work...). -- TODO -- rgerhards, 2013-03-06
+ */
+ if((fd = open("/dev/urandom", O_RDONLY)) > 0) {
+ if(read(fd, cry_key, randomKeyLen)) {}; /* keep compiler happy */
+ close(fd);
+ }
+}
+
+
+static void
+setKey()
+{
+ if(randomKeyLen != -1)
+ getRandomKey();
+ else if(keyfile != NULL)
+ getKeyFromFile(keyfile);
+ if(cry_key == NULL) {
+ fprintf(stderr, "ERROR: key must be set via some method\n");
exit(1);
}
- fclose(fp);
}
static struct option long_options[] =
@@ -349,35 +398,26 @@ static struct option long_options[] =
{"verbose", no_argument, NULL, 'v'},
{"version", no_argument, NULL, 'V'},
{"decrypt", no_argument, NULL, 'd'},
- {"write-keyfile", no_argument, NULL, 'W'},
+ {"force", no_argument, NULL, 'f'},
+ {"write-keyfile", required_argument, NULL, 'W'},
{"key", required_argument, NULL, 'K'},
+ {"generate-random-key", required_argument, NULL, 'r'},
{"keyfile", required_argument, NULL, 'k'},
{"algo", required_argument, NULL, 'a'},
{"mode", required_argument, NULL, 'm'},
{NULL, 0, NULL, 0}
};
-static void
-getKeyFromFile(char *fn)
-{
- int r;
- r = gcryGetKeyFromFile(fn, &cry_key, &cry_keylen);
- if(r != 0) {
- fprintf(stderr, "Error %d reading key from file '%s'\n", r, fn);
- exit(1);
- }
-}
-
int
main(int argc, char *argv[])
{
int i;
int opt;
int temp;
- char *keyfile = NULL;
+ char *newKeyFile = NULL;
while(1) {
- opt = getopt_long(argc, argv, "a:dk:K:m:vVW", long_options, NULL);
+ opt = getopt_long(argc, argv, "a:dfk:K:m:r:vVW:", long_options, NULL);
if(opt == -1)
break;
switch(opt) {
@@ -386,10 +426,22 @@ main(int argc, char *argv[])
break;
case 'W':
mode = MD_WRITE_KEYFILE;
+ newKeyFile = optarg;
break;
case 'k':
keyfile = optarg;
break;
+ case 'f':
+ optionForce = 1;
+ break;
+ case 'r':
+ randomKeyLen = atoi(optarg);
+ if(randomKeyLen > 64*1024) {
+ fprintf(stderr, "ERROR: keys larger than 64KiB are "
+ "not supported\n");
+ exit(1);
+ }
+ break;
case 'K':
fprintf(stderr, "WARNING: specifying the actual key "
"via the command line is highly insecure\n"
@@ -429,20 +481,16 @@ main(int argc, char *argv[])
}
}
+ setKey();
+
if(mode == MD_WRITE_KEYFILE) {
if(optind != argc) {
fprintf(stderr, "ERROR: no file parameters permitted in "
"--write-keyfile mode\n");
exit(1);
}
- write_keyfile(keyfile);
+ write_keyfile(newKeyFile);
} else {
- if(keyfile != NULL)
- getKeyFromFile(keyfile);
- if(cry_key == NULL) {
- fprintf(stderr, "ERROR: key must be set via some method\n");
- exit(1);
- }
if(optind == argc)
decrypt("-");
else {
diff --git a/tools/rscryutil.rst b/tools/rscryutil.rst
index d6381011..c546d855 100644
--- a/tools/rscryutil.rst
+++ b/tools/rscryutil.rst
@@ -7,7 +7,7 @@ Manage Encrypted Log Files
--------------------------
:Author: Rainer Gerhards <rgerhards@adiscon.com>
-:Date: 2013-04-08
+:Date: 2013-04-15
:Manual section: 1
SYNOPSIS
@@ -31,14 +31,22 @@ OPTIONS
-d, --decrypt
Select decryption mode. This is the default mode.
--W, --write-keyfile
+-W, --write-keyfile <file>
Utility function to write a key to a keyfile. The key can be obtained
- via any method (except via a keyfile for obvious reasons).
+ via any method.
-v, --verbose
Select verbose mode.
--k, --key <KEY>
+-f, --force
+ Forces operations that otherwise would fail.
+
+-k, --keyfile <file>
+ Reads the key from <file>. File _must_ contain the key, only, no headers
+ or other meta information. Keyfiles can be generated via the
+ *--write-keyfile* option.
+
+-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
@@ -52,6 +60,11 @@ OPTIONS
Sets the ciphermode to be used. See below for supported modes.
The default is "CBC".
+-r, --generate-random-key <bytes>
+ Generates a random key of length <bytes>. This option is
+ meant to be used together with *--write-keyfile* (and it is hard
+ to envision any other valid use for it).
+
OPERATION MODES
===============
@@ -64,7 +77,25 @@ unpredictable.
decrypt
-------
-The provided log files are decrypted.
+The provided log files are decrypted. Note that the *.encinfo* side files
+must exist and be accessible in order for decryption to to work.
+
+write-keyfile
+-------------
+
+In this mode no log files are processed; thus it is an error to specify
+any on the command line. The specified keyfile is written. The key itself
+is obtained via the usual key commands. If *--keyfile* is used, that
+file is effectively copied.
+
+For security reasons, existing key files are _not_ overwritten. To permit
+this, specify the *--force* option. When doing so, keep in mind that lost
+keys cannot be recovered and data encrypted with them may also be considered
+lost.
+
+Keyfiles are always created with 0400 permission, that is read access for only
+the user. An exception is when an existing file is overwritten via the
+*--force* option, in which case the former permissions still apply.
EXIT CODES
==========
@@ -77,6 +108,7 @@ SUPPORTED ALGORITHMS
====================
We basically support what libgcrypt supports. This is:
+
3DES
CAST5
BLOWFISH
@@ -101,6 +133,7 @@ SUPPORTED CIPHER MODES
======================
We basically support what libgcrypt supports. This is:
+
ECB
CFB
CBC
@@ -116,9 +149,41 @@ EXAMPLES
Decrypts "logfile" and sends data to stdout.
+
+**rscryutil --generate-random-key 16 --keyfile /some/secured/path/keyfile**
+
+Generates random key and stores it in the specified keyfile.
+
+LOG SIGNATURES
+==============
+
+Encrypted log files can be used together with signing. To verify such a file,
+it must be decrypted first, and the verification tool **rsgtutil(1)** must be
+run on the decrypted file.
+
+SECURITY CONSIDERATIONS
+=======================
+
+Specifying keys directly on the command line (*--key* option) is very
+insecure and should
+not be done, except for testing purposes with test keys. Even then it is
+recommended to use keyfiles, which are also easy to handle during testing.
+Keep in mind that command history is usally be kept by bash and can also
+easily be monitored.
+
+Local keyfiles are also a security risk. At a minimum, they should be
+used with very restrictive file permissions. For this reason,
+the *rscryutil* tool creates them with read permissions for the user,
+only, no matter what umask is set to.
+
+When selecting cipher algorithms and modes, care needs to be taken. The
+defaults should be reasonable safe to use, but this tends to change over
+time. Keep up with the most current crypto recommendations.
+
+
SEE ALSO
========
-**rsyslogd(8)**
+**rsgtutil(1)**, **rsyslogd(8)**
COPYRIGHT
=========