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 verifyCalAuthRec(KSI_CTX *ctx, KSI_Signature *sig) { int res = KSI_UNKNOWN_ERROR; KSI_OctetString *certId = NULL; KSI_PKICertificate *cert = NULL; KSI_OctetString *signatureValue = NULL; KSI_Utf8String *sigtype = NULL; const unsigned char *rawSignature = NULL; size_t rawSignature_len; unsigned char *rawData = NULL; size_t rawData_len; KSI_VerificationStep step = KSI_VERIFY_CALAUTHREC_WITH_SIGNATURE; KSI_VerificationResult *info = &sig->verificationResult; if (sig->calendarAuthRec == NULL) { res = KSI_OK; goto cleanup; } KSI_LOG_info(sig->ctx, "Verifying calendar authentication record."); res = KSI_PKISignedData_getCertId(sig->calendarAuthRec->signatureData, &certId); if (res != KSI_OK) goto cleanup; if (certId == NULL) { res = KSI_INVALID_FORMAT; goto cleanup; } res = initPublicationsFile(&sig->verificationResult, ctx); if (res != KSI_OK) goto cleanup; res = KSI_PublicationsFile_getPKICertificateById(sig->verificationResult.publicationsFile, certId, &cert); if (res != KSI_OK) goto cleanup; if (cert == NULL) { res = KSI_VerificationResult_addFailure(info, step, "Certificate not found."); goto cleanup; } res = KSI_PKISignedData_getSignatureValue(sig->calendarAuthRec->signatureData, &signatureValue); if (res != KSI_OK) goto cleanup; res = KSI_OctetString_extract(signatureValue, &rawSignature, &rawSignature_len); if (res != KSI_OK) goto cleanup; res = KSI_TLV_serialize(sig->calendarAuthRec->pubData->baseTlv, &rawData, &rawData_len); if (res != KSI_OK) goto cleanup; res = KSI_PKISignedData_getSigType(sig->calendarAuthRec->signatureData, &sigtype); if (res != KSI_OK) goto cleanup; res = KSI_PKITruststore_verifyRawSignature(sig->ctx, rawData, rawData_len, KSI_Utf8String_cstr(sigtype), rawSignature, rawSignature_len, cert); if (res != KSI_OK) { res = KSI_VerificationResult_addFailure(info, step, "Calendar authentication record signature not verified."); goto cleanup; } res = KSI_VerificationResult_addSuccess(info, step, "Calendar authentication record verified."); cleanup: KSI_free(rawData); 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; }
int main(int argc, char **argv) { KSI_CTX *ksi = NULL; int res = KSI_UNKNOWN_ERROR; FILE *in = NULL; FILE *out = NULL; KSI_DataHasher *hsr = NULL; KSI_DataHash *hsh = NULL; KSI_Signature *sign = NULL; unsigned char *raw = NULL; unsigned raw_len; unsigned char buf[1024]; unsigned buf_len; char *signerIdentity = NULL; FILE *logFile = NULL; /* Handle command line parameters */ /* Handle command line parameters */ if (argc != 7) { fprintf(stderr, "Usage:\n" " %s <in-data-file> <out-sign-file> <aggregator-uri> <user> <pass> <pub-file url | -> \n", argv[0]); res = KSI_INVALID_ARGUMENT; goto cleanup; } /* Input file */ in = fopen(argv[1], "rb"); if (in == NULL) { fprintf(stderr, "Unable to open input file '%s'\n", argv[1]); res = KSI_IO_ERROR; goto cleanup; } /* Create new KSI context for this thread. */ res = KSI_CTX_new(&ksi); if (res != KSI_OK) { fprintf(stderr, "Unable to create context.\n"); goto cleanup; } logFile = fopen("ksi_sign_aggr.log", "w"); if (logFile == NULL) { fprintf(stderr, "Unable to open log file.\n"); } 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()); res = KSI_CTX_setAggregator(ksi, argv[3], argv[4], argv[5]); if (res != KSI_OK) goto cleanup; /* Check publications file url. */ if (strncmp("-", argv[6], 1)) { res = KSI_CTX_setPublicationUrl(ksi, argv[6]); if (res != KSI_OK) { fprintf(stderr, "Unable to set publications file url.\n"); goto cleanup; } } /* Create a data hasher using default algorithm. */ res = KSI_DataHasher_open(ksi, KSI_getHashAlgorithmByName("default"), &hsr); if (res != KSI_OK) { fprintf(stderr, "Unable to create hasher.\n"); goto cleanup; } /* Read the input file and calculate the hash of its contents. */ while (!feof(in)) { buf_len = (unsigned)fread(buf, 1, sizeof(buf), in); /* Add next block to the calculation. */ res = KSI_DataHasher_add(hsr, buf, buf_len); if (res != KSI_OK) { fprintf(stderr, "Unable to add data to hasher.\n"); goto cleanup; } } /* Close the data hasher and retreive the data hash. */ res = KSI_DataHasher_close(hsr, &hsh); if (res != KSI_OK) { fprintf(stderr, "Unable to create hash.\n"); goto cleanup; } /* Sign the data hash. */ res = KSI_Signature_createAggregated(ksi, hsh, 4, &sign); // res = KSI_createSignature(ksi, hsh, &sign); if (res != KSI_OK) { fprintf(stderr, "Unable to sign %d.\n", res); goto cleanup; } res = KSI_Signature_verifyAggregated(sign, ksi, 4); if (res != KSI_OK) { fprintf(stderr, "Failed to verify signature.\n"); goto cleanup; } /* Output the signer id */ res = KSI_Signature_getSignerIdentity(sign, &signerIdentity); if (res == KSI_OK) { printf("Signer id: %s\n", signerIdentity); } else { fprintf(stderr, "Unable to extract signer identity.\n"); } /* Serialize the signature. */ res = KSI_Signature_serialize(sign, &raw, &raw_len); if (res != KSI_OK) { fprintf(stderr, "Unable to serialize signature."); goto cleanup; } /* Output file */ out = fopen(argv[2], "wb"); if (out == NULL) { fprintf(stderr, "Unable to open input file '%s'\n", argv[2]); res = KSI_IO_ERROR; goto cleanup; } /* Write the signature file. */ if (!fwrite(raw, 1, raw_len, out)) { fprintf(stderr, "Unable to write output file.\n"); res = KSI_IO_ERROR; goto cleanup; } /* Only print message when signature output is not stdout. */ if (out != NULL) { printf("Signature saved.\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); if (out != NULL) fclose(out); KSI_free(signerIdentity); KSI_Signature_free(sign); KSI_DataHash_free(hsh); KSI_DataHasher_free(hsr); KSI_free(raw); KSI_CTX_free(ksi); return res; }