summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--runtime/librsgt.c9
-rw-r--r--runtime/librsgt.h96
-rw-r--r--runtime/librsgt_read.c231
-rw-r--r--runtime/lmsig_gt.c3
-rw-r--r--tools/rsgtutil.c61
5 files changed, 315 insertions, 85 deletions
diff --git a/runtime/librsgt.c b/runtime/librsgt.c
index 20c8fd79..e24c3769 100644
--- a/runtime/librsgt.c
+++ b/runtime/librsgt.c
@@ -325,8 +325,11 @@ writeStateFile(gtfile gf)
memcpy(sf.hdr, "GTSTAT10", 8);
sf.hashID = hashIdentifier(gf->hashAlg);
sf.lenHash = gf->x_prev->digest_length;
- write(fd, &sf, sizeof(sf));
- write(fd, gf->x_prev->digest, gf->x_prev->digest_length);
+ /* if the write fails, we cannot do anything against that. We check
+ * the condition just to keep the compiler happy.
+ */
+ if(write(fd, &sf, sizeof(sf))){};
+ if(write(fd, gf->x_prev->digest, gf->x_prev->digest_length)){};
close(fd);
done: return;
}
@@ -387,7 +390,7 @@ seedIV(gtfile gf)
* will always work...). -- TODO -- rgerhards, 2013-03-06
*/
if((fd = open("/dev/urandom", O_RDONLY)) > 0) {
- read(fd, gf->IV, hashlen);
+ if(read(fd, gf->IV, hashlen)) {}; /* keep compiler happy */
close(fd);
}
}
diff --git a/runtime/librsgt.h b/runtime/librsgt.h
index 26eaf8ee..98384bb9 100644
--- a/runtime/librsgt.h
+++ b/runtime/librsgt.h
@@ -73,10 +73,39 @@ struct gtfile_s {
int tlvIdx; /* current index into tlvBuf */
};
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;
+/* The following structure describes the "error context" to be used
+ * for verification and similiar reader functions. While verifying,
+ * we need some information (like filenames or block numbers) that
+ * is not readily available from the other objects (or not even known
+ * to librsgt). In order to provide meaningful error messages, this
+ * information must be passed in from the external callers. In order
+ * to centralize information (and make it more manageable), we use
+ * ths error context here, which contains everything needed to
+ * generate good error messages. Members of this structure are
+ * maintained both by library users (the callers) as well as
+ * the library itself. Who does what simply depends on who has
+ * the relevant information.
+ */
+struct gterrctx_s {
+ FILE *fp; /**< file for error messages */
+ char *filename;
+ uint8_t verbose;
+ uint64_t recNumInFile;
+ uint64_t recNum;
+ uint64_t blkNum;
+ uint8_t treeLevel;
+ GTDataHash *computedHash;
+ GTDataHash *lefthash, *righthash; /* hashes to display if tree hash fails */
+ imprint_t *fileHash;
+ int gtstate; /* status from last relevant GT.*() function call */
+ char *errRec;
+ char *frstRecInBlk; /* This holds the first message seen inside the current block */
+};
+
struct imprint_s {
uint8_t hashID;
int len;
@@ -115,7 +144,7 @@ struct rsgtstatefile {
#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 */
-#define RSGTE_NO_BLKSIG 6/* block signature record is missing --> invalid block */
+// 6 may be reused!
#define RSGTE_INVLD_RECCNT 7/* mismatch between actual records and records
given in block-sig record */
#define RSGTE_INVLHDR 8/* invalid file header */
@@ -128,6 +157,57 @@ struct rsgtstatefile {
#define RSGTE_INVLD_TREE_HASHID 15 /* invalid tree hash ID (failed verification) */
#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 */
+
+/* the following function maps RSGTE_* state to a string - must be updated
+ * whenever a new state is added.
+ * Note: it is thread-safe to call this function, as it returns a pointer
+ * into constant memory pool.
+ */
+static inline char *
+RSGTE2String(int err)
+{
+ switch(err) {
+ case 0:
+ return "success";
+ case RSGTE_IO:
+ return "i/o error";
+ case RSGTE_FMT:
+ return "data format error";
+ case RSGTE_INVLTYP:
+ return "invalid/unexpected tlv record type";
+ case RSGTE_OOM:
+ return "out of memory";
+ case RSGTE_LEN:
+ return "length record problem";
+ case RSGTE_INVLD_RECCNT:
+ return "mismatch between actual record count and number in block signature record";
+ case RSGTE_INVLHDR:
+ return "invalid file header";
+ case RSGTE_EOF:
+ return "EOF";
+ case RSGTE_MISS_REC_HASH:
+ return "record hash missing";
+ case RSGTE_MISS_TREE_HASH:
+ return "tree hash missing";
+ case RSGTE_INVLD_REC_HASH:
+ return "record hash mismatch";
+ case RSGTE_INVLD_TREE_HASH:
+ return "tree hash mismatch";
+ case RSGTE_INVLD_REC_HASHID:
+ return "invalid record hash ID";
+ case RSGTE_INVLD_TREE_HASHID:
+ return "invalid tree hash ID";
+ case RSGTE_MISS_BLOCKSIG:
+ return "missing block signature record";
+ case RSGTE_INVLD_TIMESTAMP:
+ return "RFC3161 timestamp invalid";
+ case RSGTE_TS_DERDECODE:
+ return "error DER-decoding RFC3161 timestamp";
+ default:
+ return "unknown error";
+ }
+}
static inline uint16_t
@@ -263,11 +343,19 @@ int rsgt_getBlockParams(FILE *fp, uint8_t bRewind, block_sig_t **bs, uint8_t *bH
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);
-int verifyBLOCK_SIG(block_sig_t *bs, gtfile gf, FILE *sigfp, uint64_t nRecs);
+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);
+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);
+
/* TODO: replace these? */
void hash_m(gtfile gf, GTDataHash **m);
void hash_r(gtfile gf, GTDataHash **r, const unsigned char *rec, const size_t len);
void hash_node(gtfile gf, GTDataHash **node, GTDataHash *m, GTDataHash *r, uint8_t level);
+extern char *rsgt_read_puburl; /**< url of publication server */
+extern uint8_t rsgt_read_showVerified;
+
#endif /* #ifndef INCLUDED_LIBRSGT_H */
diff --git a/runtime/librsgt_read.c b/runtime/librsgt_read.c
index d756c336..e32ae454 100644
--- a/runtime/librsgt_read.c
+++ b/runtime/librsgt_read.c
@@ -48,6 +48,8 @@ typedef unsigned char uchar;
#define MAXFNAME 1024
static int rsgt_read_debug = 0;
+char *rsgt_read_puburl = "http://verify.guardtime.com/gt-controlpublications.bin";
+uint8_t rsgt_read_showVerified = 0;
/* macro to obtain next char from file including error tracking */
#define NEXTC if((c = fgetc(fp)) == EOF) { \
@@ -58,6 +60,130 @@ static int rsgt_read_debug = 0;
/* check return state of operation and abort, if non-OK */
#define CHKr(code) if((r = code) != 0) goto done
+
+/* if verbose==0, only the first and last two octets are shown,
+ * otherwise everything.
+ */
+static void
+outputHexBlob(FILE *fp, uint8_t *blob, uint16_t len, uint8_t verbose)
+{
+ unsigned i;
+ if(verbose || len <= 8) {
+ for(i = 0 ; i < len ; ++i)
+ fprintf(fp, "%2.2x", blob[i]);
+ } else {
+ fprintf(fp, "%2.2x%2.2x%2.2x[...]%2.2x%2.2x%2.2x",
+ blob[0], blob[1], blob[2],
+ blob[len-3], blob[len-2], blob[len-1]);
+ }
+}
+
+static inline void
+outputHash(FILE *fp, char *hdr, uint8_t *data, uint16_t len, uint8_t verbose)
+{
+ fprintf(fp, "%s", hdr);
+ outputHexBlob(fp, data, len, verbose);
+ fputc('\n', fp);
+}
+
+void
+rsgt_errctxInit(gterrctx_t *ectx)
+{
+ ectx->fp = NULL;
+ ectx->filename = NULL;
+ ectx->recNum = 0;
+ ectx->recNumInFile = 0;
+ ectx->blkNum = 0;
+ ectx->verbose = 0;
+ ectx->errRec = NULL;
+ ectx->frstRecInBlk = NULL;
+}
+void
+rsgt_errctxExit(gterrctx_t *ectx)
+{
+ free(ectx->filename);
+ free(ectx->frstRecInBlk);
+}
+
+/* note: we do not copy the record, so the caller MUST not destruct
+ * it before processing of the record is completed. To remove the
+ * current record without setting a new one, call this function
+ * with rec==NULL.
+ */
+void
+rsgt_errctxSetErrRec(gterrctx_t *ectx, char *rec)
+{
+ ectx->errRec = strdup(rec);
+}
+/* This stores the block's first record. Here we copy the data,
+ * as the caller will usually not preserve it long enough.
+ */
+void
+rsgt_errctxFrstRecInBlk(gterrctx_t *ectx, char *rec)
+{
+ free(ectx->frstRecInBlk);
+ ectx->frstRecInBlk = strdup(rec);
+}
+
+static void
+reportError(int errcode, gterrctx_t *ectx)
+{
+ if(ectx->fp != NULL) {
+ fprintf(ectx->fp, "%s[%llu:%llu:%llu]: error[%u]: %s\n",
+ ectx->filename,
+ (long long unsigned) ectx->blkNum, (long long unsigned) ectx->recNum,
+ (long long unsigned) ectx->recNumInFile,
+ errcode, RSGTE2String(errcode));
+ if(ectx->frstRecInBlk != NULL)
+ fprintf(ectx->fp, "\tBlock Start Record.: '%s'\n", ectx->frstRecInBlk);
+ if(ectx->errRec != NULL)
+ fprintf(ectx->fp, "\tRecord in Question.: '%s'\n", ectx->errRec);
+ if(ectx->computedHash != NULL) {
+ outputHash(ectx->fp, "\tComputed Hash......: ", ectx->computedHash->digest,
+ ectx->computedHash->digest_length, ectx->verbose);
+ }
+ if(ectx->fileHash != NULL) {
+ outputHash(ectx->fp, "\tSignature File Hash: ", ectx->fileHash->data,
+ ectx->fileHash->len, ectx->verbose);
+ }
+ if(errcode == RSGTE_INVLD_TREE_HASH ||
+ errcode == RSGTE_INVLD_TREE_HASHID) {
+ fprintf(ectx->fp, "\tTree Level.........: %d\n", (int) ectx->treeLevel);
+ outputHash(ectx->fp, "\tTree Left Hash.....: ", ectx->lefthash->digest,
+ ectx->lefthash->digest_length, ectx->verbose);
+ outputHash(ectx->fp, "\tTree Right Hash....: ", ectx->righthash->digest,
+ ectx->righthash->digest_length, ectx->verbose);
+ }
+ if(errcode == RSGTE_INVLD_TIMESTAMP ||
+ errcode == RSGTE_TS_DERDECODE) {
+ fprintf(ectx->fp, "\tPublication Server.: %s\n", rsgt_read_puburl);
+ fprintf(ectx->fp, "\tGT Verify Timestamp: [%u]%s\n",
+ ectx->gtstate, GTHTTP_getErrorString(ectx->gtstate));
+ }
+ }
+}
+
+/* obviously, this is not an error-reporting function. We still use
+ * ectx, as it has most information we need.
+ */
+static void
+reportVerifySuccess(gterrctx_t *ectx)
+{
+ if(ectx->fp != NULL) {
+ fprintf(ectx->fp, "%s[%llu:%llu:%llu]: block signature successfully verified\n",
+ ectx->filename,
+ (long long unsigned) ectx->blkNum, (long long unsigned) ectx->recNum,
+ (long long unsigned) ectx->recNumInFile);
+ if(ectx->frstRecInBlk != NULL)
+ fprintf(ectx->fp, "\tBlock Start Record.: '%s'\n", ectx->frstRecInBlk);
+ if(ectx->errRec != NULL)
+ 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));
+ }
+}
+
+
/**
* Read a header from a binary file.
* @param[in] fp file pointer for processing
@@ -239,7 +365,6 @@ rsgt_tlvrdBLOCK_SIG(FILE *fp, block_sig_t **blocksig, uint16_t tlvlen)
2 + lenInt /* rec-count */ +
4 + bs->sig.der.len /* rfc-3161 */;
if(sizeRead != tlvlen) {
- printf("length record error!\n");
r = RSGTE_LEN;
goto done;
}
@@ -285,7 +410,6 @@ rsgt_tlvrdRecHash(FILE *fp, imprint_t **imp)
uint16_t tlvtype, tlvlen;
if((r = rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)) != 0) goto done;
-printf("read tlvtype %4.4x\n", tlvtype);
if(tlvtype != 0x0900) {
r = RSGTE_MISS_REC_HASH;
goto done;
@@ -302,7 +426,6 @@ rsgt_tlvrdTreeHash(FILE *fp, imprint_t **imp)
uint16_t tlvtype, tlvlen;
if((r = rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)) != 0) goto done;
-printf("read tlvtype %4.4x\n", tlvtype);
if(tlvtype != 0x0901) {
r = RSGTE_MISS_TREE_HASH;
goto done;
@@ -320,7 +443,6 @@ rsgt_tlvrdVrfyBlockSig(FILE *fp, block_sig_t **bs)
uint16_t tlvtype, tlvlen;
if((r = rsgt_tlvrdTL(fp, &tlvtype, &tlvlen)) != 0) goto done;
-printf("read tlvtype %4.4x\n", tlvtype);
if(tlvtype != 0x0902) {
r = RSGTE_MISS_BLOCKSIG;
goto done;
@@ -372,24 +494,6 @@ rsgt_tlvrd(FILE *fp, uint16_t *tlvtype, uint16_t *tlvlen, void *obj)
done: return r;
}
-
-/* if verbose==0, only the first and last two octets are shown,
- * otherwise everything.
- */
-static void
-outputHexBlob(FILE *fp, uint8_t *blob, uint16_t len, uint8_t verbose)
-{
- unsigned i;
- if(verbose || len <= 6) {
- for(i = 0 ; i < len ; ++i)
- fprintf(fp, "%2.2x", blob[i]);
- } else {
- fprintf(fp, "%2.2x%2.2x[...]%2.2x%2.2x",
- blob[0], blob[1],
- blob[len-2], blob[len-1]);
- }
-}
-
/* return if a blob is all zero */
static inline int
blobIsZero(uint8_t *blob, uint16_t len)
@@ -412,14 +516,14 @@ rsgt_printIMPRINT(FILE *fp, char *name, imprint_t *imp, uint8_t verbose)
static void
rsgt_printREC_HASH(FILE *fp, imprint_t *imp, uint8_t verbose)
{
- rsgt_printIMPRINT(fp, "[0x0900]Record hash................: ",
+ rsgt_printIMPRINT(fp, "[0x0900]Record hash: ",
imp, verbose);
}
static void
rsgt_printINT_HASH(FILE *fp, imprint_t *imp, uint8_t verbose)
{
- rsgt_printIMPRINT(fp, "[0x0901]Intermediate aggregate hash: ",
+ rsgt_printIMPRINT(fp, "[0x0901]Tree hash..: ",
imp, verbose);
}
@@ -608,20 +712,26 @@ 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)
+rsgt_vrfy_chkRecHash(gtfile gf, FILE *sigfp, GTDataHash *recHash, gterrctx_t *ectx)
{
int r = 0;
imprint_t *imp;
if((r = rsgt_tlvrdRecHash(sigfp, &imp)) != 0)
+ reportError(r, ectx);
goto done;
if(imp->hashID != hashIdentifier(gf->hashAlg)) {
+ reportError(r, ectx);
r = RSGTE_INVLD_REC_HASHID;
goto done;
}
if(memcmp(imp->data, recHash->digest,
hashOutputLengthOctets(imp->hashID))) {
r = RSGTE_INVLD_REC_HASH;
+ ectx->computedHash = recHash;
+ ectx->fileHash = imp;
+ reportError(r, ectx);
+ ectx->computedHash = NULL, ectx->fileHash = NULL;
goto done;
}
r = 0;
@@ -630,38 +740,37 @@ done:
}
static int
-rsgt_vrfy_chkTreeHash(gtfile gf, FILE *sigfp, GTDataHash *hash)
+rsgt_vrfy_chkTreeHash(gtfile gf, FILE *sigfp, GTDataHash *hash, gterrctx_t *ectx)
{
int r = 0;
imprint_t *imp;
- if((r = rsgt_tlvrdTreeHash(sigfp, &imp)) != 0)
+ if((r = rsgt_tlvrdTreeHash(sigfp, &imp)) != 0) {
+ reportError(r, ectx);
goto done;
+ }
if(imp->hashID != hashIdentifier(gf->hashAlg)) {
+ reportError(r, ectx);
r = RSGTE_INVLD_TREE_HASHID;
goto done;
}
-//printf("imp hash:");
-//outputHexBlob(stdout, imp->data, hashOutputLengthOctets(imp->hashID), 1);
-//printf("\ntree hash:");
-//outputHexBlob(stdout, hash->digest, hashOutputLengthOctets(imp->hashID), 1);
-//printf("\nlenBlkStrtHAsh %d\nblkstrt hash:", gf->lenBlkStrtHash);
-//outputHexBlob(stdout, gf->blkStrtHash, gf->lenBlkStrtHash, 1);
-//printf("\n");
if(memcmp(imp->data, hash->digest,
hashOutputLengthOctets(imp->hashID))) {
r = RSGTE_INVLD_TREE_HASH;
+ ectx->computedHash = hash;
+ ectx->fileHash = imp;
+ reportError(r, ectx);
+ ectx->computedHash = NULL, ectx->fileHash = NULL;
goto done;
}
r = 0;
-printf("Tree hash OK\n");
done:
return r;
}
int
rsgt_vrfy_nextRec(block_sig_t *bs, gtfile gf, FILE *sigfp, unsigned char *rec,
- size_t len)
+ size_t len, gterrctx_t *ectx)
{
int r = 0;
GTDataHash *x; /* current hash */
@@ -671,13 +780,15 @@ rsgt_vrfy_nextRec(block_sig_t *bs, gtfile gf, FILE *sigfp, unsigned char *rec,
hash_m(gf, &m);
hash_r(gf, &recHash, rec, len);
if(gf->bKeepRecordHashes) {
- r = rsgt_vrfy_chkRecHash(gf, sigfp, recHash);
+ r = rsgt_vrfy_chkRecHash(gf, sigfp, recHash, ectx);
if(r != 0) goto done;
}
hash_node(gf, &x, m, recHash, 1); /* hash leaf */
- /* persists x here if Merkle tree needs to be persisted! */
if(gf->bKeepTreeHashes) {
- r = rsgt_vrfy_chkTreeHash(gf, sigfp, x);
+ ectx->treeLevel = 0;
+ ectx->lefthash = m;
+ ectx->righthash = recHash;
+ r = rsgt_vrfy_chkTreeHash(gf, sigfp, x, ectx);
if(r != 0) goto done;
}
/* add x to the forest as new leaf, update roots list */
@@ -690,14 +801,16 @@ rsgt_vrfy_nextRec(block_sig_t *bs, gtfile gf, FILE *sigfp, unsigned char *rec,
break;
} else if(t != NULL) {
/* hash interim node */
+ ectx->treeLevel = j+1;
+ ectx->righthash = t;
hash_node(gf, &t, gf->roots_hash[j], t, j+2);
gf->roots_valid[j] = 0;
- GTDataHash_free(gf->roots_hash[j]);
- // TODO: check if this is correct location (paper!)
if(gf->bKeepTreeHashes) {
- r = rsgt_vrfy_chkTreeHash(gf, sigfp, t);
- if(r != 0) goto done;
+ ectx->lefthash = gf->roots_hash[j];
+ r = rsgt_vrfy_chkTreeHash(gf, sigfp, t, ectx);
+ if(r != 0) goto done; /* mem leak ok, we terminate! */
}
+ GTDataHash_free(gf->roots_hash[j]);
}
}
if(t != NULL) {
@@ -749,11 +862,6 @@ verifySigblkFinish(gtfile gf, GTDataHash **pRoot)
free(gf->blkStrtHash);
gf->blkStrtHash = NULL;
*pRoot = root;
- // We do not need the following as we take this from the block params
- // (but I leave it in in order to aid getting to common code)
- //gf->lenBlkStrtHash = gf->x_prev->digest_length;
- //gf->blkStrtHash = malloc(gf->lenBlkStrtHash);
- //memcpy(gf->blkStrtHash, gf->x_prev->digest, gf->lenBlkStrtHash);
r = 0;
done:
gf->bInBlk = 0;
@@ -764,7 +872,7 @@ done:
* Merkle tree root for the current block.
*/
int
-verifyBLOCK_SIG(block_sig_t *bs, gtfile gf, FILE *sigfp, uint64_t nRecs)
+verifyBLOCK_SIG(block_sig_t *bs, gtfile gf, FILE *sigfp, gterrctx_t *ectx)
{
int r;
int gtstate;
@@ -777,29 +885,34 @@ verifyBLOCK_SIG(block_sig_t *bs, gtfile gf, FILE *sigfp, uint64_t nRecs)
goto done;
if((r = rsgt_tlvrdVrfyBlockSig(sigfp, &file_bs)) != 0)
goto done;
-printf("got sig block, now doing checks \n");
- if(nRecs != bs->recCount) {
+ if(ectx->recNum != bs->recCount) {
r = RSGTE_INVLD_RECCNT;
goto done;
}
-printf("len DER timestamp: %d, data %p\n", (int) file_bs->sig.der.len, file_bs->sig.der.data);
gtstate = GTTimestamp_DERDecode(file_bs->sig.der.data,
file_bs->sig.der.len, &timestamp);
-printf("result of GTTimestamp_DERDecode: %d\n", gtstate);
+ if(gtstate != GT_OK) {
+ r = RSGTE_TS_DERDECODE;
+ ectx->gtstate = gtstate;
+ goto done;
+ }
+
gtstate = GTHTTP_verifyTimestampHash(timestamp, root, NULL,
- NULL, NULL,
- "http://verify.guardtime.com/gt-controlpublications.bin",
- 0, &vrfyInf);
-printf("result of HTTP_vrfy: %d: %s\n", gtstate, GTHTTP_getErrorString(gtstate));
+ NULL, NULL, rsgt_read_puburl, 0, &vrfyInf);
if(! (gtstate == GT_OK
&& vrfyInf->verification_errors == GT_NO_FAILURES) ) {
- r = RSGTE_INVLD_TIMESTAMP; goto done;
+ r = RSGTE_INVLD_TIMESTAMP;
+ ectx->gtstate = gtstate;
+ goto done;
}
-printf("root timestamp OK\n");
r = 0;
+ if(rsgt_read_showVerified)
+ reportVerifySuccess(ectx);
done:
+ if(r != 0)
+ reportError(r, ectx);
if(timestamp != NULL)
GTTimestamp_free(timestamp);
return r;
diff --git a/runtime/lmsig_gt.c b/runtime/lmsig_gt.c
index 54a795a1..d61f3a86 100644
--- a/runtime/lmsig_gt.c
+++ b/runtime/lmsig_gt.c
@@ -118,9 +118,10 @@ SetCnfParam(void *pT, struct nvlst *lst)
static rsRetVal
-OnFileOpen(void *pT, uchar *fn, gtfile *pgf)
+OnFileOpen(void *pT, uchar *fn, void *pGF)
{
lmsig_gt_t *pThis = (lmsig_gt_t*) pT;
+ gtfile *pgf = (gtfile*) pGF;
DEFiRet;
dbgprintf("DDDD: onFileOpen: %s\n", fn);
diff --git a/tools/rsgtutil.c b/tools/rsgtutil.c
index 0ccfcd7b..d9cce2f7 100644
--- a/tools/rsgtutil.c
+++ b/tools/rsgtutil.c
@@ -101,9 +101,9 @@ showSigblkParams(char *name)
++blkCnt;
rsgt_printBLOCK_SIG(stdout, bs, verbose);
printf("\t***META INFORMATION:\n");
- printf("\tBlock Nbr in File......: %llu\n", blkCnt);
- printf("\tHas Record Hashes......: %d\n", bHasRecHashes);
- printf("\tHas Intermediate Hashes: %d\n", bHasIntermedHashes);
+ printf("\tBlock Nbr in File...: %llu\n", blkCnt);
+ printf("\tHas Record Hashes...: %d\n", bHasRecHashes);
+ printf("\tHas Tree Hashes.....: %d\n", bHasIntermedHashes);
}
if(fp != stdin)
@@ -145,7 +145,7 @@ 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)
+doVerifyRec(FILE *logfp, FILE *sigfp, block_sig_t *bs, gtfile gf, gterrctx_t *ectx, uint8_t bInBlock)
{
int r;
size_t lenRec;
@@ -156,10 +156,19 @@ doVerifyRec(FILE *logfp, FILE *sigfp, block_sig_t *bs, gtfile gf)
goto done;
}
lenRec = strlen(rec);
- if(rec[lenRec-1] == '\n')
+ if(rec[lenRec-1] == '\n') {
+ rec[lenRec-1] = '\0';
--lenRec;
+ rsgt_errctxSetErrRec(ectx, rec);
+ }
+
+ /* we need to preserve the first record of each block for
+ * error-reporting purposes (bInBlock==0 meanst start of block)
+ */
+ if(bInBlock == 0)
+ rsgt_errctxFrstRecInBlk(ectx, rec);
- r = rsgt_vrfy_nextRec(bs, gf, sigfp, (unsigned char*)rec, lenRec);
+ r = rsgt_vrfy_nextRec(bs, gf, sigfp, (unsigned char*)rec, lenRec, ectx);
done:
return r;
}
@@ -174,8 +183,8 @@ verify(char *name)
uint8_t bHasRecHashes, bHasIntermedHashes;
uint8_t bInBlock;
int r = 0;
- uint64_t nRecs;
char sigfname[4096];
+ gterrctx_t ectx;
if(!strcmp(name, "-")) {
fprintf(stderr, "verify mode cannot work on stdin\n");
@@ -194,6 +203,10 @@ verify(char *name)
}
rsgtInit("rsyslog rsgtutil " VERSION);
+ rsgt_errctxInit(&ectx);
+ ectx.verbose = verbose;
+ ectx.fp = stderr;
+ ectx.filename = strdup(sigfname);
if((r = rsgt_chkFileHdr(sigfp, "LOGSIG10")) != 0) goto err;
@@ -204,28 +217,31 @@ verify(char *name)
}
bInBlock = 0;
+ ectx.blkNum = 0;
+ ectx.recNumInFile = 0;
while(!feof(logfp)) {
if(bInBlock == 0) {
if((r = rsgt_getBlockParams(sigfp, 1, &bs, &bHasRecHashes,
&bHasIntermedHashes)) != 0)
goto err;
- rsgt_vrfyBlkInit(gf, bs, bHasRecHashes,
- bHasIntermedHashes);
- nRecs = 0;
- bInBlock = 1;
+ rsgt_vrfyBlkInit(gf, bs, bHasRecHashes, bHasIntermedHashes);
+ ectx.recNum = 0;
+ ++ectx.blkNum;
}
- ++nRecs;
- if((r = doVerifyRec(logfp, sigfp, bs, gf)) != 0)
+ ++ectx.recNum, ++ectx.recNumInFile;
+ if((r = doVerifyRec(logfp, sigfp, bs, gf, &ectx, bInBlock)) != 0)
goto err;
- if(nRecs == bs->recCount) {
- verifyBLOCK_SIG(bs, gf, sigfp, nRecs);
+ if(ectx.recNum == bs->recCount) {
+ verifyBLOCK_SIG(bs, gf, sigfp, &ectx);
bInBlock = 0;
- }
+ } else bInBlock = 1;
}
fclose(logfp);
fclose(sigfp);
+ rsgtExit();
+ rsgt_errctxExit(&ectx);
return;
err:
if(logfp != NULL)
@@ -233,8 +249,9 @@ err:
if(sigfp != NULL)
fclose(sigfp);
if(r != RSGTE_EOF)
- fprintf(stderr, "error %d processing file %s [%s]\n", r, name, sigfname);
+ fprintf(stderr, "error %d processing file %s\n", r, name);
rsgtExit();
+ rsgt_errctxExit(&ectx);
}
static void
@@ -265,6 +282,8 @@ 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" */
+ {"publications-server", optional_argument, NULL, 'P'},
+ {"show-verified", no_argument, NULL, 's'},
{NULL, 0, NULL, 0}
};
@@ -275,13 +294,16 @@ main(int argc, char *argv[])
int opt;
while(1) {
- opt = getopt_long(argc, argv, "v", long_options, NULL);
+ opt = getopt_long(argc, argv, "DvVTBtPs", long_options, NULL);
if(opt == -1)
break;
switch(opt) {
case 'v':
verbose = 1;
break;
+ case 's':
+ rsgt_read_showVerified = 1;
+ break;
case 'V':
fprintf(stderr, "rsgtutil " VERSION "\n");
exit(0);
@@ -291,6 +313,9 @@ main(int argc, char *argv[])
case 'B':
mode = MD_SHOW_SIGBLK_PARAMS;
break;
+ case 'P':
+ rsgt_read_puburl = optarg;
+ break;
case 'T':
mode = MD_DETECT_FILE_TYPE;
break;