/* VERIFY Function using KSI API * 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 int verifyKSI(char *name, char *errbuf, char *sigfname, char *oldsigfname, char *nsigfname, FILE *logfp, FILE *sigfp, FILE *nsigfp) { block_sig_t *bs = NULL; block_hdr_t *bh = NULL; ksifile ksi; uint8_t bHasRecHashes, bHasIntermedHashes; uint8_t bInBlock; int r = 0; int bInitDone = 0; ksierrctx_t ectx; rsksi_errctxInit(&ectx); rsksiInit("rsyslog rsksiutil " VERSION); bInitDone = 1; ectx.verbose = verbose; ectx.fp = stderr; ectx.filename = strdup(sigfname); if((r = rsksi_chkFileHdr(sigfp, "LOGSIG11")) != 0) { if (debug) fprintf(stderr, "error %d in rsksi_chkFileHdr\n", r); goto done; } if(mode == MD_EXTEND) { if(fwrite("LOGSIG11", 8, 1, nsigfp) != 1) { perror(nsigfname); r = RSGTE_IO; goto done; } } ksi = rsksi_vrfyConstruct_gf(); if(ksi == NULL) { fprintf(stderr, "error initializing signature file structure\n"); goto done; } bInBlock = 0; ectx.blkNum = 0; ectx.recNumInFile = 0; while(!feof(logfp)) { if(bInBlock == 0) { if(bs != NULL) rsksi_objfree(0x0904, bs); if (bh != NULL) rsksi_objfree(0x0901, bh); if((r = rsksi_getBlockParams(sigfp, 1, &bs, &bh, &bHasRecHashes, &bHasIntermedHashes)) != 0) { if(ectx.blkNum == 0) { fprintf(stderr, "Error %d before finding any signature block - " "is the file still open and being written to?\n", r); } else { if(verbose) fprintf(stderr, "EOF after signature block %lld\n", (long long unsigned) ectx.blkNum); } goto done; } /* Copy block header */ if ((r = verifyBLOCK_HDRKSI(sigfp, nsigfp)) != 0) goto done; rsksi_vrfyBlkInit(ksi, bh, bHasRecHashes, bHasIntermedHashes); ectx.recNum = 0; ++ectx.blkNum; } ++ectx.recNum, ++ectx.recNumInFile; if((r = doVerifyRecKSI(logfp, sigfp, nsigfp, /*bs,*/ ksi, &ectx, bInBlock)) != 0) goto done; if(ectx.recNum == bs->recCount) { if((r = verifyBLOCK_SIGKSI(bs, ksi, sigfp, nsigfp, (mode == MD_EXTEND) ? 1 : 0, &ectx)) != 0) goto done; bInBlock = 0; } else bInBlock = 1; } done: if(r != RSGTE_EOF) goto err; /* Make sure we've reached the end of file in both log and signature file */ if (fgetc(logfp) != EOF) { fprintf(stderr, "There are unsigned records in the end of log.\n"); fprintf(stderr, "Last signed record: %s\n", ectx.errRec); r = RSGTE_END_OF_SIG; goto err; } if (fgetc(sigfp) != EOF) { fprintf(stderr, "There are records missing from the end of the log file.\n"); r = RSGTE_END_OF_LOG; goto err; } fclose(logfp); logfp = NULL; fclose(sigfp); sigfp = NULL; if(nsigfp != 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; } } /* OLDCODE rsksiExit();*/ rsksi_errctxExit(&ectx); return 1; err: if(r != 0) sprintf(errbuf, "error %d (%s) processing file %s\n", r, RSKSIE2String(r), name); else errbuf[0] = '\0'; if(logfp != NULL) fclose(logfp); if(sigfp != NULL) fclose(sigfp); if(nsigfp != NULL) { fclose(nsigfp); unlink(nsigfname); } if(bInitDone) { /* OLDCODE rsksiExit();*/ rsksi_errctxExit(&ectx); } return 0; }
/* VERIFY Function using KSI API * 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 int verifyKSI(char *name, char *errbuf, char *sigfname, char *oldsigfname, char *nsigfname, FILE *logfp, FILE *sigfp, FILE *nsigfp) { int FILEMODE = FILEMODE_LOGSIG; /* Default FileMode */ block_sig_t *bs = NULL; block_hdr_t *bh = NULL; ksifile ksi = NULL; uint8_t bHasRecHashes, bHasIntermedHashes; uint8_t bInBlock; int r = 0; int bInitDone = 0; tlvrecord_t tlvrec; ksierrctx_t ectx; /* Helpers for extract verify */ int iCurrentLine = 0; int iMaxLine = 0; char* lineRec = NULL; size_t stlen = 0; ssize_t ssread; /* Init KSI related variables */ rsksi_errctxInit(&ectx); rsksiInit("rsyslog rsksiutil " VERSION); bInitDone = 1; ectx.verbose = verbose; ectx.fp = stderr; ectx.filename = strdup(sigfname); ksi = rsksi_vrfyConstruct_gf(); if(ksi == NULL) { fprintf(stderr, "verifyKSI:\t\t\t Error initializing signature file structure\n"); goto done; } /* Check if we have a logsignature file */ if((r = rsksi_chkFileHdr(sigfp, "LOGSIG11", 0)) == 0) { /* Verify Log signature */ if(debug) printf("debug: verifyKSI:\t\t\t Found log signature file ... \n"); if(mode == MD_EXTEND) { if(fwrite("LOGSIG11", 8, 1, nsigfp) != 1) { perror(nsigfname); r = RSGTE_IO; goto done; } } bInBlock = 0; ectx.blkNum = 0; ectx.recNumInFile = 0; while(!feof(logfp)) { if(bInBlock == 0) { if (bs != NULL) rsksi_objfree(0x0904, bs); if (bh != NULL) rsksi_objfree(0x0901, bh); if((r = rsksi_getBlockParams(ksi, sigfp, 1, &bs, &bh, &bHasRecHashes, &bHasIntermedHashes)) != 0) { if(ectx.blkNum == 0) { fprintf(stderr, "verifyKSI:\t\t\t Error %d before finding any signature block - is the file still open and being written to?\n", r); } else { if(verbose) fprintf(stderr, "verifyKSI:\t\t\t EOF after signature block %lld\n", (long long unsigned) ectx.blkNum); } goto done; } /* Copy block header */ if ((r = verifyBLOCK_HDRKSI(ksi, sigfp, nsigfp, &tlvrec)) != 0) goto done; rsksi_vrfyBlkInit(ksi, bh, bHasRecHashes, bHasIntermedHashes); ectx.recNum = 0; ++ectx.blkNum; } ++ectx.recNum, ++ectx.recNumInFile; if((r = doVerifyRecKSI(logfp, sigfp, nsigfp, ksi, &ectx, bInBlock)) != 0) goto done; if(ectx.recNum == bs->recCount) { /* And Verify Block signature */ if((r = verifyBLOCK_SIGKSI(bs, ksi, sigfp, nsigfp, (mode == MD_EXTEND) ? 1 : 0, NULL, &ectx)) != 0) goto done; bInBlock = 0; } else bInBlock = 1; } } else if((r = rsksi_chkFileHdr(sigfp, "RECSIG11", verbose)) == 0) { /* Verify Log Excerpts */ if(debug) printf("verifyKSI:\t\t\t Found record integrity proof file ... \n"); FILEMODE = FILEMODE_RECSIG; ectx.blkNum = 0; ectx.recNumInFile = 0; while( !feof(logfp) && !feof(sigfp)) { /* Free memory */ if (bs != NULL) rsksi_objfree(0x0905, bs); if (bh != NULL) rsksi_objfree(0x0901, bh); /* Get/Verify Block Paramaters */ if((r = rsksi_getExcerptBlockParams(ksi, sigfp, 1, &bs, &bh)) != 0) { if(ectx.blkNum == 0) { fprintf(stderr, "verifyKSI:\t\t\t Error %d before finding any signature block\n", r); } else { if(verbose) fprintf(stderr, "verifyKSI:\t\t\t EOF after signature block %lld\n", (long long unsigned) ectx.blkNum); } goto done; } ectx.recNum = 0; ++ectx.blkNum; // NEEDED ??? ++ectx.recNum, ++ectx.recNumInFile; /* Verify if records were found */ if (bs->recCount <= 0) { r = RSGTE_INVLD_RECCNT; if(verbose) fprintf(stderr, "verifyKSI:\t\t\t Either signature block or hash chains are missing.\n"); goto done; } /* Init Minimal KSI Helper */ rsksi_vrfyBlkInit(ksi, bh, 1, 0); if(debug) printf("debug: verifyKSI:\t\t\t Verifying %lld hashchains ... \n", (long long unsigned) bs->recCount); /* Set new MAXLINE */ iMaxLine = iCurrentLine + bs->recCount; do { if (debug) printf("debug: verifyKSI:\t\t\t NEXT IN LOOP .\n"); /* Free memory from last lineRec first*/ if (lineRec != NULL) { free(lineRec); lineRec = NULL; } /* Get next line from file! */ ssread = getline(&lineRec, &stlen, logfp); if (ssread != -1) { iCurrentLine++; /* Increment Current Line */ /* Remove Linefeed for verification */ if( *(lineRec+ssread-1) == '\n') { *(lineRec+ssread-1) = '\0'; --ssread; rsksi_errctxSetErrRec(&ectx, lineRec); } } else { /* END of file reached */ if (debug) printf("debug: verifyKSI:\t\t\t End of file reached.\n"); r = RSGTE_EOF; break; } /* we need to preserve the first line (record) of each block for error-reporting purposes */ rsksi_errctxFrstRecInBlk(&ectx, lineRec); if (debug) printf("debug: verifyKSI:\t\t\t Processing line '%d': %.64s... \n", iCurrentLine, lineRec); /* Verify logline record against hash chain */ if ((r = rsksi_vrfy_nextHashChain(ksi, bs, sigfp, (unsigned char*)lineRec, ssread, &ectx)) != RSGTE_SUCCESS) { fprintf(stderr, "verifyKSI:\t\t\t error %d while verifiying hash chain record for logline (%d): '%.64s...'\n", r, iCurrentLine, lineRec); goto done; } } while (iCurrentLine > iMaxLine && r != RSGTE_EOF); if (debug) printf("debug: verifyKSI:\t\t\t DONE with LOOP iCurrentLine=%d > iMaxLine=%d r=%d\n", iCurrentLine, iMaxLine, r); } } else { fprintf(stderr, "verifyKSI:\t\t\t Error %d invalid file header found \n", r); } done: /* Free mem first */ if (lineRec != NULL) { free(lineRec); lineRec = NULL; } if(r != RSGTE_EOF) goto err; /* Make sure we've reached the end of file in both log and signature file */ if (fgetc(logfp) != EOF) { fprintf(stderr, "There are unsigned records in the end of log.\n"); fprintf(stderr, "Last signed record: %s\n", ectx.errRec); r = RSGTE_END_OF_SIG; goto err; } if (fgetc(sigfp) != EOF) { fprintf(stderr, "There are records missing from the end of the log file.\n"); r = RSGTE_END_OF_LOG; goto err; } /* Close File handles */ fclose(logfp); logfp = NULL; fclose(sigfp); sigfp = NULL; if(nsigfp != NULL) { fclose(nsigfp); nsigfp = NULL; } /* Check for Extend in LogSig Mode: Everything went fine, so we rename files if we updated them */ if(FILEMODE == FILEMODE_LOGSIG && 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; } } rsksi_errctxExit(&ectx); return 1; err: if(r != 0) sprintf(errbuf, "error %d (%s) processing file %s\n", r, RSKSIE2String(r), name); else errbuf[0] = '\0'; /* Close File handles */ if(logfp != NULL) fclose(logfp); if(sigfp != NULL) fclose(sigfp); if(nsigfp != NULL) { fclose(nsigfp); unlink(nsigfname); } if(bInitDone) { rsksi_errctxExit(&ectx); } return 0; }