static int verifyCalendarChainWithPublication(KSI_Signature *sig){ int res = KSI_UNKNOWN_ERROR; KSI_CalendarHashChain *calChain = NULL; KSI_Integer *pubTime = NULL; KSI_DataHash *rootHash = NULL; KSI_PublicationRecord *sigPubRec = NULL; KSI_PublicationData *sigPubData = NULL; KSI_DataHash *publishedHash = NULL; KSI_Integer *publishedTime = NULL; KSI_VerificationStep step = KSI_VERIFY_CALCHAIN_WITH_PUBLICATION; KSI_VerificationResult *info = &sig->verificationResult; if (sig->publication == NULL) { res = KSI_OK; goto cleanup; } KSI_LOG_debug(sig->ctx, "Verifying calendar chain with publication."); calChain = sig->calendarChain; res = KSI_CalendarHashChain_getPublicationTime(calChain, &pubTime); if (res != KSI_OK) goto cleanup; res = KSI_CalendarHashChain_aggregate(calChain, &rootHash); if (res != KSI_OK) goto cleanup; sigPubRec = sig->publication; res = KSI_PublicationRecord_getPublishedData(sigPubRec, &sigPubData); if (res != KSI_OK) goto cleanup; res = KSI_PublicationData_getImprint(sigPubData, &publishedHash); if (res != KSI_OK) goto cleanup; res = KSI_PublicationData_getTime(sigPubData, &publishedTime); if (res != KSI_OK) goto cleanup; if (!KSI_DataHash_equals(rootHash, publishedHash)){ KSI_LOG_logDataHash(sig->ctx, KSI_LOG_DEBUG, "Calendar root hash", rootHash); KSI_LOG_logDataHash(sig->ctx, KSI_LOG_DEBUG, "Published hash", publishedHash); res = KSI_VerificationResult_addFailure(info, step, "Published hash and calendar hash chain root hash mismatch."); goto cleanup; } if (!KSI_Integer_equals(pubTime, publishedTime)){ KSI_LOG_debug(sig->ctx, "Calendar hash chain publication time: %i.", KSI_Integer_getUInt64(pubTime)); KSI_LOG_debug(sig->ctx, "Published publication time: %i.", KSI_Integer_getUInt64(publishedTime)); res = KSI_VerificationResult_addFailure(info, step, "Calendar hash chain publication time mismatch."); goto cleanup; } res = KSI_VerificationResult_addSuccess(info, step, "Calendar chain verified with publication."); cleanup: KSI_DataHash_free(rootHash); return res; }
static void testFindPublicationByPubStr(CuTest *tc) { static const char publication[] = "AAAAAA-CTJR3I-AANBWU-RY76YF-7TH2M5-KGEZVA-WLLRGD-3GKYBG-AM5WWV-4MCLSP-XPRDDI-UFMHBA"; int res; KSI_PublicationsFile *pubFile = NULL; KSI_PublicationRecord *pubRec = NULL; KSI_PublicationData *pub = NULL; KSI_DataHash *pubHsh = NULL; KSI_Integer *pubTime = NULL; KSI_DataHash *expHsh = NULL; unsigned char buf[0xff]; size_t len; KSI_CTX *ctx = NULL; res = KSITest_CTX_clone(&ctx); CuAssert(tc, "Unable to create KSI context.", res == KSI_OK && ctx != NULL); res = KSITest_setDefaultPubfileAndVerInfo(ctx); CuAssert(tc, "Unable to set default values to context.", res == KSI_OK); KSI_ERR_clearErrors(ctx); res = KSI_CTX_setPublicationUrl(ctx, getFullResourcePathUri(TEST_PUBLICATIONS_FILE)); CuAssert(tc, "Unable to set pubfile URI.", res == KSI_OK); res = KSI_receivePublicationsFile(ctx, &pubFile); CuAssert(tc, "Unable to get publications file.", res == KSI_OK && pubFile != NULL); res = KSI_verifyPublicationsFile(ctx, pubFile); CuAssert(tc, "Unable to verify publications file.", res == KSI_OK); res = KSI_PublicationsFile_getPublicationDataByPublicationString(pubFile, publication, &pubRec); CuAssert(tc, "Unable to get publication record by publication string.", res == KSI_OK && pubRec != NULL); res = KSI_PublicationRecord_getPublishedData(pubRec, &pub); CuAssert(tc, "Unable to get published data", res == KSI_OK && pub != NULL); res = KSI_PublicationData_getImprint(pub, &pubHsh); CuAssert(tc, "Unable to get published hash", res == KSI_OK && pubHsh != NULL); res = KSI_PublicationData_getTime(pub, &pubTime); CuAssert(tc, "Unable to get publication time.", res == KSI_OK && pubTime != NULL); KSITest_decodeHexStr("01a1b5238ffb05fccfa67546266a0b2d7130f6656026033b6b578c12e4fbbe231a", buf, sizeof(buf), &len); res = KSI_DataHash_fromImprint(ctx, buf, len, &expHsh); CuAssert(tc, "Unable to get data hash from imprint.", res == KSI_OK && expHsh != NULL); CuAssert(tc, "Publication hash mismatch.", KSI_DataHash_equals(expHsh, pubHsh)); CuAssert(tc, "Publication time mismatch", KSI_Integer_equalsUInt(pubTime, 1397520000)); KSI_DataHash_free(expHsh); KSI_PublicationsFile_free(pubFile); KSI_CTX_free(ctx); }
static int verifyCalendarChain(KSI_Signature *sig) { int res = KSI_UNKNOWN_ERROR; KSI_DataHash *rootHash = NULL; KSI_Integer *calendarPubTm = NULL; KSI_PublicationData *pubData = NULL; KSI_DataHash *pubHash = NULL; KSI_Integer *pubTime = NULL; KSI_VerificationStep step = KSI_VERIFY_CALCHAIN_WITH_CALAUTHREC; KSI_VerificationResult *info = &sig->verificationResult; if (sig->calendarAuthRec == NULL) { res = KSI_OK; goto cleanup; } KSI_LOG_info(sig->ctx, "Verifying calendar hash chain."); /* Calculate the root hash value. */ res = KSI_CalendarHashChain_aggregate(sig->calendarChain, &rootHash); if (res != KSI_OK) goto cleanup; /* Get the publication time from calendar hash chain. */ res = KSI_CalendarHashChain_getPublicationTime(sig->calendarChain, &calendarPubTm); if (res != KSI_OK) goto cleanup; /* Get publication data. */ res = KSI_CalendarAuthRec_getPublishedData(sig->calendarAuthRec, &pubData); if (res != KSI_OK) goto cleanup; /* Get published hash value. */ res = KSI_PublicationData_getImprint(pubData, &pubHash); if (res != KSI_OK) goto cleanup; /* Get publication time. */ res = KSI_PublicationData_getTime(pubData, &pubTime); if (res != KSI_OK) goto cleanup; if (KSI_Integer_equals(calendarPubTm, pubTime) && KSI_DataHash_equals(rootHash, pubHash)) { res = KSI_VerificationResult_addSuccess(info, step, "Calendar chain and authentication record match."); } else { res = KSI_VerificationResult_addFailure(info, step, "Calendar chain and authentication record mismatch."); } if (res != KSI_OK) goto cleanup; res = KSI_OK; cleanup: KSI_DataHash_free(rootHash); return res; }
static void testFindPublicationByTime(CuTest *tc) { int res; KSI_PublicationsFile *pubFile = NULL; KSI_PublicationRecord *pubRec = NULL; KSI_PublicationData *pub = NULL; KSI_DataHash *pubHsh = NULL; KSI_Integer *pubTime = NULL; KSI_DataHash *expHsh = NULL; KSI_LIST(KSI_Utf8String) *pubRefList = NULL; unsigned char buf[0xff]; unsigned len; KSI_ERR_clearErrors(ctx); res = KSI_receivePublicationsFile(ctx, &pubFile); CuAssert(tc, "Unable to get publications file.", res == KSI_OK && pubFile != NULL); res = KSI_Integer_new(ctx, 1397520000, &pubTime); CuAssert(tc, "Unable to create ksi integer object.", res == KSI_OK && pubTime != NULL); res = KSI_PublicationsFile_getPublicationDataByTime(pubFile, pubTime, &pubRec); CuAssert(tc, "Unable to get publication record by publication date.", res == KSI_OK && pubRec != NULL); res = KSI_PublicationRecord_getPublishedData(pubRec, &pub); CuAssert(tc, "Unable to get published data", res == KSI_OK && pub != NULL); res = KSI_PublicationData_getImprint(pub, &pubHsh); CuAssert(tc, "Unable to get published hash", res == KSI_OK && pubHsh != NULL); KSI_Integer_free(pubTime); pubTime = NULL; res = KSI_PublicationData_getTime(pub, &pubTime); CuAssert(tc, "Unable to get publication time.", res == KSI_OK && pubTime != NULL); KSITest_decodeHexStr("01a1b5238ffb05fccfa67546266a0b2d7130f6656026033b6b578c12e4fbbe231a", buf, sizeof(buf), &len); res = KSI_DataHash_fromImprint(ctx, buf, len, &expHsh); CuAssert(tc, "Unable to get datahash from imprint", res == KSI_OK && expHsh != NULL); CuAssert(tc, "Publication hash mismatch.", KSI_DataHash_equals(expHsh, pubHsh)); CuAssert(tc, "Publication time mismatch", KSI_Integer_equalsUInt(pubTime, 1397520000)); res = KSI_PublicationRecord_getPublicationRefList(pubRec, &pubRefList); CuAssert(tc, "Unable to get publications ref list", res == KSI_OK && pubRefList != NULL); KSI_DataHash_free(expHsh); }
int KSI_PublicationsFile_findPublication(const KSI_PublicationsFile *trust, KSI_PublicationRecord *inRec, KSI_PublicationRecord **outRec) { int res; size_t i; if (trust == NULL) { res = KSI_INVALID_ARGUMENT; goto cleanup; } KSI_ERR_clearErrors(trust->ctx); if (inRec == NULL || outRec == NULL) { KSI_pushError(trust->ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } for (i = 0; i < KSI_PublicationRecordList_length(trust->publications); i++) { KSI_PublicationRecord *pr = NULL; res = KSI_PublicationRecordList_elementAt(trust->publications, i, &pr); if (res != KSI_OK || pr == NULL) { KSI_pushError(trust->ctx, res != KSI_OK ? res : (res = KSI_INVALID_STATE), NULL); goto cleanup; } if (pr->publishedData == NULL || inRec->publishedData == NULL) { KSI_pushError(trust->ctx, res = KSI_INVALID_STATE, NULL); goto cleanup; } if (KSI_DataHash_equals(pr->publishedData->imprint, inRec->publishedData->imprint) && KSI_Integer_equals(pr->publishedData->time, inRec->publishedData->time) ) { *outRec = KSI_PublicationRecord_ref(pr); break; } KSI_nofree(pr); } res = KSI_OK; cleanup: return res; }
static int verifyAggregationRootWithCalendarChain(KSI_Signature *sig) { int res = KSI_UNKNOWN_ERROR; KSI_DataHash *inputHash = NULL; KSI_VerificationStep step = KSI_VERIFY_AGGRCHAIN_WITH_CALENDAR_CHAIN; KSI_VerificationResult *info = &sig->verificationResult; KSI_AggregationHashChain *aggregationChain = NULL; KSI_Integer *calAggrTime = NULL; KSI_LOG_info(sig->ctx, "Verifying aggregation hash chain root."); res = KSI_CalendarHashChain_getInputHash(sig->calendarChain, &inputHash); if (res != KSI_OK) goto cleanup; /* Take the first aggregation hash chain, as all of the chain should have * the same value for "aggregation time". */ res = KSI_AggregationHashChainList_elementAt(sig->aggregationChainList, 0, &aggregationChain); if (res != KSI_OK || aggregationChain == NULL) { if (res == KSI_OK) res = KSI_INVALID_STATE; goto cleanup; } if (!KSI_DataHash_equals(sig->verificationResult.aggregationHash, inputHash)) { res = KSI_VerificationResult_addFailure(info, step, "Aggregation root hash mismatch."); if (res != KSI_OK) goto cleanup; } res = KSI_CalendarHashChain_getAggregationTime(sig->calendarChain, &calAggrTime); if (res != KSI_OK) goto cleanup; if (!KSI_Integer_equals(calAggrTime, aggregationChain->aggregationTime)) { res = KSI_VerificationResult_addFailure(info, step, "Aggregation time in calendar chain and aggregation chain differ."); if (res != KSI_OK) goto cleanup; } res = KSI_VerificationResult_addSuccess(info, step, "Aggregation root matches with calendar chain."); if (res != KSI_OK) goto cleanup; cleanup: KSI_nofree(calAggrTime); KSI_nofree(aggregationChain); return res; }
static int verifyDocument(KSI_Signature *sig) { int res = KSI_UNKNOWN_ERROR; KSI_DataHash *hsh = NULL; KSI_VerificationStep step = KSI_VERIFY_DOCUMENT; KSI_VerificationResult *info = &sig->verificationResult; if (!sig->verificationResult.verifyDocumentHash) { res = KSI_OK; goto cleanup; } KSI_LOG_info(sig->ctx, "Verifying document hash."); KSI_LOG_logDataHash(sig->ctx, KSI_LOG_DEBUG, "Verifying document hash", sig->verificationResult.documentHash); if (sig->rfc3161 != NULL) { KSI_LOG_info(sig->ctx, "Document hash is compared with RFC 3161 input hash."); res = KSI_RFC3161_getInputHash(sig->rfc3161, &hsh); if (res != KSI_OK) goto cleanup; } else { res = KSI_Signature_getDocumentHash(sig, &hsh); if (res != KSI_OK) goto cleanup; } if (!KSI_DataHash_equals(hsh, sig->verificationResult.documentHash)) { KSI_LOG_logDataHash(sig->ctx, KSI_LOG_DEBUG, "Document hash", sig->verificationResult.documentHash); KSI_LOG_logDataHash(sig->ctx, KSI_LOG_DEBUG, "Signed hash", hsh); res = KSI_VerificationResult_addFailure(info, step, "Wrong document."); goto cleanup; } res = KSI_VerificationResult_addSuccess(info, step, "Document correct."); cleanup: KSI_nofree(hsh); KSI_nofree(info); return res; }
static void testFindPublicationByPubStr(CuTest *tc) { static const char publication[] = "AAAAAA-CTJR3I-AANBWU-RY76YF-7TH2M5-KGEZVA-WLLRGD-3GKYBG-AM5WWV-4MCLSP-XPRDDI-UFMHBA"; int res; KSI_PublicationsFile *pubFile = NULL; KSI_PublicationRecord *pubRec = NULL; KSI_PublicationData *pub = NULL; KSI_DataHash *pubHsh = NULL; KSI_Integer *pubTime = NULL; KSI_DataHash *expHsh = NULL; unsigned char buf[0xff]; unsigned len; KSI_ERR_clearErrors(ctx); res = KSI_receivePublicationsFile(ctx, &pubFile); CuAssert(tc, "Unable to get publications file.", res == KSI_OK && pubFile != NULL); res = KSI_PublicationsFile_getPublicationDataByPublicationString(pubFile, publication, &pubRec); CuAssert(tc, "Unable to get publication record by publication string.", res == KSI_OK && pubRec != NULL); res = KSI_PublicationRecord_getPublishedData(pubRec, &pub); CuAssert(tc, "Unable to get published data", res == KSI_OK && pub != NULL); res = KSI_PublicationData_getImprint(pub, &pubHsh); CuAssert(tc, "Unable to get published hash", res == KSI_OK && pubHsh != NULL); res = KSI_PublicationData_getTime(pub, &pubTime); CuAssert(tc, "Unable to get publication time.", res == KSI_OK && pubTime != NULL); KSITest_decodeHexStr("01a1b5238ffb05fccfa67546266a0b2d7130f6656026033b6b578c12e4fbbe231a", buf, sizeof(buf), &len); res = KSI_DataHash_fromImprint(ctx, buf, len, &expHsh); CuAssert(tc, "Unable to get data hash from imprint.", res == KSI_OK && expHsh != NULL); CuAssert(tc, "Publication hash mismatch.", KSI_DataHash_equals(expHsh, pubHsh)); CuAssert(tc, "Publication time mismatch", KSI_Integer_equalsUInt(pubTime, 1397520000)); KSI_DataHash_free(expHsh); }
int KSI_PublicationsFile_getPublicationDataByPublicationString(const KSI_PublicationsFile *pubFile, const char *pubString, KSI_PublicationRecord **pubRec) { int res; KSI_PublicationData *findPubData = NULL; KSI_DataHash *findImprint = NULL; KSI_Integer *findTime = NULL; KSI_PublicationRecord *tmpPubRec = NULL; KSI_PublicationData *tmpPubData = NULL; KSI_DataHash *tmpImprint = NULL; if (pubFile == NULL) { res = KSI_INVALID_ARGUMENT; goto cleanup; } KSI_ERR_clearErrors(pubFile->ctx); if (pubString == NULL || pubRec == NULL) { KSI_pushError(pubFile->ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } /* Decode the publication string. */ res = KSI_PublicationData_fromBase32(pubFile->ctx, pubString, &findPubData); if (res != KSI_OK) { KSI_pushError(pubFile->ctx, res, NULL); goto cleanup; } /* Extract the expected imprint. */ res = KSI_PublicationData_getImprint(findPubData, &findImprint); if (res != KSI_OK) { KSI_pushError(pubFile->ctx, res, NULL); goto cleanup; } /* Extract the expected publication time. */ res = KSI_PublicationData_getTime(findPubData, &findTime); if (res != KSI_OK) { KSI_pushError(pubFile->ctx, res, NULL); goto cleanup; } /* Find the publication using the publication time. */ res = KSI_PublicationsFile_getPublicationDataByTime(pubFile, findTime, &tmpPubRec); if (res != KSI_OK) { KSI_pushError(pubFile->ctx, res, NULL); goto cleanup; } if (tmpPubRec != NULL) { /* Extract published data. */ res = KSI_PublicationRecord_getPublishedData(tmpPubRec, &tmpPubData); if (res != KSI_OK) { KSI_pushError(pubFile->ctx, res, NULL); goto cleanup; } /* Extract the time. */ res = KSI_PublicationData_getImprint(tmpPubData, &tmpImprint); if (res != KSI_OK) { KSI_pushError(pubFile->ctx, res, NULL); goto cleanup; } if (!KSI_DataHash_equals(findImprint, tmpImprint)) { KSI_pushError(pubFile->ctx, res = KSI_INVALID_PUBLICATION, NULL); goto cleanup; } } *pubRec = tmpPubRec; res = KSI_OK; cleanup: KSI_PublicationData_free(findPubData); KSI_nofree(findImprint); KSI_nofree(findTime); KSI_nofree(tmpPubRec); KSI_nofree(tmpPubData); KSI_nofree(tmpImprint); return res; }
static void testFindPublicationByTime(CuTest *tc) { int res; KSI_PublicationsFile *pubFile = NULL; KSI_PublicationRecord *pubRec = NULL; KSI_PublicationData *pub = NULL; KSI_DataHash *pubHsh = NULL; KSI_Integer *pubTime = NULL; KSI_DataHash *expHsh = NULL; KSI_LIST(KSI_Utf8String) *pubRefList = NULL; unsigned char buf[0xff]; size_t len; KSI_CTX *ctx = NULL; res = KSITest_CTX_clone(&ctx); CuAssert(tc, "Unable to create KSI context.", res == KSI_OK && ctx != NULL); res = KSITest_setDefaultPubfileAndVerInfo(ctx); CuAssert(tc, "Unable to set default values to context.", res == KSI_OK); KSI_ERR_clearErrors(ctx); res = KSI_CTX_setPublicationUrl(ctx, getFullResourcePathUri(TEST_PUBLICATIONS_FILE)); CuAssert(tc, "Unable to set pubfile URI.", res == KSI_OK); res = KSI_receivePublicationsFile(ctx, &pubFile); CuAssert(tc, "Unable to get publications file.", res == KSI_OK && pubFile != NULL); res = KSI_verifyPublicationsFile(ctx, pubFile); CuAssert(tc, "Unable to verify publications file.", res == KSI_OK); res = KSI_Integer_new(ctx, 1397520000, &pubTime); CuAssert(tc, "Unable to create ksi integer object.", res == KSI_OK && pubTime != NULL); res = KSI_PublicationsFile_getPublicationDataByTime(pubFile, pubTime, &pubRec); CuAssert(tc, "Unable to get publication record by publication date.", res == KSI_OK && pubRec != NULL); res = KSI_PublicationRecord_getPublishedData(pubRec, &pub); CuAssert(tc, "Unable to get published data", res == KSI_OK && pub != NULL); res = KSI_PublicationData_getImprint(pub, &pubHsh); CuAssert(tc, "Unable to get published hash", res == KSI_OK && pubHsh != NULL); KSI_Integer_free(pubTime); pubTime = NULL; res = KSI_PublicationData_getTime(pub, &pubTime); CuAssert(tc, "Unable to get publication time.", res == KSI_OK && pubTime != NULL); KSITest_decodeHexStr("01a1b5238ffb05fccfa67546266a0b2d7130f6656026033b6b578c12e4fbbe231a", buf, sizeof(buf), &len); res = KSI_DataHash_fromImprint(ctx, buf, len, &expHsh); CuAssert(tc, "Unable to get datahash from imprint", res == KSI_OK && expHsh != NULL); CuAssert(tc, "Publication hash mismatch.", KSI_DataHash_equals(expHsh, pubHsh)); CuAssert(tc, "Publication time mismatch", KSI_Integer_equalsUInt(pubTime, 1397520000)); res = KSI_PublicationRecord_getPublicationRefList(pubRec, &pubRefList); CuAssert(tc, "Unable to get publications ref list", res == KSI_OK && pubRefList != NULL); KSI_DataHash_free(expHsh); KSI_PublicationsFile_free(pubFile); KSI_CTX_free(ctx); }
static void testMaskingMultiSig(CuTest *tc) { #define TEST_AGGR_RESPONSE_FILE "resource/tlv/ok-sig-2016-05-09.1-lvl4.ksig" static const unsigned char diceRolls[] = {0xd5, 0x58, 0xaf, 0xfa, 0x80, 0x67, 0xf4, 0x2c, 0xd9, 0x48, 0x36, 0x21, 0xd1, 0xab, 0xae, 0x23, 0xed, 0xd6, 0xca, 0x04, 0x72, 0x7e, 0xcf, 0xc7, 0xdb, 0xc7, 0x6b, 0xde, 0x34, 0x77, 0x1e, 0x53}; int res = KSI_UNKNOWN_ERROR; KSI_BlockSigner *bs = NULL; KSI_MultiSignature *ms = NULL; size_t i; KSI_DataHash *hsh = NULL; KSI_Signature *sig = NULL; KSI_DataHash *zero = NULL; KSI_OctetString *iv = NULL; KSI_DataHash *prevLeaf = NULL; /* Create zero hash. */ res = KSI_DataHash_createZero(ctx, KSI_HASHALG_SHA2_512, &zero); CuAssert(tc, "Unable to create zero hash.", res == KSI_OK && zero != NULL); /* Create random initial vector. */ res = KSI_OctetString_new(ctx, diceRolls, sizeof(diceRolls), &iv); CuAssert(tc, "Unable to create initial vector.", res == KSI_OK && iv != NULL); res = KSI_BlockSigner_new(ctx, KSI_HASHALG_SHA1, zero, iv, &bs); CuAssert(tc, "Unable to create block signer instance with masking.", res == KSI_OK && bs != NULL); res = KSI_BlockSigner_getPrevLeaf(bs, &prevLeaf); CuAssert(tc, "Unable to retrieve previous leaf.", res == KSI_OK && KSI_DataHash_equals(prevLeaf, zero)); addInput(tc, bs, 0); res = KSI_CTX_setAggregator(ctx, getFullResourcePathUri(TEST_AGGR_RESPONSE_FILE), "anon", "anon"); CuAssert(tc, "Unable to set aggregator file URI.", res == KSI_OK); res = KSI_BlockSigner_close(bs, &ms); CuAssert(tc, "Unable to close block signer and extract multi signature.", res == KSI_OK && ms != NULL); res = KSITest_setDefaultPubfileAndVerInfo(ctx); CuAssert(tc, "Unable to set default pubfile, default cert and default pki constraints.", res == KSI_OK); /* Lets loop over all the inputs and try to verify them. */ for (i = 0; input_data[i] != NULL; i++) { res = KSI_DataHash_create(ctx, input_data[i], strlen(input_data[i]), KSI_HASHALG_SHA2_256, &hsh); CuAssert(tc, "Unable to create data hash.", res == KSI_OK && hsh != NULL); res = KSI_MultiSignature_get(ms, hsh, &sig); CuAssert(tc, "Unable to extract signature from the multi signature container.", res == KSI_OK && sig != NULL); res = KSI_Signature_verifyDocument(sig, ctx, (void *)input_data[i], strlen(input_data[i])); CuAssert(tc, "Unable to verify the input data.", res == KSI_OK); KSI_Signature_free(sig); sig = NULL; KSI_DataHash_free(hsh); hsh = NULL; } KSI_OctetString_free(iv); KSI_DataHash_free(zero); KSI_DataHash_free(prevLeaf); KSI_DataHash_free(hsh); KSI_MultiSignature_free(ms); KSI_BlockSigner_free(bs); #undef TEST_AGGR_RESPONSE_FILE }
int main(int argc, char **argv) { int res = KSI_UNKNOWN_ERROR; /* Signature read from the file. */ KSI_Signature *sig = NULL; /* Signature extended to the publication. */ KSI_Signature *ext = NULL; /* Hash of the data file. */ KSI_DataHash *hsh = NULL; /* Hash value extracted from the signature. */ KSI_DataHash *signHsh = NULL; /* Data file hasher. */ KSI_DataHasher *hsr = NULL; /* Input file descriptor. */ FILE *in = NULL; /* Buffer for reading the input. */ unsigned char buf[1024]; /* Length of the buffer content. */ size_t buf_len; /* Verification info object. */ const KSI_VerificationResult *info = NULL; /* File descriptor for logging. */ FILE *logFile = NULL; const KSI_CertConstraint pubFileCertConstr[] = { { KSI_CERT_EMAIL, "*****@*****.**"}, { NULL, NULL } }; /* Init context. */ res = KSI_CTX_new(&ksi); if (res != KSI_OK) { fprintf(stderr, "Unable to init KSI context.\n"); goto cleanup; } logFile = fopen("ksi_verify.log", "w"); if (logFile == NULL) { fprintf(stderr, "Unable to open log file.\n"); } res = KSI_CTX_setDefaultPubFileCertConstraints(ksi, pubFileCertConstr); if (res != KSI_OK) { fprintf(stderr, "Unable to configure publications file cert constraints.\n"); goto cleanup; } /* Configure the logger. */ KSI_CTX_setLoggerCallback(ksi, KSI_LOG_StreamLogger, logFile); KSI_CTX_setLogLevel(ksi, KSI_LOG_DEBUG); KSI_LOG_info(ksi, "Using KSI version: '%s'", KSI_getVersion()); /* Check parameters. */ if (argc != 6) { fprintf(stderr, "Usage\n" " %s <data file | -> <signature> <publication-str> <extender url> <pub-file url>\n", argv[0]); goto cleanup; } /* Configure extender. */ res = KSI_CTX_setExtender(ksi, argv[4], "anon", "anon"); if (res != KSI_OK) { fprintf(stderr, "Unable to set extender parameters.\n"); goto cleanup; } /* Set the publications file url. */ res = KSI_CTX_setPublicationUrl(ksi, argv[4]); if (res != KSI_OK) { fprintf(stderr, "Unable to set publications file url.\n"); goto cleanup; } printf("Reading signature... "); /* Read the signature. */ res = KSI_Signature_fromFile(ksi, argv[2], &sig); if (res != KSI_OK) { printf("failed (%s)\n", KSI_getErrorString(res)); goto cleanup; } printf("ok\n"); printf("Verifying the signature with the publication... "); res = extendToPublication(sig, argv[3], &ext); switch (res) { case KSI_OK: printf("ok\n"); break; case KSI_VERIFICATION_FAILURE: printf("failed\n"); break; default: printf("failed (%s)\n", KSI_getErrorString(res)); goto cleanup; } /* Create hasher. */ res = KSI_Signature_createDataHasher(ext, &hsr); if (res != KSI_OK) { fprintf(stderr, "Unable to create data hasher.\n"); goto cleanup; } if (strcmp(argv[1], "-")) { in = fopen(argv[1], "rb"); if (in == NULL) { fprintf(stderr, "Unable to open data file '%s'.\n", argv[1]); goto cleanup; } /* Calculate the hash of the document. */ while (!feof(in)) { buf_len = fread(buf, 1, sizeof(buf), in); res = KSI_DataHasher_add(hsr, buf, buf_len); if (res != KSI_OK) { fprintf(stderr, "Unable hash the document.\n"); goto cleanup; } } /* Finalize the hash computation. */ res = KSI_DataHasher_close(hsr, &hsh); if (res != KSI_OK) { fprintf(stderr, "Failed to close the hashing process.\n"); goto cleanup; } res = KSI_Signature_getDocumentHash(sig, &signHsh); if (res != KSI_OK) goto cleanup; printf("Verifying document hash... "); if (!KSI_DataHash_equals(hsh, signHsh)) { printf("Wrong document!\n"); goto cleanup; } printf("ok\n"); } res = KSI_Signature_getVerificationResult(ext, &info); if (res != KSI_OK) goto cleanup; if (info != NULL) { size_t i; printf("Verification info:\n"); for (i = 0; i < KSI_VerificationResult_getStepResultCount(info); i++) { const KSI_VerificationStepResult *result = NULL; const char *desc = NULL; res = KSI_VerificationResult_getStepResult(info, i, &result); if (res != KSI_OK) goto cleanup; printf("\t0x%02x:\t%s", KSI_VerificationStepResult_getStep(result), KSI_VerificationStepResult_isSuccess(result) ? "OK" : "FAIL"); desc = KSI_VerificationStepResult_getDescription(result); if (desc && *desc) { printf(" (%s)", desc); } printf("\n"); } } res = KSI_OK; cleanup: if (logFile != NULL) fclose(logFile); if (res != KSI_OK && ksi != NULL) { KSI_ERR_statusDump(ksi, stderr); } if (in != NULL) fclose(in); KSI_Signature_free(sig); KSI_Signature_free(ext); KSI_DataHasher_free(hsr); KSI_DataHash_free(hsh); KSI_CTX_free(ksi); return res; }
static int verifyOnline(KSI_CTX *ctx, KSI_Signature *sig) { int res = KSI_UNKNOWN_ERROR; KSI_ExtendReq *req = NULL; KSI_Integer *start = NULL; KSI_Integer *end = NULL; KSI_RequestHandle *handle = NULL; KSI_DataHash *extHash = NULL; KSI_DataHash *calHash = NULL; KSI_ExtendResp *resp = NULL; KSI_Integer *status = NULL; KSI_CalendarHashChain *calChain = NULL; KSI_DataHash *rootHash = NULL; KSI_DataHash *pubHash = NULL; KSI_VerificationStep step = KSI_VERIFY_CALCHAIN_ONLINE; KSI_VerificationResult *info = &sig->verificationResult; KSI_LOG_info(sig->ctx, "Verifying signature online."); /* Extract start time */ res = KSI_CalendarHashChain_getAggregationTime(sig->calendarChain, &start); if (res != KSI_OK) goto cleanup; /* Clone the start time object */ KSI_Integer_ref(start); if (sig->verificationResult.useUserPublication) { /* Extract end time. */ res = KSI_PublicationData_getTime(sig->verificationResult.userPublication, &end); if (res != KSI_OK) goto cleanup; } res = KSI_createExtendRequest(sig->ctx, start, end, &req); if (res != KSI_OK) goto cleanup; res = KSI_sendExtendRequest(ctx, req, &handle); if (res != KSI_OK) goto cleanup; res = KSI_RequestHandle_perform(handle); if (res != KSI_OK) { KSI_pushError(ctx,res, NULL); goto cleanup; } res = KSI_RequestHandle_getExtendResponse(handle, &resp); if (res != KSI_OK) goto cleanup; /* Verify the correctness of the response. */ res = KSI_ExtendResp_verifyWithRequest(resp, req); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_ExtendResp_getStatus(resp, &status); if (res != KSI_OK) goto cleanup; /* Verify status. */ if (status != NULL && !KSI_Integer_equalsUInt(status, 0)) { KSI_Utf8String *respErr = NULL; char errm[1024]; res = KSI_ExtendResp_getErrorMsg(resp, &respErr); if (res != KSI_OK) goto cleanup; KSI_snprintf(errm, sizeof(errm), "Extend failure from server: '%s'", KSI_Utf8String_cstr(respErr)); res = KSI_VerificationResult_addFailure(info, step, errm); goto cleanup; } res = KSI_ExtendResp_getCalendarHashChain(resp, &calChain); if (res != KSI_OK) goto cleanup; res = KSI_CalendarHashChain_getInputHash(calChain, &extHash); if (res != KSI_OK) goto cleanup; res = KSI_CalendarHashChain_getInputHash(sig->calendarChain, &calHash); if (res != KSI_OK) goto cleanup; if (!KSI_DataHash_equals(extHash, calHash)) { res = KSI_VerificationResult_addFailure(info, step, "Extender returned different input hash for calendar hash chain."); goto cleanup; } if (sig->verificationResult.useUserPublication) { res = KSI_CalendarHashChain_aggregate(calChain, &rootHash); if (res != KSI_OK) goto cleanup; if (!KSI_DataHash_equals(rootHash, pubHash)) { res = KSI_VerificationResult_addFailure(info, step, "External publication imprint mismatch."); goto cleanup; } } res = KSI_VerificationResult_addSuccess(info, step, "Verified online."); cleanup: KSI_Integer_free(start); KSI_ExtendReq_free(req); KSI_RequestHandle_free(handle); KSI_ExtendResp_free(resp); return res; }
static int verifyPublicationWithPubString(KSI_CTX *ctx, KSI_Signature *sig) { int res = KSI_UNKNOWN_ERROR; KSI_VerificationStep step = KSI_VERIFY_PUBLICATION_WITH_PUBSTRING; KSI_VerificationResult *info = &sig->verificationResult; KSI_Integer *time1 = NULL; KSI_Integer *time2 = NULL; KSI_DataHash *hsh1 = NULL; KSI_DataHash *hsh2 = NULL; if (sig->publication == NULL || sig->verificationResult.useUserPublication == false) { res = KSI_OK; goto cleanup; } KSI_LOG_info(ctx, "Verifying publication with publication string"); if (sig->verificationResult.userPublication == NULL) { res = KSI_INVALID_ARGUMENT; goto cleanup; } res = KSI_PublicationData_getTime(sig->verificationResult.userPublication, &time1); if (res != KSI_OK) { res = KSI_INVALID_ARGUMENT; goto cleanup; } res = KSI_PublicationData_getImprint(sig->verificationResult.userPublication, &hsh1); if (res != KSI_OK) { res = KSI_INVALID_ARGUMENT; goto cleanup; } res = KSI_PublicationData_getTime(sig->publication->publishedData, &time2); if (res != KSI_OK) { res = KSI_INVALID_ARGUMENT; goto cleanup; } res = KSI_PublicationData_getImprint(sig->publication->publishedData, &hsh2); if (res != KSI_OK) { res = KSI_INVALID_ARGUMENT; goto cleanup; } if (KSI_Integer_compare(time1, time2) != 0) { KSI_LOG_debug(ctx, "Publication time from publication record:", time2); KSI_LOG_debug(ctx, "Publication time from user publication :", time1); res = KSI_VerificationResult_addFailure(info, step, "Publication not trusted."); goto cleanup; } if (KSI_DataHash_equals(hsh1, hsh2) != 1) { KSI_LOG_logDataHash(ctx, KSI_LOG_DEBUG, "Root hash from publication record:", hsh2); KSI_LOG_logDataHash(ctx, KSI_LOG_DEBUG, "Root hash from user publication:", hsh1); res = KSI_VerificationResult_addFailure(info, step, "Publication not trusted."); goto cleanup; } res = KSI_VerificationResult_addSuccess(info, step, "Publication trusted."); cleanup: return res; }
static int verifyInternallyAggregationChain(KSI_Signature *sig) { int res = KSI_UNKNOWN_ERROR; KSI_DataHash *hsh = NULL; KSI_DataHash *inputHash = NULL; int level; size_t i; size_t successCount = 0; KSI_VerificationStep step = KSI_VERIFY_AGGRCHAIN_INTERNALLY; KSI_VerificationResult *info = &sig->verificationResult; const KSI_AggregationHashChain *prevChain = NULL; /* Aggregate aggregation chains. */ hsh = NULL; /* The aggregation level might not be 0 in case of local aggregation. */ if (sig->verificationResult.docAggrLevel > 0xff) { KSI_pushError(sig->ctx, res = KSI_INVALID_FORMAT, "Aggregation level can't be larger than 0xff."); goto cleanup; } level = (int)sig->verificationResult.docAggrLevel; KSI_LOG_info(sig->ctx, "Verifying aggregation hash chain internal consistency."); if (sig->rfc3161 != NULL) { KSI_LOG_info(sig->ctx, "Using input hash calculated from RFC 3161 for aggregation."); res = rfc3161_getInputToAggreChain(sig, &inputHash); if (res != KSI_OK) goto cleanup; res = rfc3161_verify(sig); if (res != KSI_OK){ res = KSI_VerificationResult_addFailure(info, step, "RFC 3161 does not belong to this aggregation hash chain."); goto cleanup; } } /* Aggregate all the aggregation chains. */ for (i = 0; i < KSI_AggregationHashChainList_length(sig->aggregationChainList); i++) { const KSI_AggregationHashChain* aggregationChain = NULL; KSI_DataHash *tmpHash = NULL; res = KSI_AggregationHashChainList_elementAt(sig->aggregationChainList, i, (KSI_AggregationHashChain **)&aggregationChain); if (res != KSI_OK || aggregationChain == NULL) { if (res == KSI_OK) res = KSI_INVALID_STATE; goto cleanup; } if (prevChain != NULL) { /* Verify aggregation time. */ if (!KSI_Integer_equals(aggregationChain->aggregationTime, prevChain->aggregationTime)) { res = KSI_VerificationResult_addFailure(info, step, "Aggregation hash chain's from different aggregation rounds."); goto cleanup; } /* Verify chain index length. */ if (KSI_IntegerList_length(prevChain->chainIndex) != KSI_IntegerList_length(aggregationChain->chainIndex) + 1) { res = KSI_VerificationResult_addFailure(info, step, "Unexpected chain index length in aggregation chain."); goto cleanup; } else { unsigned j; for (j = 0; j < KSI_IntegerList_length(aggregationChain->chainIndex); j++) { KSI_Integer *chainIndex1 = NULL; KSI_Integer *chainIndex2 = NULL; res = KSI_IntegerList_elementAt(prevChain->chainIndex, j, &chainIndex1); if (res != KSI_OK) goto cleanup; res = KSI_IntegerList_elementAt(aggregationChain->chainIndex, j, &chainIndex2); if (res != KSI_OK) goto cleanup; if (!KSI_Integer_equals(chainIndex1, chainIndex2)) { res = KSI_VerificationResult_addFailure(info, step, "Aggregation chain chain index is not continuation of previous chain index."); goto cleanup; } } } } if (i == 0 && inputHash != NULL){ if (!KSI_DataHash_equals(inputHash, aggregationChain->inputHash)) { KSI_LOG_logDataHash(sig->ctx, KSI_LOG_DEBUG, "Input hash from RFC 3161 :", inputHash); KSI_LOG_logDataHash(sig->ctx, KSI_LOG_DEBUG, "Expected input hash :", aggregationChain->inputHash); res = KSI_VerificationResult_addFailure(info, step, "Aggregation hash chain's input hash does not match with RFC 3161 input hash."); goto cleanup; } } if (hsh != NULL) { /* Validate input hash */ if (!KSI_DataHash_equals(hsh, aggregationChain->inputHash)) { KSI_LOG_logDataHash(sig->ctx, KSI_LOG_DEBUG, "Calculated hash", hsh); KSI_LOG_logDataHash(sig->ctx, KSI_LOG_DEBUG, " Expected hash", aggregationChain->inputHash); break; } } res = KSI_HashChain_aggregate(aggregationChain->ctx, aggregationChain->chain, aggregationChain->inputHash, level, (int)KSI_Integer_getUInt64(aggregationChain->aggrHashId), &level, &tmpHash); if (res != KSI_OK) goto cleanup; /* TODO! Instead of freeing the object - reuse it */ if (hsh != NULL) { KSI_DataHash_free(hsh); } hsh = tmpHash; ++successCount; prevChain = aggregationChain; } /* First verify internal calculations. */ if (successCount != KSI_AggregationHashChainList_length(sig->aggregationChainList)) { res = KSI_VerificationResult_addFailure(info, step, "Aggregation hash chain calculation failed."); goto cleanup; } sig->verificationResult.aggregationHash = hsh; hsh = NULL; res = KSI_VerificationResult_addSuccess(info, step,"Aggregation chain internally consistent."); cleanup: KSI_DataHash_free(hsh); KSI_DataHash_free(inputHash); return res; }