static void testVerifySignatureWithUserPublication(CuTest *tc) { int res; KSI_Signature *sig = NULL; const char pubStr[] = "AAAAAA-CTOQBY-AAMJYH-XZPM6T-UO6U6V-2WJMHQ-EJMVXR-JEAGID-2OY7P5-XFFKYI-QIF2LG-YOV7SO"; const char pubStr_bad[] = "AAAAAA-CT5VGY-AAPUCF-L3EKCC-NRSX56-AXIDFL-VZJQK4-WDCPOE-3KIWGB-XGPPM3-O5BIMW-REOVR4"; KSI_PublicationData *pubData = NULL; KSI_PublicationData *pubData_bad = NULL; KSI_ERR_clearErrors(ctx); res = KSI_PublicationData_fromBase32(ctx, pubStr, &pubData); CuAssert(tc, "Unable to parse publication string.", res == KSI_OK && pubData != NULL); res = KSI_PublicationData_fromBase32(ctx, pubStr_bad, &pubData_bad); CuAssert(tc, "Unable to parse publication string.", res == KSI_OK && pubData_bad != NULL); res = KSI_Signature_fromFile(ctx, getFullResourcePath("resource/tlv/ok-sig-2014-04-30.1-extended.ksig"), &sig); CuAssert(tc, "Unable to read signature from file.", res == KSI_OK && sig != NULL); res = KSI_Signature_verifyWithPublication(sig, ctx, pubData); CuAssert(tc, "Unable to verify signature with publication.", res == KSI_OK); res = KSI_Signature_verifyWithPublication(sig, ctx, pubData_bad); CuAssert(tc, "Unable to verify signature with publication.", res != KSI_OK); KSI_PublicationData_free(pubData); KSI_PublicationData_free(pubData_bad); KSI_Signature_free(sig); }
int KSI_PublicationData_new(KSI_CTX *ctx, KSI_PublicationData **t) { int res = KSI_UNKNOWN_ERROR; KSI_PublicationData *tmp = NULL; if (ctx == NULL || t == NULL) { res = KSI_INVALID_ARGUMENT; goto cleanup; } tmp = KSI_new(KSI_PublicationData); if (tmp == NULL) { res = KSI_OUT_OF_MEMORY; goto cleanup; } tmp->ctx = ctx; tmp->ref = 1; tmp->time = NULL; tmp->imprint = NULL; tmp->baseTlv = NULL; *t = tmp; tmp = NULL; res = KSI_OK; cleanup: KSI_PublicationData_free(tmp); return res; }
/** * KSI_PublicationRecord */ void KSI_PublicationRecord_free(KSI_PublicationRecord *t) { if (t != NULL && --t->ref == 0) { KSI_PublicationData_free(t->publishedData); KSI_Utf8StringList_free(t->publicationRef); KSI_Utf8StringList_free(t->repositoryUriList); KSI_free(t); } }
static void testPublicationStringEncodingAndDecoding(CuTest *tc) { static const char publication[] = "AAAAAA-CTJR3I-AANBWU-RY76YF-7TH2M5-KGEZVA-WLLRGD-3GKYBG-AM5WWV-4MCLSP-XPRDDI-UFMHBA"; char *out = NULL; int res; KSI_PublicationData *pub = NULL; KSI_ERR_clearErrors(ctx); res = KSI_PublicationData_fromBase32(ctx, publication, &pub); CuAssert(tc, "Failed decoding publication string.", res == KSI_OK && pub != NULL); res = KSI_PublicationData_toBase32(pub, &out); CuAssert(tc, "Failed encoding the published data object", res == KSI_OK && out != NULL); CuAssert(tc, "Invalid encoded publication string does not match original.", !strncmp(publication, out, strlen(publication))); KSI_PublicationData_free(pub); KSI_free(out); }
int KSI_PublicationData_fromBase32(KSI_CTX *ctx, const char *publication, KSI_PublicationData **published_data) { int res = KSI_UNKNOWN_ERROR; unsigned char *binary_publication = NULL; size_t binary_publication_length; KSI_PublicationData *tmp_published_data = NULL; unsigned i; unsigned long tmp_ulong; KSI_uint64_t tmp_uint64; KSI_HashAlgorithm algo_id; size_t hash_size; KSI_DataHash *pubHash = NULL; KSI_Integer *pubTime = NULL; KSI_ERR_clearErrors(ctx); if (ctx == NULL || publication == NULL || published_data == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } res = KSI_base32Decode(publication, &binary_publication, &binary_publication_length); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } if (binary_publication_length < 13) { res = KSI_INVALID_FORMAT; goto cleanup; } tmp_ulong = 0; for (i = 0; i < 4; ++i) { tmp_ulong <<= 8; tmp_ulong |= binary_publication[binary_publication_length - 4 + i]; } if (KSI_crc32(binary_publication, binary_publication_length - 4, 0) != tmp_ulong) { KSI_pushError(ctx, res = KSI_INVALID_FORMAT, "CRC mismatch."); goto cleanup; } res = KSI_PublicationData_new(ctx, &tmp_published_data); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } tmp_uint64 = 0; for (i = 0; i < 8; ++i) { tmp_uint64 <<= 8; tmp_uint64 |= binary_publication[i]; } res = KSI_Integer_new(ctx, tmp_uint64, &pubTime); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_PublicationData_setTime(tmp_published_data, pubTime); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } pubTime = NULL; algo_id = binary_publication[8]; if (!KSI_isHashAlgorithmSupported(algo_id)) { KSI_pushError(ctx, res = KSI_UNAVAILABLE_HASH_ALGORITHM, NULL); goto cleanup; } hash_size = KSI_getHashLength(algo_id); if (binary_publication_length != 8 + 1 + hash_size + 4) { KSI_pushError(ctx, res = KSI_INVALID_FORMAT, "Hash algorithm length mismatch."); goto cleanup; } res = KSI_DataHash_fromImprint(ctx, binary_publication + 8, hash_size + 1, &pubHash); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_PublicationData_setImprint(tmp_published_data, pubHash); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } pubHash = NULL; *published_data = tmp_published_data; tmp_published_data = NULL; res = KSI_OK; cleanup: KSI_Integer_free(pubTime); KSI_DataHash_free(pubHash); KSI_free(binary_publication); KSI_PublicationData_free(tmp_published_data); return res; }
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; }
/** * 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; }