int KSI_PublicationsFile_getPublicationDataByTime(const KSI_PublicationsFile *trust, const KSI_Integer *pubTime, KSI_PublicationRecord **pubRec) { int res; size_t i; KSI_PublicationRecord *result = NULL; if (trust == NULL) { res = KSI_INVALID_ARGUMENT; goto cleanup; } KSI_ERR_clearErrors(trust->ctx); if (pubTime == NULL || 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; } if (KSI_Integer_equals(pubTime, tm)) { result = pr; break; } KSI_nofree(tm); KSI_nofree(pd); } *pubRec = result; res = KSI_OK; cleanup: KSI_nofree(result); return res; }
int KSI_PublicationsFile_verify(KSI_PublicationsFile *pubFile, KSI_CTX *ctx) { int res; KSI_CTX *useCtx = ctx; KSI_PKITruststore *pki = NULL; if (pubFile == NULL) { res = KSI_INVALID_ARGUMENT; goto cleanup; } if (useCtx == NULL) { useCtx = pubFile->ctx; } KSI_ERR_clearErrors(useCtx); /* Make sure the signature exists. */ if (pubFile->signature == NULL) { KSI_pushError(useCtx, res = KSI_PUBLICATIONS_FILE_NOT_SIGNED_WITH_PKI, NULL); goto cleanup; } /* Do we need to serialize the publications file? */ if (pubFile->raw == NULL) { /* FIXME! At the moment the creation of publications file is not supported, * thus this error can not occur under normal conditions. */ KSI_pushError(useCtx, res = KSI_UNKNOWN_ERROR, "Not implemented"); goto cleanup; } res = KSI_CTX_getPKITruststore(useCtx, &pki); if (res != KSI_OK) { KSI_pushError(useCtx, res, NULL); goto cleanup; } res = KSI_PKITruststore_verifyPKISignature(pki, pubFile->raw, pubFile->signedDataLength, pubFile->signature, pubFile->certConstraints); if (res != KSI_OK) { KSI_pushError(useCtx, res, "Signature not verified."); goto cleanup; } res = KSI_OK; cleanup: KSI_nofree(useCtx); KSI_nofree(pki); return res; }
int KSI_Utf8StringNZ_fromTlv(KSI_TLV *tlv, KSI_Utf8String **o) { int res = KSI_UNKNOWN_ERROR; KSI_CTX *ctx = NULL; KSI_Utf8String *tmp = NULL; ctx = KSI_TLV_getCtx(tlv); KSI_ERR_clearErrors(ctx); if (tlv == NULL || o == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } res = KSI_Utf8String_fromTlv(tlv, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } if (tmp->len == 0 || (tmp->len == 1 && tmp->value[0] == 0)) { KSI_pushError(ctx, res = KSI_INVALID_FORMAT, "Empty string value not allowed."); goto cleanup; } *o = tmp; tmp = NULL; res = KSI_OK; cleanup: KSI_nofree(ctx); KSI_Utf8String_free(tmp); 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; }
int KSI_Integer_fromTlv(KSI_TLV *tlv, KSI_Integer **o) { int res = KSI_UNKNOWN_ERROR; KSI_CTX *ctx = NULL; KSI_Integer *tmp = NULL; const unsigned char *raw = NULL; size_t len; size_t i; KSI_uint64_t val = 0; ctx = KSI_TLV_getCtx(tlv); KSI_ERR_clearErrors(ctx); if (tlv == NULL || o == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } res = KSI_TLV_getRawValue(tlv, &raw, &len); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } if (len > 8) { KSI_pushError(ctx, res = KSI_INVALID_FORMAT, "Integer larger than 64bit"); goto cleanup; } /* Encode the up-to 64bit unsigned integer. */ for (i = 0; i < len; i++) { val = val << 8 | raw[i]; } /* Make sure the integer was coded properly. */ if (len != KSI_UINT64_MINSIZE(val)) { KSI_pushError(ctx, res = KSI_INVALID_FORMAT, "Integer not properly formated."); goto cleanup; } res = KSI_Integer_new(ctx, val, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } *o = tmp; tmp = NULL; res = KSI_OK; cleanup: KSI_nofree(ctx); KSI_Integer_free(tmp); 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; }
int KSI_Utf8String_fromTlv(KSI_TLV *tlv, KSI_Utf8String **o) { int res = KSI_UNKNOWN_ERROR; KSI_CTX *ctx = NULL; const char *cstr = NULL; KSI_Utf8String *tmp = NULL; size_t len; ctx = KSI_TLV_getCtx(tlv); KSI_ERR_clearErrors(ctx); if (tlv == NULL || o == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } res = KSI_TLV_getRawValue(tlv, (const unsigned char **)&cstr, &len); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_Utf8String_new(ctx, cstr, len, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } *o = tmp; tmp = NULL; res = KSI_OK; cleanup: KSI_nofree(ctx); KSI_nofree(cstr); KSI_Utf8String_free(tmp); return res; }
int KSI_PublicationsFile_getPKICertificateById(const KSI_PublicationsFile *pubFile, const KSI_OctetString *id, KSI_PKICertificate **cert) { int res; size_t i; KSI_CertificateRecord *certRec = NULL; if (pubFile == NULL) { res = KSI_INVALID_ARGUMENT; goto cleanup; } KSI_ERR_clearErrors(pubFile->ctx); if (id == NULL || cert == NULL) { KSI_pushError(pubFile->ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } for (i = 0; i < KSI_CertificateRecordList_length(pubFile->certificates); i++) { KSI_OctetString *cId = NULL; res = KSI_CertificateRecordList_elementAt(pubFile->certificates, i, &certRec); if (res != KSI_OK) { KSI_pushError(pubFile->ctx, res, NULL); goto cleanup; } res = KSI_CertificateRecord_getCertId(certRec, &cId); if (res != KSI_OK) { KSI_pushError(pubFile->ctx, res, NULL); goto cleanup; } if (KSI_OctetString_equals(cId, id)) { res = KSI_CertificateRecord_getCert(certRec, cert); if (res != KSI_OK) { KSI_pushError(pubFile->ctx, res, NULL); goto cleanup; } break; } } res = KSI_OK; cleanup: KSI_nofree(certRec); return res; }
int KSI_DataHash_fromTlv(KSI_TLV *tlv, KSI_DataHash **hsh) { int res = KSI_UNKNOWN_ERROR; KSI_CTX *ctx = NULL; const unsigned char *raw = NULL; size_t raw_len = 0; KSI_DataHash *tmp = NULL; ctx = KSI_TLV_getCtx(tlv); KSI_ERR_clearErrors(ctx); if (tlv == NULL || hsh == NULL) { res = KSI_INVALID_ARGUMENT; goto cleanup; } res = KSI_TLV_getRawValue(tlv, &raw, &raw_len); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_DataHash_fromImprint(ctx, raw, raw_len, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } *hsh = tmp; tmp = NULL; res = KSI_OK; cleanup: KSI_nofree(ctx); KSI_nofree(raw); KSI_DataHash_free(tmp); return res; }
KSI_HashAlgorithm KSI_getHashAlgorithmByName(const char *name) { size_t i; KSI_HashAlgorithm algo_id = KSI_HASHALG_INVALID; int alias_id; char *alias = NULL; char *upperName = NULL; if (name == NULL || !*name || strchr(name, ',') != NULL) goto cleanup; upperName = KSI_calloc(strlen(name) + 1, 1); if (upperName == NULL) goto cleanup; /* Create upper-case name */ for (i = 0; i < (int) strlen(name); i++) { if (name[i] == '_') { upperName[i] = '-'; } else { upperName[i] = (char) toupper(name[i]); } } upperName[i] = '\0'; for (i = 0; i < KSI_NUMBER_OF_KNOWN_HASHALGS; i++) { /* Skip all records without a name. */ if (KSI_hashAlgorithmInfo[i].name == NULL) continue; /* Do we have a bingo? */ if (!strcmp(upperName, KSI_hashAlgorithmInfo[i].name)) { algo_id = i; goto cleanup; } alias_id = 0; /* Loop until a null pointer or empty string. */ while ((alias = KSI_hashAlgorithmInfo[i].aliases[alias_id++]) && *alias) { if (!strcmp(upperName, alias)) { algo_id = i; goto cleanup; } } } cleanup: KSI_free(upperName); KSI_nofree(alias); return algo_id; }
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; }
int KSI_PKISignature_toTlv(KSI_CTX *ctx, KSI_PKISignature *sig, unsigned tag, int isNonCritical, int isForward, KSI_TLV **tlv) { int res = KSI_UNKNOWN_ERROR; KSI_TLV *tmp = NULL; unsigned char *raw = NULL; unsigned raw_len = 0; KSI_ERR_clearErrors(ctx); if (ctx == NULL || sig == NULL || tlv == NULL){ res = KSI_INVALID_ARGUMENT; goto cleanup; } res = KSI_TLV_new(ctx, KSI_TLV_PAYLOAD_RAW, tag, isNonCritical, isForward, &tmp); if (res != KSI_OK){ KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_PKISignature_serialize(sig, &raw, &raw_len); if (res != KSI_OK){ KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_TLV_setRawValue(tmp, raw, raw_len); if (res != KSI_OK){ KSI_pushError(ctx, res, NULL); goto cleanup; } *tlv = tmp; tmp = NULL; res = KSI_OK; cleanup: KSI_nofree(raw); KSI_TLV_free(tmp); return res; }
int KSI_DataHash_toTlv(KSI_CTX *ctx, KSI_DataHash *hsh, unsigned tag, int isNonCritical, int isForward, KSI_TLV **tlv) { int res = KSI_UNKNOWN_ERROR; KSI_TLV *tmp = NULL; const unsigned char *raw = NULL; size_t raw_len = 0; KSI_ERR_clearErrors(ctx); if (ctx == NULL || hsh == NULL || tlv == NULL) { res = KSI_INVALID_ARGUMENT; goto cleanup; } res = KSI_TLV_new(ctx, tag, isNonCritical, isForward, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_DataHash_getImprint(hsh, &raw, &raw_len); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_TLV_setRawValue(tmp, raw, raw_len); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } *tlv = tmp; tmp = NULL; res = KSI_OK; cleanup: KSI_nofree(raw); KSI_TLV_free(tmp); return res; }
int KSI_PKISignature_fromTlv(KSI_TLV *tlv, KSI_PKISignature **sig) { KSI_CTX *ctx = NULL; int res = KSI_UNKNOWN_ERROR; KSI_PKISignature *tmp = NULL; const unsigned char *raw = NULL; unsigned int raw_len = 0; if (tlv == NULL || sig == NULL){ res = KSI_INVALID_ARGUMENT; goto cleanup; } ctx = KSI_TLV_getCtx(tlv); KSI_ERR_clearErrors(ctx); res = KSI_TLV_getRawValue(tlv, &raw, &raw_len); if (res != KSI_OK){ KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_PKISignature_new(ctx, raw, raw_len, &tmp); if (res != KSI_OK){ KSI_pushError(ctx, res, NULL); goto cleanup; } *sig = tmp; tmp = NULL; res = KSI_OK; cleanup: KSI_nofree(raw); KSI_PKISignature_free(tmp); return res; }
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; }
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 int storeObjectValue(KSI_CTX *ctx, const KSI_TlvTemplate *tmpl, void *payload, void *val) { int res = KSI_UNKNOWN_ERROR; void *list = NULL; void *listp = NULL; KSI_ERR_clearErrors(ctx); if (ctx == NULL || tmpl == NULL || payload == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } /* Verify the correctness of the template. */ if (tmpl->setValue == NULL) { KSI_pushError(ctx, res = KSI_UNKNOWN_ERROR, "Invalid template - missing setValue function."); goto cleanup; } if (tmpl->listAppend != NULL) { if (tmpl->getValue == NULL) { KSI_pushError(ctx, res = KSI_UNKNOWN_ERROR, "Invalid template - missing getValue function."); goto cleanup; } res = tmpl->getValue(payload, &listp); if (res != KSI_OK) goto cleanup; if (listp == NULL) { /* Make sure we have required function pointers. */ if (tmpl->listNew == NULL || tmpl->listFree == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, "Template does not have list constructor or destructor, but list itself does not exist."); goto cleanup; } res = tmpl->listNew(&list); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } listp = list; } res = tmpl->listAppend(listp, (void *) val); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = tmpl->setValue(payload, listp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } list = NULL; } else { /* Regular value - store with the setter. */ res = tmpl->setValue(payload, (void *) val); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } } res = KSI_OK; cleanup: KSI_nofree(listp); if (tmpl != NULL && tmpl->listFree != NULL) tmpl->listFree(list); return res; }
static int construct(KSI_CTX *ctx, KSI_TLV *tlv, const void *payload, const KSI_TlvTemplate *tmpl, struct tlv_track_s *tr, size_t tr_len, const size_t tr_size) { int res = KSI_UNKNOWN_ERROR; KSI_TLV *tmp = NULL; void *payloadp = NULL; int isNonCritical = 0; int isForward = 0; size_t template_len = 0; bool templateHit[MAX_TEMPLATE_SIZE]; bool groupHit[2] = {false, false}; bool oneOf[2] = {false, false}; size_t i; char buf[1000]; KSI_ERR_clearErrors(ctx); if (ctx == NULL || tlv == NULL || payload == NULL || tmpl == NULL || tr == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } /* Calculate the template length. */ template_len = getTemplateLength(tmpl); if (template_len == 0) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, "A template may not be empty."); goto cleanup; } if (template_len > MAX_TEMPLATE_SIZE) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, "Template too big."); goto cleanup; } memset(templateHit, 0, sizeof(templateHit)); for (i = 0; i < template_len; i++) { if ((tmpl[i].flags & KSI_TLV_TMPL_FLG_NO_SERIALIZE) != 0) continue; payloadp = NULL; res = tmpl[i].getValue(payload, &payloadp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } if (payloadp != NULL) { /* Register for tracking. */ if (tr_len < tr_size) { tr[tr_len].tag = tmpl[i].tag; tr[tr_len].desc = tmpl[i].descr; } templateHit[i] = true; if ((tmpl[i].flags & KSI_TLV_TMPL_FLG_LEAST_ONE_G0) != 0) groupHit[0] = true; if ((tmpl[i].flags & KSI_TLV_TMPL_FLG_LEAST_ONE_G1) != 0) groupHit[1] = true; if (FLAGSET(tmpl[i], KSI_TLV_TMPL_FLG_MOST_ONE_G0)) { if (oneOf[0]) { char errm[1000]; KSI_snprintf(errm, sizeof(errm), "Mutually exclusive elements present within group 0 (%s).", track_str(tr, tr_len, tr_size, buf, sizeof(buf))); KSI_pushError(ctx, res = KSI_INVALID_FORMAT, errm); } oneOf[0] = true; } if (FLAGSET(tmpl[i], KSI_TLV_TMPL_FLG_MOST_ONE_G1)) { if (oneOf[1]) { char errm[1000]; KSI_snprintf(errm, sizeof(errm), "Mutually exclusive elements present within group 1 (%s).", track_str(tr, tr_len, tr_size, buf, sizeof(buf))); KSI_pushError(ctx, res = KSI_INVALID_FORMAT, errm); } oneOf[1] = true; } isNonCritical = (tmpl[i].flags & KSI_TLV_TMPL_FLG_NONCRITICAL) != 0; isForward = (tmpl[i].flags & KSI_TLV_TMPL_FLG_FORWARD) != 0; switch (tmpl[i].type) { case KSI_TLV_TEMPLATE_OBJECT: if (tmpl[i].toTlv == NULL) { KSI_pushError(ctx, res = KSI_UNKNOWN_ERROR, "Invalid template: toTlv not set."); goto cleanup; } if (tmpl[i].listLength != NULL) { int j; for (j = 0; j < tmpl[i].listLength(payloadp); j++) { void *listElement = NULL; res = tmpl[i].listElementAt(payloadp, j, &listElement); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = tmpl[i].toTlv(ctx, listElement, tmpl[i].tag, isNonCritical, isForward != 0, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_TLV_appendNestedTlv(tlv, tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } tmp = NULL; } } else { res = tmpl[i].toTlv(ctx, payloadp, tmpl[i].tag, isNonCritical, isForward, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_TLV_appendNestedTlv(tlv, tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } tmp = NULL; } break; case KSI_TLV_TEMPLATE_COMPOSITE: if (tmpl[i].listLength != NULL) { int j; for (j = 0; j < tmpl[i].listLength(payloadp); j++) { void *listElement = NULL; res = KSI_TLV_new(ctx, KSI_TLV_PAYLOAD_TLV, tmpl[i].tag, isNonCritical, isForward, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = tmpl[i].listElementAt(payloadp, j, &listElement); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = construct(ctx, tmp, listElement, tmpl[i].subTemplate, tr, tr_len + 1, tr_size); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_TLV_appendNestedTlv(tlv, tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } tmp = NULL; } } else { res = KSI_TLV_new(ctx, KSI_TLV_PAYLOAD_TLV, tmpl[i].tag, isNonCritical, isForward, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = construct(ctx, tmp, payloadp, tmpl[i].subTemplate, tr, tr_len + 1, tr_size); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_TLV_appendNestedTlv(tlv, tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } tmp = NULL; } break; default: KSI_LOG_error(ctx, "Unimplemented template type: %d", tmpl[i].type); KSI_pushError(ctx, res = KSI_UNKNOWN_ERROR, "Unimplemented template type."); goto cleanup; } } } /* Check that every mandatory component was present. */ for (i = 0; i < template_len; i++) { char errm[1000]; if ((tmpl[i].flags & KSI_TLV_TMPL_FLG_MANDATORY) != 0 && !templateHit[i]) { KSI_snprintf(errm, sizeof(errm), "Mandatory element missing: %s->[0x%02x]%s", track_str(tr, tr_len, tr_size, buf, sizeof(buf)), tmpl[i].tag, tmpl[i].descr == NULL ? "" : tmpl[i].descr); KSI_LOG_debug(ctx, "%s", errm); KSI_pushError(ctx, res = KSI_INVALID_FORMAT, errm); goto cleanup; } if (((tmpl[i].flags & KSI_TLV_TMPL_FLG_LEAST_ONE_G0) != 0 && !groupHit[0]) || ((tmpl[i].flags & KSI_TLV_TMPL_FLG_LEAST_ONE_G1) != 0 && !groupHit[1])) { KSI_snprintf(errm, sizeof(errm), "Mandatory group missing: %s->[0x%02x]%s", track_str(tr, tr_len, tr_size, buf, sizeof(buf)), tmpl[i].tag, tmpl[i].descr == NULL ? "" : tmpl[i].descr); KSI_LOG_debug(ctx, "%s", errm); KSI_pushError(ctx, res = KSI_INVALID_FORMAT, errm); goto cleanup; } } res = KSI_OK; cleanup: KSI_nofree(payloadp); KSI_TLV_free(tmp); return res; }
KSI_END_TLV_TEMPLATE static int replaceCalendarChain(KSI_Signature *sig, KSI_CalendarHashChain *calendarHashChain) { int res; KSI_DataHash *aggrOutputHash = NULL; KSI_TLV *oldCalChainTlv = NULL; KSI_TLV *newCalChainTlv = NULL; KSI_LIST(KSI_TLV) *nestedList = NULL; size_t i; if (sig == NULL || calendarHashChain == NULL) { res = KSI_INVALID_ARGUMENT; goto cleanup; } KSI_ERR_clearErrors(sig->ctx); res = KSI_TLV_getNestedList(sig->baseTlv, &nestedList); if (res != KSI_OK) { KSI_pushError(sig->ctx, res, NULL); goto cleanup; } if (sig->calendarChain != NULL) { for (i = 0; i < KSI_TLVList_length(nestedList); i++) { res = KSI_TLVList_elementAt(nestedList,i, &oldCalChainTlv); if (res != KSI_OK) { KSI_pushError(sig->ctx, res, NULL); goto cleanup; } if (oldCalChainTlv == NULL) { KSI_pushError(sig->ctx, res = KSI_INVALID_SIGNATURE, "Signature TLV element missing."); goto cleanup; } if (KSI_TLV_getTag(oldCalChainTlv) == 0x0802) break; } } res = KSI_TLV_new(sig->ctx, 0x0802, 0, 0, &newCalChainTlv); if (res != KSI_OK) { KSI_pushError(sig->ctx, res, NULL); goto cleanup; } res = KSI_TlvTemplate_construct(sig->ctx, newCalChainTlv, calendarHashChain, KSI_TLV_TEMPLATE(KSI_CalendarHashChain)); if (res != KSI_OK) { KSI_pushError(sig->ctx, res, NULL); goto cleanup; } res = (sig->calendarChain == NULL) ? /* In case there is no calendar hash chain attached, append a new one. */ KSI_TLV_appendNestedTlv(sig->baseTlv, newCalChainTlv) : /* Otherwise replace the calendar hash chain. */ KSI_TLV_replaceNestedTlv(sig->baseTlv, oldCalChainTlv, newCalChainTlv); if (res != KSI_OK) { KSI_pushError(sig->ctx, res, NULL); goto cleanup; } newCalChainTlv = NULL; /* The memory was freed within KSI_TLV_replaceNestedTlv. */ oldCalChainTlv = NULL; KSI_CalendarHashChain_free(sig->calendarChain); sig->calendarChain = calendarHashChain; res = KSI_OK; cleanup: KSI_nofree(nestedList); KSI_DataHash_free(aggrOutputHash); KSI_TLV_free(newCalChainTlv); return res; }