diff options
Diffstat (limited to 'runtime/librsgt_read.c')
-rw-r--r-- | runtime/librsgt_read.c | 231 |
1 files changed, 172 insertions, 59 deletions
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, ×tamp); -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; |