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 testSignatureSigningTime(CuTest *tc) { int res; KSI_Signature *sig = NULL; KSI_Integer *sigTime = NULL; KSI_uint64_t utc = 0; KSI_ERR_clearErrors(ctx); res = KSI_Signature_fromFile(ctx, getFullResourcePath(TEST_SIGNATURE_FILE), &sig); CuAssert(tc, "Unable to read signature from file.", res == KSI_OK && sig != NULL); res = KSI_Signature_getSigningTime(sig, &sigTime); CuAssert(tc, "Unable to get signing time from signature", res == KSI_OK && sigTime != NULL); utc = KSI_Integer_getUInt64(sigTime); CuAssert(tc, "Unexpected signature signing time.", utc == 1398866256); KSI_Signature_free(sig); }
int KSI_PublicationData_toBase32(const KSI_PublicationData *pubData, char **pubStr) { int res; const unsigned char *imprint = NULL; size_t imprint_len = 0; KSI_uint64_t publication_identifier = 0; unsigned char *binPub = NULL; size_t binPub_length; int i; unsigned long tmp_ulong; char *tmp = NULL; if (pubData == NULL) { res = KSI_INVALID_ARGUMENT; goto cleanup; } KSI_ERR_clearErrors(pubData->ctx); if (pubStr == NULL) { KSI_pushError(pubData->ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } res = KSI_DataHash_getImprint(pubData->imprint, &imprint, &imprint_len); if (res != KSI_OK) { KSI_pushError(pubData->ctx, res, NULL); goto cleanup; } binPub_length = 8 + imprint_len + 4; binPub = KSI_calloc(binPub_length, 1); if (binPub == NULL) { KSI_pushError(pubData->ctx, res = KSI_OUT_OF_MEMORY, NULL); goto cleanup; } publication_identifier = KSI_Integer_getUInt64(pubData->time); for (i = 7; i >= 0; --i) { binPub[i] = (unsigned char) (publication_identifier & 0xff); publication_identifier >>= 8; } memcpy(binPub + 8, imprint, imprint_len); tmp_ulong = KSI_crc32(binPub, binPub_length - 4, 0); for (i = 3; i >= 0; --i) { binPub[binPub_length - 4 + i] = (unsigned char) (tmp_ulong & 0xff); tmp_ulong >>= 8; } res = KSI_base32Encode(binPub, binPub_length, 6, &tmp); if (res != KSI_OK) { KSI_pushError(pubData->ctx, res, NULL); goto cleanup; } *pubStr = tmp; tmp = NULL; res = KSI_OK; cleanup: KSI_free(binPub); KSI_free(tmp); 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; }
static int rfc3161_getInputToAggreChain(const KSI_Signature *sig, KSI_DataHash **inputToAggre) { int res; KSI_CTX *ctx = NULL; KSI_DataHash *hsh_tstInfo = NULL; KSI_DataHash *hsh_sigAttr = NULL; KSI_DataHash *tmp = NULL; KSI_DataHasher *hsr = NULL; KSI_RFC3161 *rfc = NULL; const unsigned char *imprint = NULL; size_t imprint_len = 0; KSI_HashAlgorithm algo_id = -1; KSI_HashAlgorithm tstInfoAlgoId; KSI_HashAlgorithm sigAttrAlgoId; if (sig == NULL) { res = KSI_INVALID_ARGUMENT; goto cleanup; } ctx = sig->ctx; KSI_ERR_clearErrors(ctx); if (inputToAggre == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } rfc = sig->rfc3161; if (rfc == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } if (KSI_Integer_getUInt64(rfc->tstInfoAlgo) > 0xff || KSI_Integer_getUInt64(rfc->sigAttrAlgo) > 0xff) { KSI_pushError(ctx, res = KSI_INVALID_FORMAT, "Hash algorithm can't be larger than 0xff."); goto cleanup; } else { tstInfoAlgoId = (int)KSI_Integer_getUInt64(rfc->tstInfoAlgo); sigAttrAlgoId = (int)KSI_Integer_getUInt64(rfc->sigAttrAlgo); } res = rfc3161_preSufHasher(ctx, rfc->tstInfoPrefix, rfc->inputHash, rfc->tstInfoSuffix, tstInfoAlgoId, &hsh_tstInfo); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = rfc3161_preSufHasher(ctx, rfc->sigAttrPrefix, hsh_tstInfo, rfc->sigAttrSuffix, sigAttrAlgoId, &hsh_sigAttr); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_DataHash_getImprint(hsh_sigAttr, &imprint, &imprint_len); if (res != KSI_OK) { KSI_pushError(sig->ctx, res, NULL); goto cleanup; } res = KSI_Signature_getHashAlgorithm((KSI_Signature *)sig, &algo_id); if (res != KSI_OK) { KSI_pushError(sig->ctx, res, NULL); goto cleanup; } res = KSI_DataHash_create(ctx, imprint, imprint_len, algo_id, &tmp); if (res != KSI_OK) { KSI_pushError(sig->ctx, res, NULL); goto cleanup; } *inputToAggre = tmp; tmp = NULL; cleanup: KSI_DataHasher_free(hsr); KSI_DataHash_free(hsh_tstInfo); KSI_DataHash_free(hsh_sigAttr); KSI_DataHash_free(tmp); return res; }
/*TODO: check chain index verification*/ static int rfc3161_verify(const KSI_Signature *sig) { int res; KSI_CTX *ctx = NULL; KSI_RFC3161 *rfc3161 = NULL; KSI_AggregationHashChainList *aggreChain = NULL; KSI_AggregationHashChain *firstChain = NULL; unsigned i; if (sig == NULL) { res = KSI_INVALID_ARGUMENT; goto cleanup; } ctx = sig->ctx; KSI_ERR_clearErrors(ctx); rfc3161 = sig->rfc3161; if (rfc3161 == NULL) { res = KSI_OK; goto cleanup; } aggreChain = sig->aggregationChainList; if (aggreChain == NULL) { KSI_pushError(ctx, res = KSI_INVALID_SIGNATURE, "Aggregation chain is missing."); goto cleanup; } res = KSI_AggregationHashChainList_elementAt(aggreChain, 0, &firstChain); if (res != KSI_OK || firstChain == NULL) { KSI_pushError(ctx, res != KSI_OK ? res : (res = KSI_INVALID_STATE), NULL); goto cleanup; } if (KSI_Integer_compare(firstChain->aggregationTime, rfc3161->aggregationTime) != 0) { KSI_LOG_debug(ctx, "Signatures aggregation time: %i.", KSI_Integer_getUInt64(firstChain->aggregationTime)); KSI_LOG_debug(ctx, "RFC 3161 aggregation time: %i.", KSI_Integer_getUInt64(rfc3161->aggregationTime)); KSI_pushError(ctx, res = KSI_VERIFICATION_FAILURE, "Aggregation chain and RFC 3161 aggregation time mismatch."); goto cleanup; } if (KSI_IntegerList_length(firstChain->chainIndex) != KSI_IntegerList_length(rfc3161->chainIndex)) { KSI_LOG_debug(ctx, "Aggregation chain and RFC 3161 chain index mismatch.", KSI_IntegerList_length(firstChain->chainIndex)); KSI_LOG_debug(ctx, "Signatures chain index length: %i.", KSI_IntegerList_length(firstChain->chainIndex)); KSI_LOG_debug(ctx, "RFC 3161 chain index length: %i.", KSI_IntegerList_length(rfc3161->chainIndex)); }else { for (i = 0; i < KSI_IntegerList_length(firstChain->chainIndex); i++){ KSI_Integer *ch1 = NULL; KSI_Integer *ch2 = NULL; res = KSI_IntegerList_elementAt(firstChain->chainIndex, i, &ch1); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_IntegerList_elementAt(rfc3161->chainIndex, i, &ch2); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } if (KSI_Integer_compare(ch1, ch2) != 0) { KSI_LOG_debug(ctx, "Aggregation chain and RFC 3161 chain index mismatch.", KSI_IntegerList_length(firstChain->chainIndex)); break; } } } res = KSI_OK; cleanup: return res; }