diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2013-02-21 11:29:22 +0100 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2013-02-21 11:29:22 +0100 |
commit | 212af677576238bf87deb1bee3e7bcfb170dc668 (patch) | |
tree | d12f71316c3fd3901a899d1bee1210969cea8ea8 | |
parent | 3cc89eb96923cb85654558ce623256f4da76b87f (diff) | |
download | rsyslog-212af677576238bf87deb1bee3e7bcfb170dc668.tar.gz rsyslog-212af677576238bf87deb1bee3e7bcfb170dc668.tar.bz2 rsyslog-212af677576238bf87deb1bee3e7bcfb170dc668.zip |
logsigner: sign via merkle tree approach (still PoC, non production)
-rw-r--r-- | runtime/Makefile.am | 11 | ||||
-rw-r--r-- | runtime/librsgt.c | 309 | ||||
-rw-r--r-- | runtime/lmgt.c | 124 | ||||
-rw-r--r-- | tools/Makefile.am | 6 | ||||
-rw-r--r-- | tools/logsigner.c | 54 |
5 files changed, 345 insertions, 159 deletions
diff --git a/runtime/Makefile.am b/runtime/Makefile.am index fbc92d9c..0f1b580a 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -1,6 +1,6 @@ sbin_PROGRAMS = man_MANS = -noinst_LTLIBRARIES = librsyslog.la +noinst_LTLIBRARIES = librsyslog.la librsgt.la pkglib_LTLIBRARIES = #pkglib_LTLIBRARIES = librsyslog.la @@ -92,6 +92,7 @@ librsyslog_la_SOURCES = \ ../template.h # the files with ../ we need to work on - so that they either become part of the # runtime or will no longer be needed. -- rgerhards, 2008-06-13 +# if WITH_MODDIRS librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) -I\$(top_srcdir)/tools @@ -172,6 +173,14 @@ lmnsd_gtls_la_LDFLAGS = -module -avoid-version lmnsd_gtls_la_LIBADD = $(GNUTLS_LIBS) endif +# +# support library for guardtime +# +if ENABLE_GUARDTIME + librsgt_la_SOURCES = librsgt.c +endif + + update-systemd: curl http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.c > sd-daemon.c curl http://cgit.freedesktop.org/systemd/plain/src/sd-daemon.h > sd-daemon.h diff --git a/runtime/librsgt.c b/runtime/librsgt.c new file mode 100644 index 00000000..4ad4ec26 --- /dev/null +++ b/runtime/librsgt.c @@ -0,0 +1,309 @@ +/* librsgt.c - rsyslog's guardtime support library + * + * Regarding the online algorithm for Merkle tree signing. Expected + * calling sequence is: + * + * sigblkConstruct + * for each signature block: + * sigblkInit + * for each record: + * sigblkAddRecord + * sigblkFinish + * sigblkDestruct + * + * Obviously, the next call after sigblkFinsh must either be to + * sigblkInit or sigblkDestruct (if no more signature blocks are + * to be emitted, e.g. on file close). sigblkDestruct saves state + * information (most importantly last block hash) and sigblkConstruct + * reads (or initilizes if not present) it. + * + * 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 express 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 <stdint.h> +#include <assert.h> + +#include <gt_base.h> +#include <gt_http.h> + +#include "librsgt.h" + +typedef unsigned char uchar; +#ifndef VERSION +#define VERSION "no-version" +#endif + +static void +outputhash(GTDataHash *hash) +{ + int i; + for(i = 0 ; i < hash->digest_length ; ++i) + printf("%2.2x", hash->digest[i]); + printf("\n"); +} + + + +void +rsgtInit(char *usragent) +{ + int ret = GT_OK; + + srand(time(NULL) * 7); /* see comments in seedIV() */ + + ret = GT_init(); + if(ret != GT_OK) { + fprintf(stderr, "GT_init() failed: %d (%s)\n", + ret, GT_getErrorString(ret)); + goto done; + } + ret = GTHTTP_init(usragent, 1); + if(ret != GT_OK) { + fprintf(stderr, "GTHTTP_init() failed: %d (%s)\n", + ret, GTHTTP_getErrorString(ret)); + goto done; + } +done: return; +} + +void +rsgtExit(void) +{ + GTHTTP_finalize(); + GT_finalize(); +} + + +void +seedIV(gtctx ctx) +{ + /* FIXME: this currently is "kindergarten cryptography" - use a + * sufficiently strong PRNG instead! Just a PoC so far! Do NOT + * use in production!!! + */ + ctx->IV = rand() * 1000037; +} + +gtctx +rsgtCtxNew(void) +{ + return calloc(1, sizeof(struct gtctx_s)); +} + +void +rsgtCtxDel(gtctx ctx) +{ + if(ctx == NULL) + goto done; + free(ctx); + /* TODO: persist! */ +done: return; +} + +/* new sigblk is initialized, but maybe in existing ctx */ +void +sigblkInit(gtctx ctx) +{ + seedIV(ctx); +// if(ctx->x_prev == NULL) { + ctx->x_prev = NULL; + /* FIXME: do the real thing - or in a later step as currently? */ +// } + memset(ctx->roots_valid, 0, sizeof(ctx->roots_valid)/sizeof(char)); + ctx->nRoots = 0; +} + + +/* concat: add IV to buffer */ +static inline void +bufAddIV(gtctx ctx, uchar *buf, size_t *len) +{ + memcpy(buf+*len, &ctx->IV, sizeof(ctx->IV)); + *len += sizeof(ctx->IV); +} + +/* concat: add hash to buffer */ +static inline void +bufAddHash(gtctx ctx, uchar *buf, size_t *len, GTDataHash *hash) +{ + if(hash == NULL) { + memset(buf+*len, 0, 32); /* FIXME: depends on hash function! */ + *len += 32; + } else { + memcpy(buf+*len, hash->digest, hash->digest_length); + *len += hash->digest_length; + } +} +/* concat: add tree level to buffer */ +static inline void +bufAddLevel(gtctx ctx, uchar *buf, size_t *len, int level) +{ + memcpy(buf+*len, &level, sizeof(level)); + *len += sizeof(level); +} + + +static void +hash_m(gtctx ctx, GTDataHash **m) +{ + // m = hash(concat(ctx->x_prev, IV)); + int r; + uchar concatBuf[16*1024]; + size_t len = 0; + + bufAddHash(ctx, concatBuf, &len, ctx->x_prev); + bufAddIV(ctx, concatBuf, &len); + r = GTDataHash_create(GT_HASHALG_SHA256, concatBuf, len, m); +} + +static void +hash_r(gtctx ctx, GTDataHash **r, const uchar *rec, const size_t len) +{ + // r = hash(canonicalize(rec)); + int ret; + + ret = GTDataHash_create(GT_HASHALG_SHA256, rec, len, r); +} + + +static void +hash_node(gtctx ctx, GTDataHash **node, GTDataHash *m, GTDataHash *r, int level) +{ + // x = hash(concat(m, r, 0)); /* hash leaf */ + int ret; + uchar concatBuf[16*1024]; + size_t len = 0; + + bufAddHash(ctx, concatBuf, &len, m); + bufAddHash(ctx, concatBuf, &len, r); + bufAddLevel(ctx, concatBuf, &len, level); + ret = GTDataHash_create(GT_HASHALG_SHA256, concatBuf, len, node); +} +void +sigblkAddRecord(gtctx ctx, const uchar *rec, const size_t len) +{ + GTDataHash *x; /* current hash */ + GTDataHash *m, *r, *t; + int8_t j; + int ret; + + hash_m(ctx, &m); + hash_r(ctx, &r, rec, len); + hash_node(ctx, &x, m, r, 0); /* hash leaf */ + /* persists x here if Merkle tree needs to be persisted! */ + /* add x to the forest as new leaf, update roots list */ + t = x; + for(j = 0 ; j < ctx->nRoots ; ++j) { + if(ctx->roots_valid[j] == 0) { + GTDataHash_free(ctx->roots_hash[j]); + ctx->roots_hash[j] = t; + ctx->roots_valid[j] = 1; + t = NULL; + } else if(t != NULL) { + /* hash interim node */ + hash_node(ctx, &t, ctx->roots_hash[j], t, j+1); + ctx->roots_valid[j] = 0; + } + } + if(t != NULL) { + /* new level, append "at the top" */ + ctx->roots_hash[ctx->nRoots] = t; + ++ctx->nRoots; + assert(ctx->nRoots < MAX_ROOTS); + t = NULL; + } + ctx->x_prev = x; /* single var may be sufficient */ + + /* cleanup */ + GTDataHash_free(m); + GTDataHash_free(r); +} + +static void +timestampIt(gtctx ctx, GTDataHash *hash) +{ + int r = GT_OK; + GTTimestamp *timestamp = NULL; + unsigned char *der = NULL; + char *sigFile = "logsigner.TIMESTAMP"; + size_t der_len; + + /* Get the timestamp. */ + r = GTHTTP_createTimestampHash(hash, + "http://stamper.guardtime.net/gt-signingservice", ×tamp); + + if(r != GT_OK) { + fprintf(stderr, "GTHTTP_createTimestampHash() failed: %d (%s)\n", + r, GTHTTP_getErrorString(r)); + goto done; + } + + /* Encode timestamp. */ + r = GTTimestamp_getDEREncoded(timestamp, &der, &der_len); + if(r != GT_OK) { + fprintf(stderr, "GTTimestamp_getDEREncoded() failed: %d (%s)\n", + r, GT_getErrorString(r)); + goto done; + } + + /* Save DER-encoded timestamp to file. */ + r = GT_saveFile(sigFile, der, der_len); + if(r != GT_OK) { + fprintf(stderr, "Cannot save timestamp to file %s: %d (%s)\n", + sigFile, r, GT_getErrorString(r)); + if(r == GT_IO_ERROR) { + fprintf(stderr, "\t%d (%s)\n", errno, strerror(errno)); + } + goto done; + } + printf("Timestamping succeeded!\n"); +done: + GT_free(der); + GTTimestamp_free(timestamp); +} + + +void +sigblkFinish(gtctx ctx) +{ + GTDataHash *root, *rootDel; + int8_t j; + + root = NULL; + for(j = 0 ; j < ctx->nRoots ; ++j) { + if(root == NULL) { + root = ctx->roots_hash[j]; + ctx->roots_valid[j] = 0; /* guess this is redundant with init, maybe del */ + } else if(ctx->roots_valid[j]) { + rootDel = root; + hash_node(ctx, &root, ctx->roots_hash[j], root, j+1); + ctx->roots_valid[j] = 0; /* guess this is redundant with init, maybe del */ + GTDataHash_free(rootDel); + } + } + /* persist root value here (callback?) */ +printf("root hash is:\n"); outputhash(root); + timestampIt(ctx, root); +} diff --git a/runtime/lmgt.c b/runtime/lmgt.c deleted file mode 100644 index 15a56cfa..00000000 --- a/runtime/lmgt.c +++ /dev/null @@ -1,124 +0,0 @@ -/* lmgt.c - * - * Regarding the online algorithm for Merkle tree signing. Expected - * calling sequence is: - * - * sigblkConstruct - * for each signature block: - * sigblkInit - * for each record: - * sigblkAddRecord - * sigblkFinish - * sigblkDestruct - * - * Obviously, the next call after sigblkFinsh must either be to - * sigblkInit or sigblkDestruct (if no more signature blocks are - * to be emitted, e.g. on file close). sigblkDestruct saves state - * information (most importantly last block hash) and sigblkConstruct - * reads (or initilizes if not present) it. - * - * 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 express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "config.h" -#include <stdint.h> - - -/* Max number of roots inside the forest. This permits blocks of up to - * 2^MAX_ROOTS records. We assume that 64 is sufficient for all use - * cases ;) [and 64 is not really a waste of memory, so we do not even - * try to work with reallocs and such... - */ -#define MAX_ROOTS 64 - -/* context for gt calls. All state data is kept here, this permits - * multiple concurrent callers. - */ -struct gtctx_s { - IV; /* initial value for blinding masks (where to do we get it from?) */ - x_prev = NULL; /* last leaf hash (maybe of previous block) --> preserve on term */ - int8_t nroots; - /* algo engineering: roots structure is split into two arrays - * in order to improve cache hits. - */ - char roots_valid[MAX_ROOTS]; - hash_mem roots_hash[MAX_ROOTS]; - -}; -typedef struct gtctx_s *gtctx; - -void -sigblkInit(gtctx ctx) -{ - init ctx->IV; - if(ctx->x_prev == NULL) - alloc & zero-fill x_prev; - memset(ctx->roots_valid, 0, sizeof(ctx->roots_valid)/sizeof(char)); - nroots = 0; -} - - -void -sigblkAddRecord(gtctx ctx, char *rec) -{ - auto x; /* current hash */ - hash_mem m, r, t; - int8_t j; - - m = hash(concat(ctx->x_prev, IV)); - r = hash(canonicalize(rec)); - x = hash(concat(m, r, 0)); /* hash leaf */ - /* persists x here if Merkle tree needs to be persisted! */ - /* add x to the forest as new leaf, update roots list */ - t = x; - for(j = 0 ; j < ctx->nRoots ; ++j) { - if(ctx->roots_valid[j] == 0) { - ctx->roots_hash[j] = t; - ctx->roots_valid[j] = 1; - t = NULL; - } else if(t != NULL) { - t = hash(concat(ctx->roots_hash[j], t, j+1)); /* hash interim node */ - ctx->roots_valid[j] = 0; - } - if(t != NULL) { - ctx->roots_hash[ctx->nroots] = t; - ++ctx->roots_hash; - assert(ctx->roots_hash < MAX_ROOTS); - t = NULL; - } - ctx->x_prev = x; /* single var may be sufficient */ -} - -void -sigblkFinish(gtctx ctx) -{ - hash_mem root; - int8_t j; - - root = NULL; - for(j = 0 ; j < ctx->nRoots ; ++j) { - if(root == NULL) { - root = ctx->roots_hash[j]; - ctx->roots_valid[j] = 0; /* guess this is redundant with init, maybe del */ - } else if(ctx->roots_valid[j]) { - root = hash(concat(ctx->roots_hash[j], root, j+1)); - ctx->roots_valid[j] = 0; /* guess this is redundant with init, maybe del */ - } - } - /* persist root value here (callback?) */ -} diff --git a/tools/Makefile.am b/tools/Makefile.am index 9d9bd352..712443c0 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -58,6 +58,12 @@ logctl_SOURCES = logctl.c logctl_CPPFLAGS = $(LIBMONGO_CLIENT_CFLAGS) logctl_LDADD = $(LIBMONGO_CLIENT_LIBS) endif +if ENABLE_GUARDTIME +bin_PROGRAMS += logsigner +logsigner = logsigner.c +logsigner_CPPFLAGS = $(RSRT_CFLAGS) $(GUARDTIME_CFLAGS) +logsigner_LDADD = ../runtime/librsgt.la $(GUARDTIME_LIBS) +endif endif EXTRA_DIST = $(man_MANS) \ diff --git a/tools/logsigner.c b/tools/logsigner.c index 2aeb2162..51803be2 100644 --- a/tools/logsigner.c +++ b/tools/logsigner.c @@ -26,15 +26,20 @@ * 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 <gt_base.h> #include <gt_http.h> +#include "librsgt.h" + +#if 0 void outputhash(GTDataHash *hash) { @@ -45,33 +50,6 @@ outputhash(GTDataHash *hash) } void -gtInit() -{ - int r = GT_OK; - - r = GT_init(); - if(r != GT_OK) { - fprintf(stderr, "GT_init() failed: %d (%s)\n", - r, GT_getErrorString(r)); - goto done; - } - r = GTHTTP_init("rsyslog logsigner", 1); - if(r != GT_OK) { - fprintf(stderr, "GTHTTP_init() failed: %d (%s)\n", - r, GTHTTP_getErrorString(r)); - goto done; - } -done: return; -} - -void -gtExit() -{ - GTHTTP_finalize(); - GT_finalize(); -} - -void timestampIt(GTDataHash *hash) { int r = GT_OK; @@ -116,7 +94,7 @@ done: void -sign(const char *buf, size_t len) +sign(const char *buf, const size_t len) { int r; GTDataHash *hash = NULL; @@ -132,6 +110,7 @@ sign(const char *buf, size_t len) timestampIt(hash); /* of course, this needs to be moved to once at end ;) */ done: GTDataHash_free(hash); } +#endif void processFile(char *name) @@ -139,7 +118,10 @@ processFile(char *name) FILE *fp; size_t len; char line[64*1024+1]; + gtctx ctx = NULL; + ctx = rsgtCtxNew(); + sigblkInit(ctx); if(!strcmp(name, "-")) fp = stdin; else @@ -147,7 +129,8 @@ processFile(char *name) while(1) { if(fgets(line, sizeof(line), fp) == NULL) { - perror(name); + if(!feof(fp)) + perror(name); break; } len = strlen(line); @@ -155,19 +138,22 @@ processFile(char *name) --len; line[len] = '\0'; } - sign(line, len); + //sign(line, len); + sigblkAddRecord(ctx, line, len); } - if(fp != stdout) + if(fp != stdin) fclose(fp); + sigblkFinish(ctx); + rsgtCtxDel(ctx); } int main(int argc, char *argv[]) { - gtInit(); + rsgtInit("rsyslog logsigner " VERSION); processFile("-"); - gtExit(); + rsgtExit(); return 0; } |