static void TestClone(CuTest *tc) { int res; KSI_TLV *tlv = NULL; KSI_TLV *clone = NULL; unsigned char in[0xffff + 4]; unsigned char out1[0xffff + 4]; char errstr[1024]; size_t out_len; size_t in_len; FILE *f = NULL; int i = 0; KSI_ERR_clearErrors(ctx); while (ok_sample[i] != NULL) { f = fopen(getFullResourcePath(ok_sample[i]), "rb"); CuAssert(tc, "Unable to open test file.", f != NULL); in_len = (unsigned) fread(in, 1, sizeof(in), f); fclose(f); f = NULL; res = KSI_TLV_parseBlob2(ctx, in, in_len, 0, &tlv); CuAssert(tc, "Unable to parse TLV.", res == KSI_OK); res = parseStructure(tlv, 0); CuAssert(tc, "Unable to parse TLV structure.", res == KSI_OK); res = KSI_TLV_clone(tlv, &clone); CuAssert(tc, "Unsable to clone TLV.", res == KSI_OK && clone != NULL); /* Re assemble TLV */ res = KSI_TLV_serialize_ex(clone, out1, sizeof(out1), &out_len); CuAssert(tc, "Unable to serialize TLV.", res == KSI_OK); CuAssert(tc, "Serialized TLV size mismatch.", in_len == out_len); sprintf(errstr, "Serialised TLV content does not match original: '%s'.", ok_sample[i]); CuAssert(tc, errstr, !memcmp(in, out1, in_len)); KSI_TLV_free(clone); clone = NULL; KSI_TLV_free(tlv); tlv = NULL; i++; } }
int KSI_TlvTemplate_parse(KSI_CTX *ctx, const unsigned char *raw, unsigned raw_len, const KSI_TlvTemplate *tmpl, void *payload) { int res = KSI_UNKNOWN_ERROR; KSI_TLV *tlv = NULL; struct tlv_track_s tr[0xf]; KSI_ERR_clearErrors(ctx); if (ctx == NULL || raw == NULL || tmpl == NULL || payload == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } res = KSI_TLV_parseBlob2(ctx, (unsigned char *)raw, raw_len, 0, &tlv); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = extract(ctx, payload, tlv, tmpl, tr, 0, sizeof(tr)); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } KSI_LOG_logTlv(ctx, KSI_LOG_DEBUG, "Parsed TLV", tlv); res = KSI_OK; cleanup: KSI_TLV_free(tlv); return res; }
int KSI_Utf8StringNZ_toTlv(KSI_CTX *ctx, KSI_Utf8String *o, unsigned tag, int isNonCritical, int isForward, KSI_TLV **tlv) { int res = KSI_UNKNOWN_ERROR; KSI_TLV *tmp = NULL; KSI_ERR_clearErrors(ctx); if (ctx == NULL || o == NULL || tlv == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } if (o->len == 0 || (o->len == 1 && o->value[0] == 0)) { KSI_pushError(ctx, res = KSI_INVALID_FORMAT, "Empty string value not allowed."); goto cleanup; } res = KSI_Utf8String_toTlv(ctx, o, tag, isNonCritical, isForward, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } *tlv = tmp; tmp = NULL; res = KSI_OK; cleanup: KSI_TLV_free(tmp); return res; }
int KSI_OctetString_toTlv(KSI_CTX *ctx, KSI_OctetString *o, unsigned tag, int isNonCritical, int isForward, KSI_TLV **tlv) { int res = KSI_UNKNOWN_ERROR; KSI_TLV *tmp = NULL; KSI_ERR_clearErrors(ctx); if (ctx == NULL || o == NULL || tlv == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } res = KSI_TLV_new(ctx, tag, isNonCritical, isForward, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_TLV_setRawValue(tmp, o->data, o->data_len); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } *tlv = tmp; tmp = NULL; res = KSI_OK; cleanup: KSI_TLV_free(tmp); return res; }
/** * KSI_PublicationData */ void KSI_PublicationData_free(KSI_PublicationData *t) { if (t != NULL && --t->ref == 0) { KSI_Integer_free(t->time); KSI_DataHash_free(t->imprint); KSI_TLV_free(t->baseTlv); KSI_free(t); } }
int KSI_TlvTemplate_serializeObject(KSI_CTX *ctx, const void *obj, unsigned tag, int isNc, int isFwd, const KSI_TlvTemplate *tmpl, unsigned char **raw, unsigned *raw_len) { int res = KSI_UNKNOWN_ERROR; KSI_TLV *tlv = NULL; unsigned char *tmp = NULL; unsigned tmp_len = 0; KSI_ERR_clearErrors(ctx); if (ctx == NULL || obj == NULL || tmpl == NULL || raw == NULL || raw_len == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } /* Create TLV for the PDU object. */ res = KSI_TLV_new(ctx, KSI_TLV_PAYLOAD_TLV, tag, isFwd, isNc, &tlv); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } /* Evaluate the TLV. */ res = KSI_TlvTemplate_construct(ctx, tlv, obj, tmpl); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } KSI_LOG_logTlv(ctx, KSI_LOG_DEBUG, "Serializing object", tlv); /* Serialize the TLV. */ res = KSI_TLV_serialize(tlv, &tmp, &tmp_len); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } *raw = tmp; tmp = NULL; *raw_len = tmp_len; res = KSI_OK; cleanup: KSI_free(tmp); KSI_TLV_free(tlv); return res; }
int KSI_Integer_toTlv(KSI_CTX *ctx, KSI_Integer *o, unsigned tag, int isNonCritical, int isForward, KSI_TLV **tlv) { int res = KSI_UNKNOWN_ERROR; KSI_TLV *tmp = NULL; unsigned char raw[8]; unsigned len = 0; KSI_uint64_t val; KSI_ERR_clearErrors(ctx); if (ctx == NULL || o == NULL || tlv == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } val = o->value; res = KSI_TLV_new(ctx, tag, isNonCritical, isForward, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } /* Encode the integer value. */ while (val != 0) { raw[7 - len++] = val & 0xff; val >>= 8; } /* If the length is greater than 0 (val > 0), add the raw value. */ if (len > 0) { res = KSI_TLV_setRawValue(tmp, raw + 8 - len, len); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } } *tlv = tmp; tmp = NULL; res = KSI_OK; cleanup: KSI_TLV_free(tmp); 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; }
static void TestNokFiles(CuTest* tc) { int res; int i = 0; KSI_TLV *tlv = NULL; KSI_ERR_clearErrors(ctx); while (nok_sample[i] != NULL) { res = KSITest_tlvFromFile(getFullResourcePath(nok_sample[i++]), &tlv); if (res == KSI_OK) { res = parseStructure(tlv, 0); } CuAssert(tc, "Parser did not fail with invalid TLV.", res != KSI_OK); KSI_TLV_free(tlv); tlv = NULL; } }
static void TestOkFiles(CuTest* tc) { int res; int i = 0; KSI_TLV *tlv = NULL; KSI_ERR_clearErrors(ctx); while (ok_sample[i] != NULL) { CuAssert(tc, "Unable to read valid TLV.", KSITest_tlvFromFile(getFullResourcePath(ok_sample[i++]), &tlv) == KSI_OK); res = parseStructure(tlv, 0); CuAssert(tc, "Unable to parse valid TLV.", res == KSI_OK); KSI_TLV_free(tlv); tlv = NULL; break; } }
int KSI_TlvTemplate_deepCopy(KSI_CTX *ctx, const void *from, const KSI_TlvTemplate *baseTemplate, void *to) { int res = KSI_UNKNOWN_ERROR; KSI_TLV *tmpTlv = NULL; KSI_ERR_clearErrors(ctx); if (ctx == NULL || from == NULL || baseTemplate == NULL || to == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } /* Create a dummy TLV */ res = KSI_TLV_new(ctx, KSI_TLV_PAYLOAD_TLV, 0x0, 0, 0, &tmpTlv); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } /* Create a TLV object */ res = KSI_TlvTemplate_construct(ctx, tmpTlv, from, baseTemplate); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } /* Evaluate the cloned object */ res = KSI_TlvTemplate_extract(ctx, to, tmpTlv, baseTemplate); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_OK; cleanup: KSI_TLV_free(tmpTlv); return res; }
int KSI_Utf8String_toTlv(KSI_CTX *ctx, KSI_Utf8String *o, unsigned tag, int isNonCritical, int isForward, KSI_TLV **tlv) { int res = KSI_UNKNOWN_ERROR; KSI_TLV *tmp = NULL; KSI_ERR_clearErrors(ctx); if (ctx == NULL || o == NULL || tlv == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } res = KSI_TLV_new(ctx, tag, isNonCritical, isForward, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } if (o->len > 0xffff){ KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, "UTF8 string too long for TLV conversion."); goto cleanup; } res = KSI_TLV_setRawValue(tmp, o->value, (unsigned)o->len); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } *tlv = tmp; tmp = NULL; res = KSI_OK; cleanup: 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; }
int KSI_PublicationsFile_serialize(KSI_CTX *ctx, KSI_PublicationsFile *pubFile, char **raw, size_t *raw_len) { int res; const unsigned char *buf = NULL; size_t buf_len = 0; KSI_TLV *tlv = NULL; unsigned char *tmp = NULL; size_t tmp_len = 0; size_t sig_len = 0; KSI_ERR_clearErrors(ctx); if (ctx == NULL || pubFile == 0 || raw == NULL || raw_len == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } /** * Create TLV 0x700 that contains nested list of publication file TLVs. * Calculate signed data length assuming that signature TLV is always the last. */ res = KSI_TLV_new(ctx, 0x700, 0, 0, &tlv); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_TlvTemplate_construct(ctx, tlv, pubFile, KSI_TLV_TEMPLATE(KSI_PublicationsFile)); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = publicationsFileTLV_getSignatureTLVLength(tlv, &sig_len); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = KSI_TLV_getRawValue(tlv, &buf, &buf_len); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } /** * Append raw value to publication file header. Copy raw publication file into * internal and external buffer. */ tmp_len = buf_len + sizeof(PUB_FILE_HEADER_ID) - 1; tmp = (unsigned char *) KSI_malloc(tmp_len); if (tmp == NULL) { KSI_pushError(ctx, res = KSI_OUT_OF_MEMORY, NULL); goto cleanup; } if (KSI_strncpy((char *)tmp, PUB_FILE_HEADER_ID, tmp_len) == NULL) { KSI_pushError(ctx, res = KSI_UNKNOWN_ERROR, NULL); goto cleanup; } memcpy(tmp + sizeof(PUB_FILE_HEADER_ID) - 1, buf, buf_len); if (pubFile->raw != NULL) KSI_free(pubFile->raw); pubFile->raw = tmp; pubFile->raw_len = tmp_len; pubFile->signedDataLength = tmp_len - sig_len; tmp = NULL; tmp = (unsigned char *) KSI_malloc(pubFile->raw_len); if (tmp == NULL) { KSI_pushError(ctx, res = KSI_OUT_OF_MEMORY, NULL); goto cleanup; } memcpy(tmp, pubFile->raw, pubFile->raw_len); *raw = (char *)tmp; *raw_len = pubFile->raw_len; tmp = NULL; res = KSI_OK; cleanup: KSI_TLV_free(tlv); KSI_free(tmp); return res; }
int KSI_PublicationsFile_parse(KSI_CTX *ctx, const void *raw, size_t raw_len, KSI_PublicationsFile **pubFile) { int res; KSI_PublicationsFile *tmp = NULL; struct generator_st gen = {ctx, raw, raw_len, NULL, 0, 0, false}; unsigned char *tmpRaw = NULL; const size_t hdrLen = strlen(PUB_FILE_HEADER_ID); KSI_ERR_clearErrors(ctx); if (ctx == NULL || raw == NULL || raw_len == 0 || pubFile == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } /* Check the header. */ if (gen.len < hdrLen || memcmp(gen.ptr, PUB_FILE_HEADER_ID, hdrLen)) { KSI_pushError(ctx, res = KSI_INVALID_FORMAT, "Unrecognized header."); goto cleanup; } /* Header verification ok - create the store object. */ res = KSI_PublicationsFile_new(ctx, &tmp); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } tmp->signedDataLength = hdrLen; /* Initialize generator. */ gen.ptr += hdrLen; gen.len -= hdrLen; /* Read the payload of the file, and make no assumptions with the ordering. */ res = KSI_TlvTemplate_extractGenerator(ctx, tmp, (void *)&gen, KSI_TLV_TEMPLATE(KSI_PublicationsFile), (int (*)(void *, KSI_TLV **))generateNextTlv); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } tmp->signedDataLength += gen.sig_offset; /* Copy the raw value */ tmpRaw = KSI_malloc(raw_len); if (tmpRaw == NULL) { KSI_pushError(ctx, res = KSI_OUT_OF_MEMORY, NULL); goto cleanup; } memcpy(tmpRaw, raw, raw_len); tmp->raw = tmpRaw; tmp->raw_len = raw_len; tmpRaw = NULL; *pubFile = tmp; tmp = NULL; res = KSI_OK; cleanup: KSI_free(tmpRaw); KSI_TLV_free(gen.tlv); KSI_PublicationsFile_free(tmp); return res; }
static int extractGenerator(KSI_CTX *ctx, void *payload, void *generatorCtx, const KSI_TlvTemplate *tmpl, int (*generator)(void *, KSI_TLV **), struct tlv_track_s *tr, size_t tr_len, size_t tr_size) { int res = KSI_UNKNOWN_ERROR; KSI_TLV *tlv = NULL; char buf[1024]; void *voidVal = NULL; void *compositeVal = NULL; void *valuep = NULL; KSI_TLV *tlvVal = NULL; size_t template_len = 0; bool templateHit[MAX_TEMPLATE_SIZE]; bool groupHit[2] = {false, false}; bool oneOf[2] = {false, false}; size_t i; size_t tmplStart = 0; KSI_ERR_clearErrors(ctx); if (ctx == NULL || payload == NULL || generatorCtx == NULL || tmpl == NULL || generator == NULL || tr == NULL) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, NULL); goto cleanup; } /* Analyze the template. */ template_len = getTemplateLength(tmpl); if (template_len == 0) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, "Empty template suggests invalid state."); goto cleanup; } /* Make sure there will be no buffer overflow. */ if (template_len > MAX_TEMPLATE_SIZE) { KSI_pushError(ctx, res = KSI_INVALID_ARGUMENT, "Template too big"); goto cleanup; } memset(templateHit, 0, sizeof(templateHit)); while (1) { int matchCount = 0; res = generator(generatorCtx, &tlv); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } if (tlv == NULL) break; KSI_LOG_trace(ctx, "Starting to parse TLV[0x%02x]", KSI_TLV_getTag(tlv)); if (tr_len < tr_size) { tr[tr_len].tag = KSI_TLV_getTag(tlv); tr[tr_len].desc = NULL; } for (i = tmplStart; i < template_len; i++) { if (tmpl[i].tag != KSI_TLV_getTag(tlv)) continue; if (i == tmplStart && !tmpl[i].multiple) tmplStart++; tr[tr_len].desc = tmpl[i].descr; matchCount++; 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]) { KSI_pushError(ctx, res = KSI_INVALID_FORMAT, "Mutually exclusive elements present within group 0."); goto cleanup; } oneOf[0] = true; } if (FLAGSET(tmpl[i], KSI_TLV_TMPL_FLG_MOST_ONE_G1)) { if (oneOf[1]) { KSI_pushError(ctx, res = KSI_INVALID_FORMAT, "Mutually exclusive elements present within group 0."); goto cleanup; } oneOf[1] = true; } valuep = NULL; if (tmpl[i].getValue != NULL) { /* Validate the value has not been set */ res = tmpl[i].getValue(payload, (void **)&valuep); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } } if (valuep != NULL && !tmpl[i].multiple) { compositeVal = NULL; KSI_LOG_error(ctx, "Multiple occurrences of a unique tag 0x%02x", tmpl[i].tag); KSI_pushError(ctx, res = KSI_INVALID_FORMAT, "To avoid memory leaks, a value may not be set more than once while parsing."); goto cleanup; } /* Parse the current TLV */ switch (tmpl[i].type) { case KSI_TLV_TEMPLATE_OBJECT: KSI_LOG_trace(ctx, "Detected object template for TLV value extraction."); if (tmpl[i].fromTlv == NULL) { KSI_pushError(ctx, res = KSI_UNKNOWN_ERROR, "Invalid template: fromTlv not set."); goto cleanup; } res = tmpl[i].fromTlv(tlv, &voidVal); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = storeObjectValue(ctx, &tmpl[i], payload, voidVal); if (res != KSI_OK) { tmpl[i].destruct(voidVal); // FIXME: Make sure, it is a valid pointer. goto cleanup; } break; case KSI_TLV_TEMPLATE_COMPOSITE: { KSI_LOG_trace(ctx, "Detected composite template for TLV value extraction."); res = tmpl[i].construct(ctx, &compositeVal); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } res = extract(ctx, compositeVal, tlv, tmpl[i].subTemplate, tr, tr_len + 1, tr_size); if (res != KSI_OK) { KSI_LOG_error(ctx, "Unable to parse composite TLV: %s", track_str(tr, tr_len, tr_size, buf, sizeof(buf))); tmpl[i].destruct(compositeVal); // FIXME: Make sure is is a valid pointer. goto cleanup; } res = storeObjectValue(ctx, &tmpl[i], payload, (void *)compositeVal); if (res != KSI_OK) { KSI_pushError(ctx, res, NULL); goto cleanup; } /* Reset the buffer. */ break; } default: KSI_LOG_error(ctx, "No template found."); /* Should not happen, but just in case. */ KSI_pushError(ctx, res = KSI_UNKNOWN_ERROR, "Undefined template type"); goto cleanup; } if ((tmpl[i].flags & KSI_TLV_TMPL_FLG_MORE_DEFS) == 0) break; } /* Check if a match was found, an raise an error if the TLV is marked as critical. */ if (matchCount == 0 && !KSI_TLV_isNonCritical(tlv)) { char errm[1024]; KSI_snprintf(errm, sizeof(errm), "Unknown critical tag: %s", track_str(tr, tr_len + 1, tr_size, buf, sizeof(buf))); KSI_LOG_error(ctx, errm); KSI_pushError(ctx, res = KSI_INVALID_FORMAT, errm); goto cleanup; } } /* Check that every mandatory component was present. */ for (i = 0; i < template_len; i++) { char errm[100]; if ((tmpl[i].flags & KSI_TLV_TMPL_FLG_MANDATORY) != 0 && !templateHit[i]) { KSI_snprintf(errm, sizeof(errm), "Mandatory element missing: %s->[0x%x]%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%x]%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_TLV_free(tlvVal); return res; }
static int generateNextTlv(struct generator_st *gen, KSI_TLV **tlv) { int res = KSI_UNKNOWN_ERROR; unsigned char *buf = NULL; size_t consumed = 0; KSI_FTLV ftlv; if (gen == NULL) { res = KSI_INVALID_ARGUMENT; goto cleanup; } if (gen->tlv != NULL) { KSI_TLV_free(gen->tlv); gen->tlv = NULL; } /* Try to parse only when there is something left to parse. */ if (gen->len > 0) { memset(&ftlv, 0, sizeof(ftlv)); res = KSI_FTLV_memRead(gen->ptr, gen->len, &ftlv); if (res != KSI_OK) { KSI_pushError(gen->ctx, res, NULL); goto cleanup; } consumed = ftlv.hdr_len + ftlv.dat_len; buf = KSI_malloc(consumed); if (buf == NULL) { KSI_pushError(gen->ctx, res = KSI_OUT_OF_MEMORY, NULL); goto cleanup; } memcpy(buf, gen->ptr, consumed); gen->ptr += consumed; gen->len -= consumed; /* Make sure the buffer is not overflowing. */ if (consumed > UINT_MAX){ KSI_pushError(gen->ctx, res = KSI_INVALID_FORMAT, "Input too large."); goto cleanup; } if (consumed > 0) { if (gen->hasSignature) { /* The signature must be the last element. */ KSI_pushError(gen->ctx, res = KSI_INVALID_FORMAT, "The signature must be the last element."); goto cleanup; } res = KSI_TLV_parseBlob2(gen->ctx, buf, (unsigned)consumed, 1, &gen->tlv); if (res != KSI_OK) { KSI_pushError(gen->ctx, res, NULL); goto cleanup; } buf = NULL; if (KSI_TLV_getTag(gen->tlv) == 0x0704) { gen->sig_offset = gen->offset; gen->hasSignature = true; } } } gen->offset += consumed; *tlv = gen->tlv; res = KSI_OK; cleanup: KSI_free(buf); 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; }