int KSI_PublicationsFile_getLatestPublication(const KSI_PublicationsFile *trust, const KSI_Integer *pubTime, KSI_PublicationRecord **pubRec) { int res; size_t i; KSI_PublicationRecord *result = NULL; KSI_Integer *result_tm = NULL; if (trust == NULL) { res = KSI_INVALID_ARGUMENT; goto cleanup; } KSI_ERR_clearErrors(trust->ctx); if (pubRec == 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; KSI_PublicationData *pd = NULL; KSI_Integer *tm = NULL; res = KSI_PublicationRecordList_elementAt(trust->publications, i, &pr); if (res != KSI_OK) { KSI_pushError(trust->ctx, res, NULL); goto cleanup; } res = KSI_PublicationRecord_getPublishedData(pr, &pd); if (res != KSI_OK) { KSI_pushError(trust->ctx, res, NULL); goto cleanup; } res = KSI_PublicationData_getTime(pd, &tm); if (res != KSI_OK) { KSI_pushError(trust->ctx, res, NULL); goto cleanup; } /* Check if current publication time is after given time. */ if (pubTime == NULL || KSI_Integer_compare(pubTime, tm) <= 0) { /* Check if current publication time is after the latest so far. */ if (result_tm == NULL || KSI_Integer_compare(result_tm, tm) <= 0) { result = pr; result_tm = tm; } } KSI_nofree(tm); KSI_nofree(pd); } *pubRec = result; res = KSI_OK; cleanup: KSI_nofree(result); KSI_nofree(result_tm); 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; }
/** * This function extends the signature to the given publication. * \param[in] sig Initial signature. * \param[in] pubStr Null-terminated c string of the publication. * \param[out] ext Pointer to the receiving pointer to the extended signature. * \return Returns KSI_OK if successful. */ static int extendToPublication(KSI_Signature *sig, const char *pubStr, KSI_Signature **ext) { int res = KSI_UNKNOWN_ERROR; /* Only the published data. */ KSI_PublicationData *pubData = NULL; /* Published data and the references to the actual publications. */ KSI_PublicationRecord *pubRec = NULL; /* Publication time. */ KSI_Integer *pubTime = NULL; /* Signature signing time. */ KSI_Integer *signTime = NULL; /* Parse the publications string. */ res = KSI_PublicationData_fromBase32(ksi, pubStr, &pubData); if (res != KSI_OK) { fprintf(stderr, "Invalid publication: '%s'\n", pubStr); goto cleanup; } /* Verify the publication is newer than the signature. */ res = KSI_Signature_getSigningTime(sig, &signTime); if (res != KSI_OK) goto cleanup; res = KSI_PublicationData_getTime(pubData, &pubTime); if (res != KSI_OK) goto cleanup; if (KSI_Integer_compare(signTime, pubTime) > 0) { fprintf(stderr, "Signature created after publication.\n"); res = KSI_INVALID_ARGUMENT; goto cleanup; } /* Create a publication record. */ res = KSI_PublicationRecord_new(ksi, &pubRec); if (res != KSI_OK) goto cleanup; /* Set the published data value. */ res = KSI_PublicationRecord_setPublishedData(pubRec, pubData); if (res != KSI_OK) goto cleanup; /* The pointer will be free by KSI_PublicatioinRecord_free. */ pubData = NULL; /* NB! If the user wants to store the extended signature, some publication references should * be added to the publication reference. As we are going to discard the signature after * verification, the references are not important. */ /* Extend the signature to the publication. */ res = KSI_Signature_extend(sig, ksi, pubRec, ext); if (res != KSI_OK) { fprintf(stderr, "Unable to to extend the signature to the given publication: '%s'\n", pubStr); goto cleanup; } res = KSI_OK; cleanup: /* We can cleanup the values. */ KSI_PublicationData_free(pubData); KSI_PublicationRecord_free(pubRec); 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; }