Example #1
0
/* 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, FILE *nsigfp,
                uint8_t bExtend, gterrctx_t *ectx)
{
	int r;
	int gtstate;
	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, &rec)) != 0)
		goto done;
	if(ectx->recNum != bs->recCount) {
		r = RSGTE_INVLD_RECCNT;
		goto done;
	}

	gtstate = GTTimestamp_DERDecode(file_bs->sig.der.data,
					file_bs->sig.der.len, &timestamp);
	if(gtstate != GT_OK) {
		r = RSGTE_TS_DERDECODE;
		ectx->gtstate = gtstate;
		goto done;
	}

	gtstate = GTHTTP_verifyTimestampHash(timestamp, root, NULL,
			NULL, NULL, rsgt_read_puburl, 0, &vrfyInf);
	if(! (gtstate == GT_OK
	      && vrfyInf->verification_errors == GT_NO_FAILURES) ) {
		r = RSGTE_INVLD_TIMESTAMP;
		ectx->gtstate = gtstate;
		goto done;
	}

	if(rsgt_read_showVerified)
		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)
		GTTimestamp_free(timestamp);
	return r;
}
Example #2
0
/* EXTRACT Loglines Function using KSI API 
 *
 * Input: logfilename and open file handles
 */
static int
extractKSI(char *name, char *errbuf, char *sigfname, FILE *logfp, FILE *sigfp)
{
	char newsigfname[4096];
	FILE *newsigfp = NULL; 
	FILE *newlogfp = NULL; 
	char* lineRec = NULL; 
	size_t stlen = 0;
	ssize_t ssread;
	char writeMode[2] = "w"; /* Default = Create new file! */
	int iLineNumbers = 0;
	int* paiLineNumbers = NULL; 
	int r = 0;
	unsigned int j = 0; 
	int iReturn = 1;
	
	/* KSI Signature related variables */
	block_sig_t *bs = NULL;
	block_hdr_t *bh = NULL;
	tlvrecord_t tlvbhrec; 
	ksifile ksi = NULL;
	uint8_t bHasRecHashes, bHasIntermedHashes;
	uint8_t bInBlock;
	int bInitDone = 0;
	block_hashchain_t *hashchain = NULL;
	KSI_DataHash *ksiRootHash = NULL;
	off_t sigfilerewindPos = 0; /* Helper needed to rewind sigfile */

	/* Create default outputfilename if needed*/
	if (outputfile == NULL) {
		int iNameLength = strlen(name); 
		outputfile = malloc( iNameLength + 5 );
		memcpy(outputfile, name, iNameLength);
		memcpy(outputfile+iNameLength, ".out", 4);
		*(outputfile+iNameLength+4) = '\0'; 
		if (debug) printf("debug: extractKSI:\t\t\t default Outputfile: '%s' \n", outputfile); 
	} else {
		if (debug) printf("debug: extractKSI:\t\t\t Outputfile: '%s' \n", outputfile); 
	}

	/* Check/set User output writemode */
	if (append > 0 ) { 
		writeMode[0] = 'a'; 
	}

	/* Count number of linenumbers */ 
	if (strlen(linenumbers) > 0 ) {
		/* Get count of line numbers */ 
		char* pszTmp = linenumbers;
		if (*(pszTmp) != ',')
			iLineNumbers++; 
		else
			pszTmp++; /*Next Char*/

		while(pszTmp != NULL) {
			pszTmp = strchr(pszTmp, ',');
			if( pszTmp != NULL) {
				pszTmp++;
				if ( *(pszTmp) == ',' ) {
					/* Invalid number, double ,, - skip char */
					pszTmp++;
				} else {
					iLineNumbers++;
				}
			}
		}
		if (iLineNumbers == 0) {
			fprintf(stderr, "extractKSI:\t\t\t error invalid linenumbers\n");
			r = RSGTE_IO;
			goto done;
		}
		if (debug) printf("debug: extractKSI:\t\t\t found '%d' linenumbers\n", iLineNumbers);

		/* Convert line numbers into int Array */
		paiLineNumbers = malloc(iLineNumbers*sizeof(int));
		int iNumPos = 0; 
		int iNumLength = 0; 
		char szTmpNum[11]; 
		char* pszBegin = linenumbers;
		char* pszEnd; 
		while(pszBegin != NULL) {
			/* Cut number from string */
			pszEnd = strchr(pszBegin, ',');
			if (pszEnd != NULL )
				iNumLength = (pszEnd-pszBegin);
			else /* Rest of string is last number */
				iNumLength = strlen(pszBegin);
			
			/* Check for valid linenumber */
			if ( iNumLength <= 0 || iNumLength > 10 ) {
				fprintf(stderr, "extractKSI:\t\t\t error invalid linenumbers\n");
				r = RSGTE_IO;
				goto done;
			}
			/* Copy into tmp string and terminate buffer */
			strncpy(szTmpNum, pszBegin, iNumLength);
			szTmpNum[iNumLength] = '\0'; 

			/* Process next linenumber */ 
			if (pszEnd != NULL ) { pszBegin = pszEnd+1; } else { pszBegin = NULL; }
			/* if (debug) fprintf(stderr, "Adding linenumber: '%s' \n", szTmpNum); */

			/* try to convert into INT now! */
			paiLineNumbers[iNumPos] = atoi(szTmpNum); /* invalid numbers will become 0 and ignored */
			if (debug) printf("debug: extractKSI:\t\t\t Adding Linenumber: '%d' \n", paiLineNumbers[iNumPos]); 
			iNumPos++; 
		}
	} else {
		fprintf(stderr, "extractKSI:\t\t\t error missing linenumbers to extract\n");
		r = RSGTE_IO;
		goto done;
	}

	/* Init KSI library */
	ksierrctx_t ectx;
	rsksi_errctxInit(&ectx);
	rsksiInit("rsyslog rsksiutil " VERSION);
	bInitDone = 1;
	/* Set defaults for KSI Signature extraction */
	ectx.verbose = verbose;
	ectx.fp = stderr;
	ectx.filename = strdup(sigfname);

	/* Check for valid file header in sigfile */
	if((r = rsksi_chkFileHdr(sigfp, "LOGSIG11", verbose)) != 0) {
		if (debug) printf("debug: extractKSI:\t\t\t error %d in rsksi_chkFileHdr\n", r); 
		goto done;
	}	
	sigfilerewindPos = ftello(sigfp); /* Store rewind position */


	/* Init KSIFiles for IN and OUT */
	ksi = rsksi_vrfyConstruct_gf();
	if(ksi == NULL) {
		if (debug) printf("debug: extractKSI:\t\t\t error initializing signature file structures\n");
		r = RSGTE_IO;
		goto done;
	}

	/* Start extracting process */
	if (debug) printf("debug: extractKSI:\t\t\t extracting lines(%d) %s from %s now ...\n", iLineNumbers, linenumbers, name); 

	/* Open output logfile for extracted loglines */
	if((newlogfp = fopen(outputfile, writeMode)) == NULL) {
		perror(outputfile);
		r = RSGTE_IO;
		goto done;
	} else {
		if (debug) printf("debug: extractKSI:\t\t\t Output logfile %s opened with mode: '%s'\n", outputfile, writeMode); 
	}

	/* Open output signaturefile for extracted signatures */
	snprintf(newsigfname, sizeof(newsigfname), "%s.ksisig", outputfile);
	newsigfname[sizeof(newsigfname)-1] = '\0';
	if((newsigfp = fopen(newsigfname, writeMode)) == NULL) {
		perror(newsigfname);
		r = RSGTE_IO;
		goto done;
	} else {
		if (debug) printf("debug: extractKSI:\t\t\t Output sigfile %s opened with mode: '%s'\n", newsigfname, writeMode); 
		/* write KSI fileheader */
		if (writeMode[0] == 'w') {
			if(fwrite("RECSIG11", 8, 1, newsigfp) != 1) {
					perror(newsigfname);
					r = RSGTE_IO;
					goto done;
			}
		}
	}

	/* Variables needed for the logfile extraction process */
	int iIndex = 0; 
	int iLineSearch = 0; 
	int iLineMax = 0; 
	int iLineCurrent = 0; 
	int bLogLineFound = 0;		/* Helper variable to detect when right HASH is found! */
	int bBlockSigWritten = 0;	/* Helper variable to verify if block signature is written */
	
	/* Find highest possible linenumber */	
	for(iIndex = 0; iIndex < iLineNumbers; iIndex++) {
		if (paiLineNumbers[iIndex] > iLineMax)
			iLineMax = paiLineNumbers[iIndex]; 
	} 

	/* Main Extraction Loop Starts here */
	do
	{
		/* Free previous hashchain */
		if (hashchain != NULL) {
			rsksi_objfree(0x0907, hashchain); 
			hashchain = NULL;
		}

		/* Init new HashChain */
		if((hashchain = calloc(1, sizeof(block_hashchain_t))) == NULL) {
			r = RSGTE_OOM;
			goto done;
		}
		hashchain->rec_hash.data = NULL; 
		hashchain->stepCount = 0; 
		hashchain->level = 0; 

		/* Get Next linenumber for extraction */
		for(iIndex = 0; iIndex < iLineNumbers; iIndex++) {
			if (paiLineNumbers[iIndex] > iLineSearch) {
				iLineSearch = paiLineNumbers[iIndex]; 
				break; 
			}
		}
		if (debug) printf("debug: extractKSI:\t\t\t Extracting line number '%d'\n", iLineSearch); 
	
		/* Rewind LOG and SIG File for now */
		rewind(logfp); 
		iLineCurrent = 0; 
		fseeko(sigfp, sigfilerewindPos, SEEK_SET); 
		
		/* Reset Helper variables */
		ectx.blkNum = 0;
		ectx.recNumInFile = 0;
		bInBlock = 0;
		bLogLineFound = 0; 
		bBlockSigWritten = 0; 

		do
		{
			/* 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) {
				iLineCurrent++; /* Increment Current Line */
			} else {
				/* END of file reached */
				if (debug) printf("debug: extractKSI:\t\t\t End of file reached.\n"); 
				r = RSGTE_EOF;
				break; 
			}

if (debug) printf("debug: extractKSI:\t\t\t line '%d': %.64s...\n", iLineSearch, lineRec); 

			/* Extract line if correct one */
			if (iLineCurrent == iLineSearch) {
				if (debug) printf("debug: extractKSI:\t\t\t Extracted line '%d': %.64s...\n", iLineSearch, lineRec); 
				
				/* Write logline into output */
				if( (fwrite(lineRec, ssread, 1, newlogfp) != 1) /*|| 
					(fwrite("\n", sizeof(char), 1, newlogfp) != 1)*/ ) {
					free(lineRec);
					fprintf(stderr, "extractKSI:\t\t\t error '%d' while writing into output logfile %s\n", ferror(newlogfp), outputfile);
					r = RSGTE_IO;
					goto done;
				} 

				/* Found correct record, need to extract hash in next step! */
				bLogLineFound = 1; 
			}

			/* Remove Linefeed for verification */
			if( *(lineRec+ssread-1) == '\n') {
				*(lineRec+ssread-1) = '\0';
				--ssread;
				rsksi_errctxSetErrRec(&ectx, lineRec);
			}

			/* Check if this is a new signature block */
			if(bInBlock == 0) {
				/* Free memory */
				if(bs != NULL) { rsksi_objfree(0x0904, bs); bs = NULL; }
				if(bh != NULL) { rsksi_objfree(0x0901, bh); bh = NULL; }
				
				/* Get/Verify Block Paramaters */
				if((r = rsksi_getBlockParams(ksi, sigfp, 1, &bs, &bh, &bHasRecHashes, &bHasIntermedHashes)) != 0) {
					if(ectx.blkNum == 0) {
						fprintf(stderr, "extractKSI:\t\t\t Error %d before finding any signature block - is the file still open and being written to?\n", r);
						r = RSGTE_IO;
					} else {
						if(verbose)
							fprintf(stderr, "extractKSI:\t\t\t EOF after signature block %lld\n", (long long unsigned) ectx.blkNum);
						r = RSGTE_EOF;
					}
					perror(sigfname);
					goto done;
				} else {
					if (debug) printf("debug: extractKSI:\t\t\t %ju records in Block \n", bs->recCount); 
				}

				/* Verify block header */
				if ((r = verifyBLOCK_HDRKSI(ksi, sigfp, NULL, &tlvbhrec)) != 0) {
					perror(sigfname);
					r = RSGTE_IO;
					goto done;
				} 

				/* Init Signature Block */
				rsksi_vrfyBlkInit(ksi, bh, bHasRecHashes, bHasIntermedHashes);
				ectx.recNum = 0;
				++ectx.blkNum;
			}
			++ectx.recNum, ++ectx.recNumInFile;

			/* we need to preserve the first line (record) of each block for
			 * error-reporting purposes (bInBlock==0 meanst start of block)
			 */
			if(bInBlock == 0) rsksi_errctxFrstRecInBlk(&ectx, lineRec);

			/* Verify next record in signature file */
			if ((r = rsksi_vrfy_nextRecExtract(ksi, sigfp, NULL, (unsigned char*)lineRec, ssread, &ectx, hashchain, bLogLineFound)) != RSGTE_SUCCESS) {
				fprintf(stderr, "extractKSI:\t\t\t error %d while verifiying next signature record for logline (%d): '%.64s...'\n", r, iLineCurrent, lineRec);
				goto done;
			} 

			if (bLogLineFound == 1) {
				if (bBlockSigWritten == 0) {
					/* WRITE BLOCK Signature */
					if (debug) printf("debug: extractKSI:\t\t\t rsksi_ExtractBlockSignature #1: \n"); 
					if ((r = rsksi_ExtractBlockSignature(newsigfp, ksi, bs, &ectx, verbose)) != RSGTE_SUCCESS) {
						fprintf(stderr, "extractKSI:\t\t\t error %d while writing block signature for (%d): '%.64s...'\n", r, iLineCurrent, lineRec);
						goto done;
					}
					bBlockSigWritten = 1; 
				}
			}

			if(ectx.recNum == bs->recCount) {
				if (bBlockSigWritten == 1) {
					/* We need additional Block Finish handling! */				
					if((r = verifySigblkFinishChain(ksi, hashchain, &ksiRootHash, &ectx)) != 0) {
						fprintf(stderr, "extractKSI:\t\t\t error %d while finishing BLOCK signature\n", r);
						goto done;
					}
				} else {
					/* Finish Block ! */				
					if((r = verifySigblkFinish(ksi, &ksiRootHash)) != 0) {
						fprintf(stderr, "extractKSI:\t\t\t error %d while finish signature BLOCK\n", r);
						goto done;
					}
				}

				/* Verify Block signature */
				if((r = verifyBLOCK_SIGKSI(bs, ksi, sigfp, NULL, 0, ksiRootHash, &ectx)) != RSGTE_SUCCESS) {
					fprintf(stderr, "extractKSI:\t\t\t error %d while verifiying BLOCK signature for logline (%d): '%.64s...'\n", r, iLineCurrent, lineRec);
					goto done;
				}

				/* Reset Block state variables */
				bInBlock = 0;

				if (bLogLineFound == 1 ) {
					/* Write HashChain now */
					if ((r = rsksi_WriteHashChain(newsigfp, hashchain, bs, verbose)) != RSGTE_SUCCESS) {
						fprintf(stderr, "extractKSI:\t\t\t error %d while starting new hash chain for (%d): '%.64s...'\n", r, iLineCurrent, lineRec);
						goto done;
					}

					/* Abort Loop from here and start over */
					break; 
				}
			} else {
				bInBlock = 1;
			}
//		} while (iLineCurrent < iLineSearch && r != RSGTE_EOF); 
		} while (r != RSGTE_EOF); 

		/* Variables will be resetted at Loop begin */
	} while ( (iLineMax > iLineSearch || bInBlock == 1) && r != RSGTE_EOF); 

done:
	/* Free mem */
	if (lineRec != NULL)
		free(lineRec);
	if (paiLineNumbers != NULL)
		free(paiLineNumbers); 

	/* Free hashchain */
	if (hashchain != NULL) {
		rsksi_objfree(0x0907, hashchain); 
		hashchain = NULL;
	}

	/* Free Blockheader / Sig */
	if(bs != NULL) rsksi_objfree(0x0904, bs);
	if(bh != NULL) rsksi_objfree(0x0901, bh);

	/* Free KSI File helper stuff */
	if (ksi != NULL) {
		rsksiCtxDel(ksi->ctx);
		free(ksi->IV);
		rsksiimprintDel(ksi->x_prev);
		free(ksi);
	}

	if(r != RSGTE_EOF) {
		goto done2;
	}

	/* 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 done2;
	}
	if (fgetc(sigfp) != EOF) {
		fprintf(stderr, "There are records missing from the end of the log file.\n");
		r = RSGTE_END_OF_LOG;
		goto done2;
	}

done2: 
	if(r != 0 && r != RSGTE_EOF) {
		sprintf(errbuf, "extractKSI:\t\t\t error %d (%s) processing file %s\n", r, RSKSIE2String(r), name);
		iReturn = 0; 
	} else
		errbuf[0] = '\0';

	/* Close file handles */
	if(logfp != NULL) {
		fclose(logfp); 
	}
	if(sigfp != NULL) {
		fclose(sigfp); 
	}
	if(newlogfp != NULL) {
		fclose(newlogfp); 
	}
	if(newsigfp != NULL) {
		fclose(newsigfp); 
	}
	
	/* Deinit KSI stuff */
	if(bInitDone)
		rsksi_errctxExit(&ectx);
	return iReturn;
}