diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/Makefile.am | 2 | ||||
-rw-r--r-- | runtime/librsgt.c | 70 | ||||
-rw-r--r-- | runtime/librsgt.h | 88 | ||||
-rw-r--r-- | runtime/librsgt_read.c | 348 |
4 files changed, 452 insertions, 56 deletions
diff --git a/runtime/Makefile.am b/runtime/Makefile.am index 20824494..c429394d 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -178,7 +178,7 @@ endif # support library for guardtime # if ENABLE_GUARDTIME - librsgt_la_SOURCES = librsgt.c + librsgt_la_SOURCES = librsgt.c librsgt_read.c pkglib_LTLIBRARIES += lmsig_gt.la lmsig_gt_la_SOURCES = lmsig_gt.c diff --git a/runtime/librsgt.c b/runtime/librsgt.c index 8aa80771..e5187c42 100644 --- a/runtime/librsgt.c +++ b/runtime/librsgt.c @@ -48,7 +48,7 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> -#define MAXFNAME 1024 /* TODO: include correct header */ +#define MAXFNAME 1024 #include <gt_http.h> @@ -59,45 +59,6 @@ typedef unsigned char uchar; #define VERSION "no-version" #endif -static inline uint16_t -hashOutputLengthOctets(uint8_t hashID) -{ - switch(hashID) { - case GT_HASHALG_SHA1: /* paper: SHA1 */ - return 20; - case GT_HASHALG_RIPEMD160: /* paper: RIPEMD-160 */ - return 20; - case GT_HASHALG_SHA224: /* paper: SHA2-224 */ - return 28; - case GT_HASHALG_SHA256: /* paper: SHA2-256 */ - return 32; - case GT_HASHALG_SHA384: /* paper: SHA2-384 */ - return 48; - case GT_HASHALG_SHA512: /* paper: SHA2-512 */ - return 64; - default:return 32; - } -} -static inline uint8_t -hashIdentifier(uint8_t hashID) -{ - switch(hashID) { - case GT_HASHALG_SHA1: /* paper: SHA1 */ - return 0x00; - case GT_HASHALG_RIPEMD160: /* paper: RIPEMD-160 */ - return 0x02; - case GT_HASHALG_SHA224: /* paper: SHA2-224 */ - return 0x03; - case GT_HASHALG_SHA256: /* paper: SHA2-256 */ - return 0x01; - case GT_HASHALG_SHA384: /* paper: SHA2-384 */ - return 0x04; - case GT_HASHALG_SHA512: /* paper: SHA2-512 */ - return 0x05; - default:return 0xff; - } -} - static void outputhash(GTDataHash *hash) { @@ -108,7 +69,6 @@ outputhash(GTDataHash *hash) } - void rsgtInit(char *usragent) { @@ -144,7 +104,6 @@ tlvbufPhysWrite(gtctx ctx) ssize_t iTotalWritten; ssize_t iWritten; char *pWriteBuf; - fprintf(stderr, "emu: writing TLV file!\n"); lenBuf = ctx->tlvIdx; pWriteBuf = ctx->tlvBuf; @@ -171,8 +130,6 @@ tlvbufPhysWrite(gtctx ctx) pWriteBuf += iWritten; } while(lenBuf > 0); /* Warning: do..while()! */ - //DBGOPRINT((obj_t*) pThis, "file %d write wrote %d bytes\n", pThis->fd, (int) iWritten); - finalize_it: ctx->tlvIdx = 0; } @@ -228,7 +185,10 @@ tlv8Write(gtctx ctx, int flags, int tlvtype, int len) void tlv16Write(gtctx ctx, int flags, int tlvtype, uint16_t len) { - tlvbufAddOctet(ctx, ((flags|1) << 13)|tlvtype); + uint16_t typ; + typ = ((flags|1) << 13)|tlvtype; + tlvbufAddOctet(ctx, typ >> 8); + tlvbufAddOctet(ctx, typ & 0xff); tlvbufAddOctet(ctx, (len >> 8) & 0xff); tlvbufAddOctet(ctx, len & 0xff); } @@ -245,11 +205,12 @@ tlvWriteBlockSig(gtctx ctx, uchar *der, uint16_t lenDer) { unsigned tlvlen; - tlvlen = 1 + 1 /* hash algo TLV */ + - 1 + hashOutputLengthOctets(ctx->hashAlg) /* iv */ + - 1 + 1 + ctx->lenBlkStrtHash /* last hash */ + - 1 + 8 /* rec-count (64 bit integer) */ + - 2 + lenDer /* rfc-3161 */; + tlvlen = 2 + 1 /* hash algo TLV */ + + 2 + hashOutputLengthOctets(ctx->hashAlg) /* iv */ + + 2 + 1 + ctx->lenBlkStrtHash /* last hash */ + + 2 + 8 /* rec-count (64 bit integer) */ + + 4 + lenDer /* rfc-3161 */; +printf("TTTT: tlvlen %u, lenDer %u\n", tlvlen, lenDer); /* write top-level TLV object (block-sig */ tlv16Write(ctx, 0x00, 0x0902, tlvlen); /* and now write the children */ @@ -258,13 +219,14 @@ tlvWriteBlockSig(gtctx ctx, uchar *der, uint16_t lenDer) tlv8Write(ctx, 0x00, 0x00, 1); tlvbufAddOctet(ctx, hashIdentifier(ctx->hashAlg)); /* block-iv */ - tlv8Write(ctx, 0x00, 0x01, 1); + tlv8Write(ctx, 0x00, 0x01, hashOutputLengthOctets(ctx->hashAlg)); tlvbufAddOctetString(ctx, ctx->IV, hashOutputLengthOctets(ctx->hashAlg)); /* last-hash */ - tlv8Write(ctx, 0x00, 0x02, 1); + tlv8Write(ctx, 0x00, 0x02, ctx->lenBlkStrtHash+1); + tlvbufAddOctet(ctx, hashIdentifier(ctx->hashAlg)); tlvbufAddOctetString(ctx, ctx->blkStrtHash, ctx->lenBlkStrtHash); /* rec-count */ - tlv8Write(ctx, 0x00, 0x03, 1); + tlv8Write(ctx, 0x00, 0x03, 8); tlvbufAddInt64(ctx, ctx->nRecords); /* rfc-3161 */ tlv16Write(ctx, 0x00, 0x906, lenDer); @@ -274,7 +236,6 @@ tlvWriteBlockSig(gtctx ctx, uchar *der, uint16_t lenDer) void tlvClose(gtctx ctx) { tlvFlush(ctx); - fprintf(stderr, "emu: close tlv file\n"); close(ctx->fd); ctx->fd = -1; } @@ -285,7 +246,6 @@ void tlvClose(gtctx ctx) */ void tlvOpen(gtctx ctx, char *hdr, unsigned lenHdr) { - fprintf(stderr, "emu: open tlv file '%s'\n", ctx->sigfilename); ctx->fd = open((char*)ctx->sigfilename, O_WRONLY/*|O_APPEND*/|O_CREAT|O_NOCTTY|O_CLOEXEC, 0600); // FIXME: check fd == -1 diff --git a/runtime/librsgt.h b/runtime/librsgt.h index cb1829e9..4ce0be30 100644 --- a/runtime/librsgt.h +++ b/runtime/librsgt.h @@ -70,6 +70,8 @@ struct block_sig_s { uint8_t hashID; uint8_t sigID; /* what type of *signature*? */ uint8_t *iv; + // TODO: think about the situation where the last hash is + // different from the current one (e.g. config change!) imprint_t lastHash; uint64_t recCount; struct { @@ -80,6 +82,87 @@ struct block_sig_s { } sig; }; +/* error states */ +#define RSGTE_IO 1 /* any kind of io error, including EOF */ +#define RSGTE_FMT 2 /* data fromat error */ +#define RSGTE_INVLTYP 3 /* invalid TLV type record (unexcpected at this point) */ +#define RSGTE_OOM 4 /* ran out of memory */ +#define RSGTE_LEN 5 /* error related to length records */ + + +static inline uint16_t +hashOutputLengthOctets(uint8_t hashID) +{ + switch(hashID) { + case GT_HASHALG_SHA1: /* paper: SHA1 */ + return 20; + case GT_HASHALG_RIPEMD160: /* paper: RIPEMD-160 */ + return 20; + case GT_HASHALG_SHA224: /* paper: SHA2-224 */ + return 28; + case GT_HASHALG_SHA256: /* paper: SHA2-256 */ + return 32; + case GT_HASHALG_SHA384: /* paper: SHA2-384 */ + return 48; + case GT_HASHALG_SHA512: /* paper: SHA2-512 */ + return 64; + default:return 32; + } +} + +static inline uint8_t +hashIdentifier(uint8_t hashID) +{ + switch(hashID) { + case GT_HASHALG_SHA1: /* paper: SHA1 */ + return 0x00; + case GT_HASHALG_RIPEMD160: /* paper: RIPEMD-160 */ + return 0x02; + case GT_HASHALG_SHA224: /* paper: SHA2-224 */ + return 0x03; + case GT_HASHALG_SHA256: /* paper: SHA2-256 */ + return 0x01; + case GT_HASHALG_SHA384: /* paper: SHA2-384 */ + return 0x04; + case GT_HASHALG_SHA512: /* paper: SHA2-512 */ + return 0x05; + default:return 0xff; + } +} +static inline char * +hashAlgName(uint8_t hashID) +{ + switch(hashID) { + case GT_HASHALG_SHA1: + return "SHA1"; + case GT_HASHALG_RIPEMD160: + return "RIPEMD-160"; + case GT_HASHALG_SHA224: + return "SHA2-224"; + case GT_HASHALG_SHA256: + return "SHA2-256"; + case GT_HASHALG_SHA384: + return "SHA2-384"; + case GT_HASHALG_SHA512: + return "SHA2-512"; + default:return "[unknown]"; + } +} +static inline char * +sigTypeName(uint8_t sigID) +{ + switch(sigID) { + case SIGID_RFC3161: + return "RFC3161"; + default:return "[unknown]"; + } +} +static inline uint16_t +getIVLen(block_sig_t *bs) +{ + return hashOutputLengthOctets(bs->hashID); +} + void rsgtInit(char *usragent); void rsgtExit(void); gtctx rsgtCtxNew(unsigned char *logfn, enum GTHashAlgorithm hashAlg); @@ -88,4 +171,9 @@ void sigblkInit(gtctx ctx); void sigblkAddRecord(gtctx ctx, const unsigned char *rec, const size_t len); void sigblkFinish(gtctx ctx); void rsgtCtxSetLogfileName(gtctx ctx, char *logfilename); +/* reader functions */ +int rsgt_tlvrdHeader(FILE *fp, unsigned char *hdr); +int rsgt_tlvrd(FILE *fp, uint16_t *tlvtype, uint16_t *tlvlen, void *obj); +void rsgt_tlvprint(FILE *fp, uint16_t tlvtype, void *obj, uint8_t verbose); + #endif /* #ifndef INCLUDED_LIBRSGT_H */ diff --git a/runtime/librsgt_read.c b/runtime/librsgt_read.c new file mode 100644 index 00000000..fa489a0f --- /dev/null +++ b/runtime/librsgt_read.c @@ -0,0 +1,348 @@ +/* librsgt_read.c - rsyslog's guardtime support library + * This includes functions used for reading signature (and + * other related) files. + * + * This part of the library uses C stdio and expects that the + * caller will open and close the file to be read itself. + * + * 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 <stdio.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdint.h> +#include <assert.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "librsgt.h" + +typedef unsigned char uchar; +#ifndef VERSION +#define VERSION "no-version" +#endif +#define MAXFNAME 1024 + +static int rsgt_read_debug = 0; + +/* macro to obtain next char from file including error tracking */ +#define NEXTC if((c = fgetc(fp)) == EOF) { \ + r = RSGTE_IO; \ + goto done; \ + } + +/* check return state of operation and abort, if non-OK */ +#define CHKr(code) if((r = code) != 0) goto done + +/** + * Read a header from a binary file. + * @param[in] fp file pointer for processing + * @param[in] hdr buffer for the header. Must be 9 bytes + * (8 for header + NUL byte) + * @returns 0 if ok, something else otherwise + */ +int +rsgt_tlvrdHeader(FILE *fp, uchar *hdr) +{ + int r; + if(fread(hdr, 8, 1, fp) != 1) { + r = RSGTE_IO; + goto done; + } + hdr[8] = '\0'; + r = 0; +done: return r; +} + +/* read type & length */ +static int +rsgt_tlvrdTL(FILE *fp, uint16_t *tlvtype, uint16_t *tlvlen) +{ + int r = 1; + int c; + + NEXTC; + *tlvtype = c & 0x1f; + if(c & 0x20) { /* tlv16? */ + NEXTC; + *tlvtype = (*tlvtype << 8) | c; + NEXTC; + *tlvlen = c << 8; + NEXTC; + *tlvlen |= c; + } else { + NEXTC; + *tlvlen = c; + } + if(rsgt_read_debug) + printf("read tlvtype %4.4x, len %u\n", (unsigned) *tlvtype, + (unsigned) *tlvlen); + r = 0; +done: return r; +} + +static int +rsgt_tlvrdOctetString(FILE *fp, uint8_t **data, size_t len) +{ + size_t i; + int c, r = 1; + if((*data = (uint8_t*)malloc(len)) == NULL) {r=RSGTE_OOM;goto done;} + for(i = 0 ; i < len ; ++i) { + NEXTC; + (*data)[i] = c; + } + r = 0; +done: return r; +} +static int +rsgt_tlvrdHASH_ALGO(FILE *fp, uint8_t *hashAlg) +{ + int r = 1; + int c; + uint16_t tlvtype, tlvlen; + + CHKr(rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)); + if(!(tlvtype == 0x00 && tlvlen == 1)) { + r = RSGTE_FMT; + goto done; + } + NEXTC; + *hashAlg = c; + r = 0; +done: return r; +} +static int +rsgt_tlvrdBLOCK_IV(FILE *fp, uint8_t **iv) +{ + int r = 1; + uint16_t tlvtype, tlvlen; + + CHKr(rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)); + if(!(tlvtype == 0x01)) { + r = RSGTE_INVLTYP; + goto done; + } + CHKr(rsgt_tlvrdOctetString(fp, iv, tlvlen)); + r = 0; +done: return r; +} +static int +rsgt_tlvrdLAST_HASH(FILE *fp, imprint_t *imp) +{ + int r = 1; + int c; + uint16_t tlvtype, tlvlen; + + CHKr(rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)); + if(!(tlvtype == 0x02)) { r = RSGTE_INVLTYP; goto done; } + NEXTC; + imp->hashID = c; + imp->len = tlvlen - 1; + CHKr(rsgt_tlvrdOctetString(fp, &imp->data, tlvlen-1)); + r = 0; +done: return r; +} +static int +rsgt_tlvrdREC_COUNT(FILE *fp, uint64_t *cnt, size_t *lenInt) +{ + int r = 1; + int i; + int c; + uint64_t val; + uint16_t tlvtype, tlvlen; + + if((r = rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)) != 0) goto done; + if(!(tlvtype == 0x03 && tlvlen <= 8)) { r = RSGTE_INVLTYP; goto done; } + *lenInt = tlvlen; + val = 0; + for(i = 0 ; i < tlvlen ; ++i) { + NEXTC; + val = (val << 8) + c; + } + *cnt = val; + r = 0; +done: return r; +} +static int +rsgt_tlvrdSIG(FILE *fp, block_sig_t *bs) +{ + int r = 1; + uint16_t tlvtype, tlvlen; + + CHKr(rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)); + if(!(tlvtype == 0x0906)) { r = RSGTE_INVLTYP; goto done; } + bs->sig.der.len = tlvlen; + bs->sigID = SIGID_RFC3161; + CHKr(rsgt_tlvrdOctetString(fp, &(bs->sig.der.data), tlvlen)); + r = 0; +done: return r; +} + +static int +rsgt_tlvrdBLOCK_SIG(FILE *fp, block_sig_t **blocksig, uint16_t tlvlen) +{ + int r = 1; + size_t lenInt = 0; + uint16_t sizeRead; + block_sig_t *bs; + if((bs = calloc(1, sizeof(block_sig_t))) == NULL) { + r = RSGTE_OOM; + goto done; + } + CHKr(rsgt_tlvrdHASH_ALGO(fp, &(bs->hashID))); + CHKr(rsgt_tlvrdBLOCK_IV(fp, &(bs->iv))); + CHKr(rsgt_tlvrdLAST_HASH(fp, &(bs->lastHash))); + CHKr(rsgt_tlvrdREC_COUNT(fp, &(bs->recCount), &lenInt)); + CHKr(rsgt_tlvrdSIG(fp, bs)); + sizeRead = 2 + 1 /* hash algo TLV */ + + 2 + getIVLen(bs) /* iv */ + + 2 + 1 + bs->lastHash.len /* last hash */ + + 2 + lenInt /* rec-count */ + + 4 + bs->sig.der.len /* rfc-3161 */; + if(sizeRead != tlvlen) { + printf("lenght record error!\n"); + r = RSGTE_LEN; + goto done; + } + *blocksig = bs; + r = 0; +done: return r; +} + + +/** + * Read the next "object" from file. This usually is + * a single TLV, but may be something larger, for + * example in case of a block-sig TLV record. + * Unknown type records are ignored (or run aborted + * if we are not permitted to skip). + * + * @param[in] fp file pointer for processing + * @param[out] tlvtype type of tlv record (top-level for + * structured objects. + * @param[out] tlvlen length of the tlv record value + * @param[out] obj pointer to object; This is a proper + * tlv record structure, which must be casted + * by the caller according to the reported type. + * The object must be freed by the caller (TODO: better way?) + * + * @returns 0 if ok, something else otherwise + */ +int +rsgt_tlvrd(FILE *fp, uint16_t *tlvtype, uint16_t *tlvlen, void *obj) +{ + int r = 1; + + if((r = rsgt_tlvrdTL(fp, tlvtype, tlvlen)) != 0) goto done; + switch(*tlvtype) { + case 0x0902: + r = rsgt_tlvrdBLOCK_SIG(fp, obj, *tlvlen); + if(r != 0) goto done; + break; + } + r = 0; +done: return r; +} + + +/* if verbose==0, only the first and last two octets are shown, + * otherwise everything. + */ +static void +outputHexBlob(uint8_t *blob, uint16_t len, uint8_t verbose) +{ + unsigned i; + if(verbose || len <= 6) { + for(i = 0 ; i < len ; ++i) + printf("%2.2x", blob[i]); + } else { + printf("%2.2x%2.2x[...]%2.2x%2.2x", + blob[0], blob[1], + blob[len-2], blob[len-2]); + } +} + +/* return if a blob is all zero */ +static inline int +blobIsZero(uint8_t *blob, uint16_t len) +{ + int i; + for(i = 0 ; i < len ; ++i) + if(blob[i] != 0) + return 0; + return 1; +} +/** + * Output a human-readable representation of a block_sig_t + * to proviced file pointer. This function is mainly inteded for + * debugging purposes or dumping tlv files. + * + * @param[in] fp file pointer to send output to + * @param[in] bsig ponter to block_sig_t to output + * @param[in] verbose if 0, abbreviate blob hexdump, else complete + */ +void +rsgt_printBLOCK_SIG(FILE *fp, block_sig_t *bs, uint8_t verbose) +{ + fprintf(fp, "Block Signature Record [0x0902]:\n"); + fprintf(fp, "\tPrevious Block Hash:\n"); + fprintf(fp, "\t Algorithm..: %s\n", hashAlgName(bs->lastHash.hashID)); + fprintf(fp, "\t Hash.......: "); + outputHexBlob(bs->lastHash.data, bs->lastHash.len, verbose); + fputc('\n', fp); + if(blobIsZero(bs->lastHash.data, bs->lastHash.len)) + fprintf(fp, "\t NOTE: New Hash Chain Start!\n"); + fprintf(fp, "\tHash Algorithm: %s\n", hashAlgName(bs->hashID)); + fprintf(fp, "\tIV............: "); + outputHexBlob(bs->iv, getIVLen(bs), verbose); + fputc('\n', fp); + fprintf(fp, "\tRecord Count..: %llu\n", bs->recCount); + fprintf(fp, "\tSignature Type: %s\n", sigTypeName(bs->sigID)); + fprintf(fp, "\tSignature Len.: %u\n", bs->sig.der.len); + fprintf(fp, "\tSignature.....: "); + outputHexBlob(bs->sig.der.data, bs->sig.der.len, verbose); + fputc('\n', fp); +} + + +/** + * Output a human-readable representation of a tlv object. + * + * @param[in] fp file pointer to send output to + * @param[in] tlvtype type of tlv object (record) + * @param[in] verbose if 0, abbreviate blob hexdump, else complete + */ +void +rsgt_tlvprint(FILE *fp, uint16_t tlvtype, void *obj, uint8_t verbose) +{ + switch(tlvtype) { + case 0x0902: + rsgt_printBLOCK_SIG(fp, obj, verbose); + break; + default:fprintf(fp, "unknown tlv record %4.4x\n", tlvtype); + break; + } +} |