diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2013-03-25 18:54:21 +0100 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2013-03-25 18:54:21 +0100 |
commit | 88be3a67958ec8dcef9acc2df09d66d2ee6970ea (patch) | |
tree | 72c18b97d28682aa46ffaf4428f29cb8329a37ba | |
parent | 28a34dab0752968f53f6a2d4de2c6b64463e8b06 (diff) | |
parent | 95e2ffec16c925097e1a478b44e031cd1348164a (diff) | |
download | rsyslog-88be3a67958ec8dcef9acc2df09d66d2ee6970ea.tar.gz rsyslog-88be3a67958ec8dcef9acc2df09d66d2ee6970ea.tar.bz2 rsyslog-88be3a67958ec8dcef9acc2df09d66d2ee6970ea.zip |
Merge branch 'master-gt'
-rw-r--r-- | runtime/Makefile.am | 2 | ||||
-rw-r--r-- | runtime/librsgt.c | 5 | ||||
-rw-r--r-- | runtime/librsgt.h | 26 | ||||
-rw-r--r-- | runtime/librsgt_read.c | 490 | ||||
-rw-r--r-- | tools/rsgtutil.c | 149 | ||||
-rw-r--r-- | tools/rsgtutil.rst | 29 |
6 files changed, 504 insertions, 197 deletions
diff --git a/runtime/Makefile.am b/runtime/Makefile.am index ac793484..8f969512 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_read.c + librsgt_la_SOURCES = librsgt.c librsgt_read.c librsgt.h pkglib_LTLIBRARIES += lmsig_gt.la lmsig_gt_la_SOURCES = lmsig_gt.c diff --git a/runtime/librsgt.c b/runtime/librsgt.c index e24c3769..adcc2a8a 100644 --- a/runtime/librsgt.c +++ b/runtime/librsgt.c @@ -277,6 +277,10 @@ tlvWriteBlockSig(gtfile gf, uchar *der, uint16_t lenDer) tlvbufAddOctetString(gf, der, lenDer); } +/* support for old platforms - graceful degrade */ +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif /* read rsyslog log state file; if we cannot access it or the * contents looks invalid, we flag it as non-present (and thus * begin a new hash chain). @@ -627,6 +631,7 @@ timestampIt(gtfile gf, GTDataHash *hash) /* Encode timestamp. */ r = GTTimestamp_getDEREncoded(timestamp, &der, &lenDer); if(r != GT_OK) { + // TODO: use rsyslog error reporting! fprintf(stderr, "GTTimestamp_getDEREncoded() failed: %d (%s)\n", r, GT_getErrorString(r)); goto done; diff --git a/runtime/librsgt.h b/runtime/librsgt.h index 98384bb9..d308d4c3 100644 --- a/runtime/librsgt.h +++ b/runtime/librsgt.h @@ -76,6 +76,15 @@ typedef struct gtfile_s *gtfile; typedef struct gterrctx_s gterrctx_t; typedef struct imprint_s imprint_t; typedef struct block_sig_s block_sig_t; +typedef struct tlvrecord_s tlvrecord_t; + +struct tlvrecord_s { + uint16_t tlvtype; + uint16_t tlvlen; + uint8_t hdr[4]; /* the raw header (as persisted to file) */ + uint8_t lenHdr; /* length of raw header */ + uint8_t data[64*1024]; /* the actual data part (of length tlvlen) */ +}; /* The following structure describes the "error context" to be used * for verification and similiar reader functions. While verifying, @@ -138,13 +147,16 @@ struct rsgtstatefile { /* after that, the hash value is contained within the file */ }; +/* Flags and record types for TLV handling */ +#define RSGT_FLAG_TLV16 0x20 + /* error states */ #define RSGTE_IO 1 /* any kind of io error */ #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 */ -// 6 may be reused! +#define RSGTE_TS_EXTEND 6/* error extending timestamp */ #define RSGTE_INVLD_RECCNT 7/* mismatch between actual records and records given in block-sig record */ #define RSGTE_INVLHDR 8/* invalid file header */ @@ -158,6 +170,7 @@ struct rsgtstatefile { #define RSGTE_MISS_BLOCKSIG 16 /* block signature record missing when expected */ #define RSGTE_INVLD_TIMESTAMP 17 /* RFC3161 timestamp is invalid */ #define RSGTE_TS_DERDECODE 18 /* error DER-Decoding a timestamp */ +#define RSGTE_TS_DERENCODE 19 /* error DER-Encoding a timestamp */ /* the following function maps RSGTE_* state to a string - must be updated * whenever a new state is added. @@ -180,6 +193,8 @@ RSGTE2String(int err) return "out of memory"; case RSGTE_LEN: return "length record problem"; + case RSGTE_TS_EXTEND: + return "error extending timestamp"; case RSGTE_INVLD_RECCNT: return "mismatch between actual record count and number in block signature record"; case RSGTE_INVLHDR: @@ -204,6 +219,8 @@ RSGTE2String(int err) return "RFC3161 timestamp invalid"; case RSGTE_TS_DERDECODE: return "error DER-decoding RFC3161 timestamp"; + case RSGTE_TS_DERENCODE: + return "error DER-encoding RFC3161 timestamp"; default: return "unknown error"; } @@ -336,19 +353,20 @@ void sigblkAddRecord(gtfile gf, const unsigned char *rec, const size_t len); void sigblkFinish(gtfile gf); /* reader functions */ int rsgt_tlvrdHeader(FILE *fp, unsigned char *hdr); -int rsgt_tlvrd(FILE *fp, uint16_t *tlvtype, uint16_t *tlvlen, void *obj); +int rsgt_tlvrd(FILE *fp, tlvrecord_t *rec, void *obj); void rsgt_tlvprint(FILE *fp, uint16_t tlvtype, void *obj, uint8_t verbose); void rsgt_printBLOCK_SIG(FILE *fp, block_sig_t *bs, uint8_t verbose); int rsgt_getBlockParams(FILE *fp, uint8_t bRewind, block_sig_t **bs, uint8_t *bHasRecHashes, uint8_t *bHasIntermedHashes); int rsgt_chkFileHdr(FILE *fp, char *expect); gtfile rsgt_vrfyConstruct_gf(void); void rsgt_vrfyBlkInit(gtfile gf, block_sig_t *bs, uint8_t bHasRecHashes, uint8_t bHasIntermedHashes); -int rsgt_vrfy_nextRec(block_sig_t *bs, gtfile gf, FILE *sigfp, unsigned char *rec, size_t lenRec, gterrctx_t *ectx); -int verifyBLOCK_SIG(block_sig_t *bs, gtfile gf, FILE *sigfp, gterrctx_t *ectx); +int rsgt_vrfy_nextRec(block_sig_t *bs, gtfile gf, FILE *sigfp, FILE *nsigfp, unsigned char *rec, size_t len, gterrctx_t *ectx); +int verifyBLOCK_SIG(block_sig_t *bs, gtfile gf, FILE *sigfp, FILE *nsigfp, uint8_t bExtend, gterrctx_t *ectx); void rsgt_errctxInit(gterrctx_t *ectx); void rsgt_errctxExit(gterrctx_t *ectx); void rsgt_errctxSetErrRec(gterrctx_t *ectx, char *rec); void rsgt_errctxFrstRecInBlk(gterrctx_t *ectx, char *rec); +void rsgt_objfree(uint16_t tlvtype, void *obj); /* TODO: replace these? */ diff --git a/runtime/librsgt_read.c b/runtime/librsgt_read.c index e32ae454..29a07e54 100644 --- a/runtime/librsgt_read.c +++ b/runtime/librsgt_read.c @@ -1,6 +1,8 @@ /* librsgt_read.c - rsyslog's guardtime support library * This includes functions used for reading signature (and - * other related) files. + * other related) files. Well, actually it also contains + * some writing functionality, but only as far as rsyslog + * itself is not concerned, but "just" the utility programs. * * This part of the library uses C stdio and expects that the * caller will open and close the file to be read itself. @@ -49,6 +51,7 @@ typedef unsigned char uchar; static int rsgt_read_debug = 0; char *rsgt_read_puburl = "http://verify.guardtime.com/gt-controlpublications.bin"; +char *rsgt_extend_puburl = "http://verifier.guardtime.net/gt-extendingservice"; uint8_t rsgt_read_showVerified = 0; /* macro to obtain next char from file including error tracking */ @@ -97,6 +100,8 @@ rsgt_errctxInit(gterrctx_t *ectx) ectx->verbose = 0; ectx->errRec = NULL; ectx->frstRecInBlk = NULL; + ectx->fileHash = NULL; + ectx->lefthash = ectx->righthash = ectx->computedHash = NULL; } void rsgt_errctxExit(gterrctx_t *ectx) @@ -160,6 +165,16 @@ reportError(int errcode, gterrctx_t *ectx) fprintf(ectx->fp, "\tGT Verify Timestamp: [%u]%s\n", ectx->gtstate, GTHTTP_getErrorString(ectx->gtstate)); } + if(errcode == RSGTE_TS_EXTEND || + errcode == RSGTE_TS_DERDECODE) { + fprintf(ectx->fp, "\tExtending Server...: %s\n", rsgt_extend_puburl); + fprintf(ectx->fp, "\tGT Extend Timestamp: [%u]%s\n", + ectx->gtstate, GTHTTP_getErrorString(ectx->gtstate)); + } + if(errcode == RSGTE_TS_DERENCODE) { + fprintf(ectx->fp, "\tAPI return state...: [%u]%s\n", + ectx->gtstate, GTHTTP_getErrorString(ectx->gtstate)); + } } } @@ -167,7 +182,7 @@ reportError(int errcode, gterrctx_t *ectx) * ectx, as it has most information we need. */ static void -reportVerifySuccess(gterrctx_t *ectx) +reportVerifySuccess(gterrctx_t *ectx, GTVerificationInfo *vrfyInf) { if(ectx->fp != NULL) { fprintf(ectx->fp, "%s[%llu:%llu:%llu]: block signature successfully verified\n", @@ -180,9 +195,27 @@ reportVerifySuccess(gterrctx_t *ectx) fprintf(ectx->fp, "\tBlock End Record...: '%s'\n", ectx->errRec); fprintf(ectx->fp, "\tGT Verify Timestamp: [%u]%s\n", ectx->gtstate, GTHTTP_getErrorString(ectx->gtstate)); + GTVerificationInfo_print(ectx->fp, 0, vrfyInf); } } +/** + * Write the provided record to the current file position. + * + * @param[in] fp file pointer for writing + * @param[out] rec tlvrecord to write + * + * @returns 0 if ok, something else otherwise + */ +static int +rsgt_tlvwrite(FILE *fp, tlvrecord_t *rec) +{ + int r = RSGTE_IO; + if(fwrite(rec->hdr, (size_t) rec->lenHdr, 1, fp) != 1) goto done; + if(fwrite(rec->data, (size_t) rec->tlvlen, 1, fp) != 1) goto done; + r = 0; +done: return r; +} /** * Read a header from a binary file. @@ -204,167 +237,216 @@ rsgt_tlvrdHeader(FILE *fp, uchar *hdr) done: return r; } -/* read type & length */ +/* read type a complete tlv record + */ static int -rsgt_tlvrdTL(FILE *fp, uint16_t *tlvtype, uint16_t *tlvlen) +rsgt_tlvRecRead(FILE *fp, tlvrecord_t *rec) { int r = 1; int c; NEXTC; - *tlvtype = c & 0x1f; + rec->hdr[0] = c; + rec->tlvtype = c & 0x1f; if(c & 0x20) { /* tlv16? */ + rec->lenHdr = 4; NEXTC; - *tlvtype = (*tlvtype << 8) | c; + rec->hdr[1] = c; + rec->tlvtype = (rec->tlvtype << 8) | c; NEXTC; - *tlvlen = c << 8; + rec->hdr[2] = c; + rec->tlvlen = c << 8; NEXTC; - *tlvlen |= c; + rec->hdr[3] = c; + rec->tlvlen |= c; } else { NEXTC; - *tlvlen = c; + rec->lenHdr = 2; + rec->hdr[1] = c; + rec->tlvlen = c; } + if(fread(rec->data, (size_t) rec->tlvlen, 1, fp) != 1) { + r = RSGTE_IO; + goto done; + } + if(rsgt_read_debug) - printf("read tlvtype %4.4x, len %u\n", (unsigned) *tlvtype, - (unsigned) *tlvlen); + printf("read tlvtype %4.4x, len %u\n", (unsigned) rec->tlvtype, + (unsigned) rec->tlvlen); r = 0; done: return r; } +/* decode a sub-tlv record from an existing record's memory buffer + */ static int -rsgt_tlvrdOctetString(FILE *fp, uint8_t **data, size_t len) +rsgt_tlvDecodeSUBREC(tlvrecord_t *rec, uint16_t *stridx, tlvrecord_t *newrec) { - 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; + int r = 1; + int c; + + if(rec->tlvlen == *stridx) {r=RSGTE_LEN; goto done;} + c = rec->data[(*stridx)++]; + newrec->hdr[0] = c; + newrec->tlvtype = c & 0x1f; + if(c & 0x20) { /* tlv16? */ + newrec->lenHdr = 4; + if(rec->tlvlen == *stridx) {r=RSGTE_LEN; goto done;} + c = rec->data[(*stridx)++]; + newrec->hdr[1] = c; + newrec->tlvtype = (newrec->tlvtype << 8) | c; + if(rec->tlvlen == *stridx) {r=RSGTE_LEN; goto done;} + c = rec->data[(*stridx)++]; + newrec->hdr[2] = c; + newrec->tlvlen = c << 8; + if(rec->tlvlen == *stridx) {r=RSGTE_LEN; goto done;} + c = rec->data[(*stridx)++]; + newrec->hdr[3] = c; + newrec->tlvlen |= c; + } else { + if(rec->tlvlen == *stridx) {r=RSGTE_LEN; goto done;} + c = rec->data[(*stridx)++]; + newrec->lenHdr = 2; + newrec->hdr[1] = c; + newrec->tlvlen = c; } + if(rec->tlvlen < *stridx + newrec->tlvlen) {r=RSGTE_LEN; goto done;} + memcpy(newrec->data, (rec->data)+(*stridx), newrec->tlvlen); + *stridx += newrec->tlvlen; + + if(rsgt_read_debug) + printf("read sub-tlv: tlvtype %4.4x, len %u\n", + (unsigned) newrec->tlvtype, + (unsigned) newrec->tlvlen); r = 0; done: return r; } + + static int -rsgt_tlvrdSkipVal(FILE *fp, size_t len) +rsgt_tlvDecodeIMPRINT(tlvrecord_t *rec, imprint_t **imprint) { - size_t i; - int c, r = 1; - for(i = 0 ; i < len ; ++i) { - NEXTC; + int r = 1; + imprint_t *imp; + + if((imp = calloc(1, sizeof(imprint_t))) == NULL) { + r = RSGTE_OOM; + goto done; + } + + imp->hashID = rec->data[0]; + if(rec->tlvlen != 1 + hashOutputLengthOctets(imp->hashID)) { + r = RSGTE_LEN; + goto done; } + imp->len = rec->tlvlen - 1; + if((imp->data = (uint8_t*)malloc(imp->len)) == NULL) {r=RSGTE_OOM;goto done;} + memcpy(imp->data, rec->data+1, imp->len); + *imprint = imp; r = 0; done: return r; } + static int -rsgt_tlvrdHASH_ALGO(FILE *fp, uint8_t *hashAlg) +rsgt_tlvDecodeHASH_ALGO(tlvrecord_t *rec, uint16_t *strtidx, uint8_t *hashAlg) { int r = 1; - int c; - uint16_t tlvtype, tlvlen; + tlvrecord_t subrec; - CHKr(rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)); - if(!(tlvtype == 0x00 && tlvlen == 1)) { + CHKr(rsgt_tlvDecodeSUBREC(rec, strtidx, &subrec)); + if(!(subrec.tlvtype == 0x00 && subrec.tlvlen == 1)) { r = RSGTE_FMT; goto done; } - NEXTC; - *hashAlg = c; + *hashAlg = subrec.data[0]; r = 0; done: return r; } static int -rsgt_tlvrdBLOCK_IV(FILE *fp, uint8_t **iv) +rsgt_tlvDecodeBLOCK_IV(tlvrecord_t *rec, uint16_t *strtidx, uint8_t **iv) { int r = 1; - uint16_t tlvtype, tlvlen; + tlvrecord_t subrec; - CHKr(rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)); - if(!(tlvtype == 0x01)) { + CHKr(rsgt_tlvDecodeSUBREC(rec, strtidx, &subrec)); + if(!(subrec.tlvtype == 0x01)) { r = RSGTE_INVLTYP; goto done; } - CHKr(rsgt_tlvrdOctetString(fp, iv, tlvlen)); + if((*iv = (uint8_t*)malloc(subrec.tlvlen)) == NULL) {r=RSGTE_OOM;goto done;} + memcpy(*iv, subrec.data, subrec.tlvlen); r = 0; done: return r; } static int -rsgt_tlvrdLAST_HASH(FILE *fp, imprint_t *imp) +rsgt_tlvDecodeLAST_HASH(tlvrecord_t *rec, uint16_t *strtidx, imprint_t *imp) { int r = 1; - int c; - uint16_t tlvtype, tlvlen; + tlvrecord_t subrec; - CHKr(rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)); - if(!(tlvtype == 0x02)) { r = RSGTE_INVLTYP; goto done; } - NEXTC; - imp->hashID = c; - if(tlvlen != 1 + hashOutputLengthOctets(imp->hashID)) { + CHKr(rsgt_tlvDecodeSUBREC(rec, strtidx, &subrec)); + if(!(subrec.tlvtype == 0x02)) { r = RSGTE_INVLTYP; goto done; } + imp->hashID = subrec.data[0]; + if(subrec.tlvlen != 1 + hashOutputLengthOctets(imp->hashID)) { r = RSGTE_LEN; goto done; } - imp->len = tlvlen - 1; - CHKr(rsgt_tlvrdOctetString(fp, &imp->data, tlvlen-1)); + imp->len = subrec.tlvlen - 1; + if((imp->data = (uint8_t*)malloc(imp->len)) == NULL) {r=RSGTE_OOM;goto done;} + memcpy(imp->data, subrec.data+1, subrec.tlvlen-1); r = 0; done: return r; } static int -rsgt_tlvrdREC_COUNT(FILE *fp, uint64_t *cnt, size_t *lenInt) +rsgt_tlvDecodeREC_COUNT(tlvrecord_t *rec, uint16_t *strtidx, uint64_t *cnt) { int r = 1; int i; - int c; uint64_t val; - uint16_t tlvtype, tlvlen; + tlvrecord_t subrec; - if((r = rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)) != 0) goto done; - if(!(tlvtype == 0x03 && tlvlen <= 8)) { r = RSGTE_INVLTYP; goto done; } - *lenInt = tlvlen; + CHKr(rsgt_tlvDecodeSUBREC(rec, strtidx, &subrec)); + if(!(subrec.tlvtype == 0x03 && subrec.tlvlen <= 8)) { r = RSGTE_INVLTYP; goto done; } val = 0; - for(i = 0 ; i < tlvlen ; ++i) { - NEXTC; - val = (val << 8) + c; + for(i = 0 ; i < subrec.tlvlen ; ++i) { + val = (val << 8) + subrec.data[i]; } *cnt = val; r = 0; done: return r; } static int -rsgt_tlvrdSIG(FILE *fp, block_sig_t *bs) +rsgt_tlvDecodeSIG(tlvrecord_t *rec, uint16_t *strtidx, block_sig_t *bs) { int r = 1; - uint16_t tlvtype, tlvlen; + tlvrecord_t subrec; - CHKr(rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)); - if(!(tlvtype == 0x0906)) { r = RSGTE_INVLTYP; goto done; } - bs->sig.der.len = tlvlen; + CHKr(rsgt_tlvDecodeSUBREC(rec, strtidx, &subrec)); + if(!(subrec.tlvtype == 0x0906)) { r = RSGTE_INVLTYP; goto done; } + bs->sig.der.len = subrec.tlvlen; bs->sigID = SIGID_RFC3161; - CHKr(rsgt_tlvrdOctetString(fp, &(bs->sig.der.data), tlvlen)); + if((bs->sig.der.data = (uint8_t*)malloc(bs->sig.der.len)) == NULL) {r=RSGTE_OOM;goto done;} + memcpy(bs->sig.der.data, subrec.data, bs->sig.der.len); r = 0; done: return r; } static int -rsgt_tlvrdBLOCK_SIG(FILE *fp, block_sig_t **blocksig, uint16_t tlvlen) +rsgt_tlvDecodeBLOCK_SIG(tlvrecord_t *rec, block_sig_t **blocksig) { int r = 1; - size_t lenInt = 0; - uint16_t sizeRead; + uint16_t strtidx = 0; 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) { + CHKr(rsgt_tlvDecodeHASH_ALGO(rec, &strtidx, &(bs->hashID))); + CHKr(rsgt_tlvDecodeBLOCK_IV(rec, &strtidx, &(bs->iv))); + CHKr(rsgt_tlvDecodeLAST_HASH(rec, &strtidx, &(bs->lastHash))); + CHKr(rsgt_tlvDecodeREC_COUNT(rec, &strtidx, &(bs->recCount))); + CHKr(rsgt_tlvDecodeSIG(rec, &strtidx, bs)); + if(strtidx != rec->tlvlen) { r = RSGTE_LEN; goto done; } @@ -372,87 +454,78 @@ rsgt_tlvrdBLOCK_SIG(FILE *fp, block_sig_t **blocksig, uint16_t tlvlen) r = 0; done: return r; } - static int -rsgt_tlvrdIMPRINT(FILE *fp, imprint_t **imprint, uint16_t tlvlen) +rsgt_tlvRecDecode(tlvrecord_t *rec, void *obj) { int r = 1; - imprint_t *imp; - int c; - - if((imp = calloc(1, sizeof(imprint_t))) == NULL) { - r = RSGTE_OOM; - goto done; - } - if((imp->data = calloc(1, sizeof(imprint_t))) == NULL) { - r = RSGTE_OOM; - goto done; - } - - NEXTC; - imp->hashID = c; - if(tlvlen != 1 + hashOutputLengthOctets(imp->hashID)) { - r = RSGTE_LEN; - goto done; + switch(rec->tlvtype) { + case 0x0900: + case 0x0901: + r = rsgt_tlvDecodeIMPRINT(rec, obj); + if(r != 0) goto done; + break; + case 0x0902: + r = rsgt_tlvDecodeBLOCK_SIG(rec, obj); + if(r != 0) goto done; + break; } - imp->len = tlvlen - 1; - CHKr(rsgt_tlvrdOctetString(fp, &imp->data, tlvlen-1)); - - *imprint = imp; - r = 0; -done: return r; +done: + return r; } static int -rsgt_tlvrdRecHash(FILE *fp, imprint_t **imp) +rsgt_tlvrdRecHash(FILE *fp, FILE *outfp, imprint_t **imp) { int r; - uint16_t tlvtype, tlvlen; + tlvrecord_t rec; - if((r = rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)) != 0) goto done; - if(tlvtype != 0x0900) { + if((r = rsgt_tlvrd(fp, &rec, imp)) != 0) goto done; + if(rec.tlvtype != 0x0900) { r = RSGTE_MISS_REC_HASH; + rsgt_objfree(rec.tlvtype, *imp); goto done; } - if((r = rsgt_tlvrdIMPRINT(fp, imp, tlvlen)) != 0) goto done; + if(outfp != NULL) + if((r = rsgt_tlvwrite(outfp, &rec)) != 0) goto done; r = 0; done: return r; } static int -rsgt_tlvrdTreeHash(FILE *fp, imprint_t **imp) +rsgt_tlvrdTreeHash(FILE *fp, FILE *outfp, imprint_t **imp) { int r; - uint16_t tlvtype, tlvlen; + tlvrecord_t rec; - if((r = rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)) != 0) goto done; - if(tlvtype != 0x0901) { + if((r = rsgt_tlvrd(fp, &rec, imp)) != 0) goto done; + if(rec.tlvtype != 0x0901) { r = RSGTE_MISS_TREE_HASH; + rsgt_objfree(rec.tlvtype, *imp); goto done; } - if((r = rsgt_tlvrdIMPRINT(fp, imp, tlvlen)) != 0) goto done; + if(outfp != NULL) + if((r = rsgt_tlvwrite(outfp, &rec)) != 0) goto done; r = 0; done: return r; } /* read BLOCK_SIG during verification phase */ static int -rsgt_tlvrdVrfyBlockSig(FILE *fp, block_sig_t **bs) +rsgt_tlvrdVrfyBlockSig(FILE *fp, block_sig_t **bs, tlvrecord_t *rec) { int r; - uint16_t tlvtype, tlvlen; - if((r = rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)) != 0) goto done; - if(tlvtype != 0x0902) { + if((r = rsgt_tlvrd(fp, rec, bs)) != 0) goto done; + if(rec->tlvtype != 0x0902) { r = RSGTE_MISS_BLOCKSIG; + rsgt_objfree(rec->tlvtype, *bs); goto done; } - if((r = rsgt_tlvrdBLOCK_SIG(fp, bs, tlvlen)) != 0) goto done; 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. @@ -471,29 +544,15 @@ done: return r; * @returns 0 if ok, something else otherwise */ int -rsgt_tlvrd(FILE *fp, uint16_t *tlvtype, uint16_t *tlvlen, void *obj) +rsgt_tlvrd(FILE *fp, tlvrecord_t *rec, void *obj) { - int r = 1; - - if((r = rsgt_tlvrdTL(fp, tlvtype, tlvlen)) != 0) goto done; - switch(*tlvtype) { - case 0x0900: - r = rsgt_tlvrdIMPRINT(fp, obj, *tlvlen); - if(r != 0) goto done; - break; - case 0x0901: - r = rsgt_tlvrdIMPRINT(fp, obj, *tlvlen); - if(r != 0) goto done; - break; - case 0x0902: - r = rsgt_tlvrdBLOCK_SIG(fp, obj, *tlvlen); - if(r != 0) goto done; - break; - } - r = 0; + int r; + if((r = rsgt_tlvRecRead(fp, rec)) != 0) goto done; + r = rsgt_tlvRecDecode(rec, obj); done: return r; } + /* return if a blob is all zero */ static inline int blobIsZero(uint8_t *blob, uint16_t len) @@ -585,6 +644,31 @@ rsgt_tlvprint(FILE *fp, uint16_t tlvtype, void *obj, uint8_t verbose) } } +/** + * Free the provided object. + * + * @param[in] tlvtype type of tlv object (record) + * @param[in] obj the object to be destructed + */ +void +rsgt_objfree(uint16_t tlvtype, void *obj) +{ + switch(tlvtype) { + case 0x0900: + case 0x0901: + free(((imprint_t*)obj)->data); + break; + case 0x0902: + free(((block_sig_t*)obj)->iv); + free(((block_sig_t*)obj)->lastHash.data); + free(((block_sig_t*)obj)->sig.der.data); + break; + default:fprintf(stderr, "rsgt_objfree: unknown tlv record %4.4x\n", + tlvtype); + break; + } + free(obj); +} /** * Read block parameters. This detects if the block contains the @@ -615,9 +699,10 @@ rsgt_getBlockParams(FILE *fp, uint8_t bRewind, block_sig_t **bs, { int r; uint64_t nRecs = 0; - uint16_t tlvtype, tlvlen; uint8_t bDone = 0; off_t rewindPos = 0; + void *obj; + tlvrecord_t rec; if(bRewind) rewindPos = ftello(fp); @@ -626,25 +711,24 @@ rsgt_getBlockParams(FILE *fp, uint8_t bRewind, block_sig_t **bs, *bs = NULL; while(!bDone) { /* we will err out on EOF */ - if((r = rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)) != 0) goto done; - switch(tlvtype) { + if((r = rsgt_tlvrd(fp, &rec, &obj)) != 0) goto done; + switch(rec.tlvtype) { case 0x0900: ++nRecs; *bHasRecHashes = 1; - rsgt_tlvrdSkipVal(fp, tlvlen); break; case 0x0901: *bHasIntermedHashes = 1; - rsgt_tlvrdSkipVal(fp, tlvlen); break; case 0x0902: - r = rsgt_tlvrdBLOCK_SIG(fp, bs, tlvlen); - if(r != 0) goto done; + *bs = (block_sig_t*) obj; bDone = 1; break; - default:fprintf(fp, "unknown tlv record %4.4x\n", tlvtype); + default:fprintf(fp, "unknown tlv record %4.4x\n", rec.tlvtype); break; } + if(!bDone) + rsgt_objfree(rec.tlvtype, obj); } if(*bHasRecHashes && (nRecs != (*bs)->recCount)) { @@ -712,12 +796,13 @@ rsgt_vrfyBlkInit(gtfile gf, block_sig_t *bs, uint8_t bHasRecHashes, uint8_t bHas } static int -rsgt_vrfy_chkRecHash(gtfile gf, FILE *sigfp, GTDataHash *recHash, gterrctx_t *ectx) +rsgt_vrfy_chkRecHash(gtfile gf, FILE *sigfp, FILE *nsigfp, + GTDataHash *recHash, gterrctx_t *ectx) { int r = 0; - imprint_t *imp; + imprint_t *imp = NULL; - if((r = rsgt_tlvrdRecHash(sigfp, &imp)) != 0) + if((r = rsgt_tlvrdRecHash(sigfp, nsigfp, &imp)) != 0) reportError(r, ectx); goto done; if(imp->hashID != hashIdentifier(gf->hashAlg)) { @@ -736,16 +821,19 @@ rsgt_vrfy_chkRecHash(gtfile gf, FILE *sigfp, GTDataHash *recHash, gterrctx_t *ec } r = 0; done: + if(imp != NULL) + rsgt_objfree(0x0900, imp); return r; } static int -rsgt_vrfy_chkTreeHash(gtfile gf, FILE *sigfp, GTDataHash *hash, gterrctx_t *ectx) +rsgt_vrfy_chkTreeHash(gtfile gf, FILE *sigfp, FILE *nsigfp, + GTDataHash *hash, gterrctx_t *ectx) { int r = 0; - imprint_t *imp; + imprint_t *imp = NULL; - if((r = rsgt_tlvrdTreeHash(sigfp, &imp)) != 0) { + if((r = rsgt_tlvrdTreeHash(sigfp, nsigfp, &imp)) != 0) { reportError(r, ectx); goto done; } @@ -765,22 +853,24 @@ rsgt_vrfy_chkTreeHash(gtfile gf, FILE *sigfp, GTDataHash *hash, gterrctx_t *ectx } r = 0; done: + if(imp != NULL) + rsgt_objfree(0x0901, imp); return r; } int -rsgt_vrfy_nextRec(block_sig_t *bs, gtfile gf, FILE *sigfp, unsigned char *rec, - size_t len, gterrctx_t *ectx) +rsgt_vrfy_nextRec(block_sig_t *bs, gtfile gf, FILE *sigfp, FILE *nsigfp, + unsigned char *rec, size_t len, gterrctx_t *ectx) { int r = 0; GTDataHash *x; /* current hash */ - GTDataHash *m, *recHash, *t; + GTDataHash *m, *recHash = NULL, *t; uint8_t j; hash_m(gf, &m); hash_r(gf, &recHash, rec, len); if(gf->bKeepRecordHashes) { - r = rsgt_vrfy_chkRecHash(gf, sigfp, recHash, ectx); + r = rsgt_vrfy_chkRecHash(gf, sigfp, nsigfp, recHash, ectx); if(r != 0) goto done; } hash_node(gf, &x, m, recHash, 1); /* hash leaf */ @@ -788,7 +878,7 @@ rsgt_vrfy_nextRec(block_sig_t *bs, gtfile gf, FILE *sigfp, unsigned char *rec, ectx->treeLevel = 0; ectx->lefthash = m; ectx->righthash = recHash; - r = rsgt_vrfy_chkTreeHash(gf, sigfp, x, ectx); + r = rsgt_vrfy_chkTreeHash(gf, sigfp, nsigfp, x, ectx); if(r != 0) goto done; } /* add x to the forest as new leaf, update roots list */ @@ -807,7 +897,7 @@ rsgt_vrfy_nextRec(block_sig_t *bs, gtfile gf, FILE *sigfp, unsigned char *rec, gf->roots_valid[j] = 0; if(gf->bKeepTreeHashes) { ectx->lefthash = gf->roots_hash[j]; - r = rsgt_vrfy_chkTreeHash(gf, sigfp, t, ectx); + r = rsgt_vrfy_chkTreeHash(gf, sigfp, nsigfp, t, ectx); if(r != 0) goto done; /* mem leak ok, we terminate! */ } GTDataHash_free(gf->roots_hash[j]); @@ -827,8 +917,9 @@ rsgt_vrfy_nextRec(block_sig_t *bs, gtfile gf, FILE *sigfp, unsigned char *rec, /* cleanup */ /* note: x is freed later as part of roots cleanup */ GTDataHash_free(m); - GTDataHash_free(recHash); done: + if(recHash != NULL) + GTDataHash_free(recHash); return r; } @@ -868,22 +959,94 @@ done: return r; } + +/* helper for rsgt_extendSig: */ +#define COPY_SUBREC_TO_NEWREC \ + memcpy(newrec.data+iWr, subrec.hdr, subrec.lenHdr); \ + iWr += subrec.lenHdr; \ + memcpy(newrec.data+iWr, subrec.data, subrec.tlvlen); \ + iWr += subrec.tlvlen; +static inline int +rsgt_extendSig(GTTimestamp *timestamp, tlvrecord_t *rec, gterrctx_t *ectx) +{ + GTTimestamp *out_timestamp; + uint8_t *der; + size_t lenDer; + int r, rgt; + tlvrecord_t newrec, subrec; + uint16_t iRd, iWr; + + rgt = GTHTTP_extendTimestamp(timestamp, rsgt_extend_puburl, &out_timestamp); + if(rgt != GT_OK) { + ectx->gtstate = rgt; + r = RSGTE_TS_EXTEND; + goto done; + } + r = GTTimestamp_getDEREncoded(out_timestamp, &der, &lenDer); + if(r != GT_OK) { + r = RSGTE_TS_DERENCODE; + ectx->gtstate = rgt; + goto done; + } + /* update block_sig tlv record with new extended timestamp */ + /* we now need to copy all tlv records before the actual der + * encoded part. + */ + iRd = iWr = 0; + // TODO; check tlvtypes at comment places below! + if ((r = rsgt_tlvDecodeSUBREC(rec, &iRd, &subrec)) != 0) goto done; + /* HASH_ALGO */ + COPY_SUBREC_TO_NEWREC + if ((r = rsgt_tlvDecodeSUBREC(rec, &iRd, &subrec)) != 0) goto done; + /* BLOCK_IV */ + COPY_SUBREC_TO_NEWREC + if ((r = rsgt_tlvDecodeSUBREC(rec, &iRd, &subrec)) != 0) goto done; + /* LAST_HASH */ + COPY_SUBREC_TO_NEWREC + if ((r = rsgt_tlvDecodeSUBREC(rec, &iRd, &subrec)) != 0) goto done; + /* REC_COUNT */ + COPY_SUBREC_TO_NEWREC + if ((r = rsgt_tlvDecodeSUBREC(rec, &iRd, &subrec)) != 0) goto done; + /* actual sig! */ + newrec.data[iWr++] = 0x09 | RSGT_FLAG_TLV16; + newrec.data[iWr++] = 0x06; + newrec.data[iWr++] = (lenDer >> 8) & 0xff; + newrec.data[iWr++] = lenDer & 0xff; + /* now we know how large the new main record is */ + newrec.tlvlen = (uint16_t) iWr+lenDer; + newrec.tlvtype = rec->tlvtype; + newrec.hdr[0] = rec->hdr[0]; + newrec.hdr[1] = rec->hdr[1]; + newrec.hdr[2] = (newrec.tlvlen >> 8) & 0xff; + newrec.hdr[3] = newrec.tlvlen & 0xff; + newrec.lenHdr = 4; + memcpy(newrec.data+iWr, der, lenDer); + /* and finally copy back new record to existing one */ + memcpy(rec, &newrec, sizeof(newrec)-sizeof(newrec.data)+newrec.tlvlen+4); + r = 0; +done: + return r; +} + + /* verify the root hash. This also means we need to compute the * Merkle tree root for the current block. */ int -verifyBLOCK_SIG(block_sig_t *bs, gtfile gf, FILE *sigfp, gterrctx_t *ectx) +verifyBLOCK_SIG(block_sig_t *bs, gtfile gf, FILE *sigfp, FILE *nsigfp, + uint8_t bExtend, gterrctx_t *ectx) { int r; int gtstate; - block_sig_t *file_bs; + block_sig_t *file_bs = NULL; GTTimestamp *timestamp = NULL; GTVerificationInfo *vrfyInf; GTDataHash *root = NULL; + tlvrecord_t rec; if((r = verifySigblkFinish(gf, &root)) != 0) goto done; - if((r = rsgt_tlvrdVrfyBlockSig(sigfp, &file_bs)) != 0) + if((r = rsgt_tlvrdVrfyBlockSig(sigfp, &file_bs, &rec)) != 0) goto done; if(ectx->recNum != bs->recCount) { r = RSGTE_INVLD_RECCNT; @@ -907,10 +1070,17 @@ verifyBLOCK_SIG(block_sig_t *bs, gtfile gf, FILE *sigfp, gterrctx_t *ectx) goto done; } - r = 0; if(rsgt_read_showVerified) - reportVerifySuccess(ectx); + reportVerifySuccess(ectx, vrfyInf); + if(bExtend) + if((r = rsgt_extendSig(timestamp, &rec, ectx)) != 0) goto done; + + if(nsigfp != NULL) + if((r = rsgt_tlvwrite(nsigfp, &rec)) != 0) goto done; + r = 0; done: + if(file_bs != NULL) + rsgt_objfree(0x0902, file_bs); if(r != 0) reportError(r, ectx); if(timestamp != NULL) diff --git a/tools/rsgtutil.c b/tools/rsgtutil.c index 9d9f3568..45106c00 100644 --- a/tools/rsgtutil.c +++ b/tools/rsgtutil.c @@ -26,6 +26,7 @@ #include <stdio.h> #include <errno.h> #include <string.h> +#include <unistd.h> #include <gt_base.h> #include <gt_http.h> #include <getopt.h> @@ -35,7 +36,7 @@ typedef unsigned char uchar; static enum { MD_DUMP, MD_DETECT_FILE_TYPE, MD_SHOW_SIGBLK_PARAMS, - MD_VERIFY + MD_VERIFY, MD_EXTEND } mode = MD_DUMP; static int verbose = 0; @@ -44,8 +45,8 @@ dumpFile(char *name) { FILE *fp; uchar hdr[9]; - uint16_t tlvtype, tlvlen; void *obj; + tlvrecord_t rec; int r = -1; if(!strcmp(name, "-")) @@ -60,13 +61,14 @@ dumpFile(char *name) if((r = rsgt_tlvrdHeader(fp, hdr)) != 0) goto err; printf("File Header: '%s'\n", hdr); while(1) { /* we will err out on EOF */ - if((r = rsgt_tlvrd(fp, &tlvtype, &tlvlen, &obj)) != 0) { + if((r = rsgt_tlvrd(fp, &rec, &obj)) != 0) { if(feof(fp)) break; else goto err; } - rsgt_tlvprint(stdout, tlvtype, obj, verbose); + rsgt_tlvprint(stdout, rec.tlvtype, obj, verbose); + rsgt_objfree(rec.tlvtype, obj); } if(fp != stdin) @@ -147,49 +149,62 @@ err: fprintf(stderr, "error %d processing file %s\n", r, name); } static inline int -doVerifyRec(FILE *logfp, FILE *sigfp, block_sig_t *bs, gtfile gf, gterrctx_t *ectx, uint8_t bInBlock) +doVerifyRec(FILE *logfp, FILE *sigfp, FILE *nsigfp, + block_sig_t *bs, gtfile gf, gterrctx_t *ectx, uint8_t bInBlock) { int r; size_t lenRec; - char rec[128*1024]; + char line[128*1024]; - if(fgets(rec, sizeof(rec), logfp) == NULL) { - r = feof(logfp) ? RSGTE_EOF : RSGTE_IO; + if(fgets(line, sizeof(line), logfp) == NULL) { + if(feof(logfp)) { + r = RSGTE_EOF; + } else { + perror("log file input"); + r = RSGTE_IO; + } goto done; } - lenRec = strlen(rec); - if(rec[lenRec-1] == '\n') { - rec[lenRec-1] = '\0'; + lenRec = strlen(line); + if(line[lenRec-1] == '\n') { + line[lenRec-1] = '\0'; --lenRec; - rsgt_errctxSetErrRec(ectx, rec); + rsgt_errctxSetErrRec(ectx, line); } - /* we need to preserve the first record of each block for + /* we need to preserve the first line (record) of each block for * error-reporting purposes (bInBlock==0 meanst start of block) */ if(bInBlock == 0) - rsgt_errctxFrstRecInBlk(ectx, rec); + rsgt_errctxFrstRecInBlk(ectx, line); - r = rsgt_vrfy_nextRec(bs, gf, sigfp, (unsigned char*)rec, lenRec, ectx); + r = rsgt_vrfy_nextRec(bs, gf, sigfp, nsigfp, (unsigned char*)line, lenRec, ectx); done: return r; } -/* note: here we need to have the LOG file name, not signature! */ +/* We handle both verify and extend with the same function as they + * are very similiar. + * + * note: here we need to have the LOG file name, not signature! + */ static void verify(char *name) { - FILE *logfp = NULL, *sigfp = NULL; - block_sig_t *bs; + FILE *logfp = NULL, *sigfp = NULL, *nsigfp = NULL; + block_sig_t *bs = NULL; gtfile gf; uint8_t bHasRecHashes, bHasIntermedHashes; uint8_t bInBlock; int r = 0; char sigfname[4096]; + char oldsigfname[4096]; + char nsigfname[4096]; gterrctx_t ectx; if(!strcmp(name, "-")) { - fprintf(stderr, "verify mode cannot work on stdin\n"); + fprintf(stderr, "%s mode cannot work on stdin\n", + mode == MD_VERIFY ? "verify" : "extend"); goto err; } else { snprintf(sigfname, sizeof(sigfname), "%s.gtsig", name); @@ -199,9 +214,20 @@ verify(char *name) goto err; } if((sigfp = fopen(sigfname, "r")) == NULL) { - perror(name); + perror(sigfname); goto err; } + if(mode == MD_EXTEND) { + snprintf(nsigfname, sizeof(nsigfname), "%s.gtsig.new", name); + nsigfname[sizeof(nsigfname)-1] = '\0'; + if((nsigfp = fopen(nsigfname, "w")) == NULL) { + perror(nsigfname); + goto err; + } + snprintf(oldsigfname, sizeof(oldsigfname), + "%s.gtsig.old", name); + oldsigfname[sizeof(oldsigfname)-1] = '\0'; + } } rsgtInit("rsyslog rsgtutil " VERSION); @@ -210,12 +236,18 @@ verify(char *name) ectx.fp = stderr; ectx.filename = strdup(sigfname); - if((r = rsgt_chkFileHdr(sigfp, "LOGSIG10")) != 0) goto err; - + if((r = rsgt_chkFileHdr(sigfp, "LOGSIG10")) != 0) goto done; + if(mode == MD_EXTEND) { + if(fwrite("LOGSIG10", 8, 1, nsigfp) != 1) { + perror(nsigfname); + r = RSGTE_IO; + goto done; + } + } gf = rsgt_vrfyConstruct_gf(); if(gf == NULL) { fprintf(stderr, "error initializing signature file structure\n"); - goto err; + goto done; } bInBlock = 0; @@ -224,34 +256,84 @@ verify(char *name) while(!feof(logfp)) { if(bInBlock == 0) { + if(bs != NULL) + rsgt_objfree(0x0902, bs); if((r = rsgt_getBlockParams(sigfp, 1, &bs, &bHasRecHashes, &bHasIntermedHashes)) != 0) - goto err; + goto done; rsgt_vrfyBlkInit(gf, bs, bHasRecHashes, bHasIntermedHashes); ectx.recNum = 0; ++ectx.blkNum; } ++ectx.recNum, ++ectx.recNumInFile; - if((r = doVerifyRec(logfp, sigfp, bs, gf, &ectx, bInBlock)) != 0) - goto err; + if((r = doVerifyRec(logfp, sigfp, nsigfp, bs, gf, &ectx, bInBlock)) != 0) + goto done; if(ectx.recNum == bs->recCount) { - verifyBLOCK_SIG(bs, gf, sigfp, &ectx); + if((r = verifyBLOCK_SIG(bs, gf, sigfp, nsigfp, + (mode == MD_EXTEND) ? 1 : 0, &ectx)) != 0) + goto done; bInBlock = 0; } else bInBlock = 1; } - fclose(logfp); - fclose(sigfp); +done: + if(r != RSGTE_EOF) + goto err; + + fclose(logfp); logfp = NULL; + fclose(sigfp); sigfp = NULL; + fclose(nsigfp); nsigfp = NULL; + + /* everything went fine, so we rename files if we updated them */ + if(mode == MD_EXTEND) { + if(unlink(oldsigfname) != 0) { + if(errno != ENOENT) { + perror("unlink oldsig"); + r = RSGTE_IO; + goto err; + } + } + if(link(sigfname, oldsigfname) != 0) { + perror("link oldsig"); + r = RSGTE_IO; + goto err; + } + if(unlink(sigfname) != 0) { + perror("unlink cursig"); + r = RSGTE_IO; + goto err; + } + if(link(nsigfname, sigfname) != 0) { + perror("link newsig"); + fprintf(stderr, "WARNING: current sig file has been " + "renamed to %s - you need to manually recover " + "it.\n", oldsigfname); + r = RSGTE_IO; + goto err; + } + if(unlink(nsigfname) != 0) { + perror("unlink newsig"); + fprintf(stderr, "WARNING: current sig file has been " + "renamed to %s - you need to manually recover " + "it.\n", oldsigfname); + r = RSGTE_IO; + goto err; + } + } rsgtExit(); rsgt_errctxExit(&ectx); return; + err: + fprintf(stderr, "error %d processing file %s\n", r, name); if(logfp != NULL) fclose(logfp); if(sigfp != NULL) fclose(sigfp); - if(r != RSGTE_EOF) - fprintf(stderr, "error %d processing file %s\n", r, name); + if(nsigfp != NULL) { + fclose(nsigfp); + unlink(nsigfname); + } rsgtExit(); rsgt_errctxExit(&ectx); } @@ -270,6 +352,7 @@ processFile(char *name) showSigblkParams(name); break; case MD_VERIFY: + case MD_EXTEND: verify(name); break; } @@ -284,6 +367,7 @@ static struct option long_options[] = {"detect-file-type", no_argument, NULL, 'T'}, {"show-sigblock-params", no_argument, NULL, 'B'}, {"verify", no_argument, NULL, 't'}, /* 't' as in "test signatures" */ + {"extend", no_argument, NULL, 'e'}, {"publications-server", optional_argument, NULL, 'P'}, {"show-verified", no_argument, NULL, 's'}, {NULL, 0, NULL, 0} @@ -324,6 +408,9 @@ main(int argc, char *argv[]) case 't': mode = MD_VERIFY; break; + case 'e': + mode = MD_EXTEND; + break; case '?': break; default:fprintf(stderr, "getopt_long() returns unknown value %d\n", opt); diff --git a/tools/rsgtutil.rst b/tools/rsgtutil.rst index c5782c5a..37958450 100644 --- a/tools/rsgtutil.rst +++ b/tools/rsgtutil.rst @@ -7,7 +7,7 @@ Manage (GuardTime) Signed Log Files ----------------------------------- :Author: Rainer Gerhards <rgerhards@adiscon.com> -:Date: 2013-03-22 +:Date: 2013-03-25 :Manual section: 1 SYNOPSIS @@ -61,6 +61,11 @@ OPTIONS Select verbose mode. Most importantly, hashes and signatures are printed in full length (can be **very** lengthy) rather than the usual abbreviation. +-e, --extend + Select extend mode. This extends the RFC3161 signatures. Note that this + mode also implies a full verification. If there are verify errors, extending + will also fail. + -P <URL>, --publications-server <URL> Sets the publications server. If not set but required by the operation a default server is used. The default server is not necessarily optimal @@ -104,6 +109,28 @@ By default, only errors are printed. To also print successful verifications, use **--show-verified** option. +extend +------ +This extends the RFC3161 signatures. This includes a full verification +of the file. If there are verification errors, extending will also fail. +Note that a signature can only be extended when the required hash has been +published. Currently, these hashes are created at the 15th of each month at +0:00hrs UTC. It takes another few days to get them finally published. As such, +it can be assumed that extending is only possible after this happend (which +means it may take slightly above a month). + +To prevent data corruption, a copy of the signature file is created during +extension. So there must be enough disk space available for both files, +otherwise the operation will fail. If the log file is named logfile, the +signature file is logfile.gtsig and the temporary work file is named +logfile.gtsig.new. When extending finished successfully, the original +signature file (logfile.gtsig in our example) is renamed with the .old +postfix (logfile.gtsig.old) and the temporary file written under the +original name. The .old file can be deleted. It is just kept as a +precaution to prevent signature loss. Note that any already existing +.old or .new files are overwritten by these operations. + + detect-file-type ---------------- This mode is used to detect the type of some well-know files used inside the |