From 67bc91e11d243679f554cd18389c53554036a19f Mon Sep 17 00:00:00 2001 From: SciLor Date: Wed, 18 Dec 2024 12:46:38 +0000 Subject: [PATCH] Add TAF checks add option sha/size validation for TAFs (valid) --- include/handler.h | 2 +- include/settings.h | 1 + src/contentJson.c | 2 +- src/handler.c | 45 +++++++++++++++++++++++++++++++++++--- src/settings.c | 1 + src/tonie_audio_playlist.c | 2 +- src/toniefile.c | 5 +++++ 7 files changed, 52 insertions(+), 6 deletions(-) diff --git a/include/handler.h b/include/handler.h index 7d5dfda5..5a4d05c4 100644 --- a/include/handler.h +++ b/include/handler.h @@ -88,7 +88,7 @@ char *strupr(char input[]); void getContentPathFromCharRUID(char ruid[17], char **pcontentPath, settings_t *settings); void getContentPathFromUID(uint64_t uid, char **pcontentPath, settings_t *settings); void setTonieboxSettings(TonieFreshnessCheckResponse *freshResp, settings_t *settings); -bool_t isValidTaf(const char *contentPath); +bool_t isValidTaf(const char *contentPath, bool checkHashAndSize); tonie_info_t *getTonieInfoFromUid(uint64_t uid, bool lock, settings_t *settings); tonie_info_t *getTonieInfoFromRuid(char ruid[17], bool lock, settings_t *settings); tonie_info_t *getTonieInfo(const char *contentPath, bool lock, settings_t *settings); diff --git a/include/settings.h b/include/settings.h index 40c89432..5c980c91 100644 --- a/include/settings.h +++ b/include/settings.h @@ -292,6 +292,7 @@ typedef struct settings_level settings_level; bool tonies_json_auto_update; + bool full_taf_validation; } settings_core_t; typedef struct diff --git a/src/contentJson.c b/src/contentJson.c index c3bd83ff..63e86499 100644 --- a/src/contentJson.c +++ b/src/contentJson.c @@ -96,7 +96,7 @@ error_t load_content_json(const char *content_path, contentJson_t *content_json, if (osStrlen(content_json->source) > 0) { resolveSpecialPathPrefix(&content_json->_source_resolved, settings); - if (isValidTaf(content_json->_source_resolved)) + if (isValidTaf(content_json->_source_resolved, settings->core.full_taf_validation)) { content_json->_source_type = CT_SOURCE_TAF; } diff --git a/src/handler.c b/src/handler.c index db927133..0984370e 100644 --- a/src/handler.c +++ b/src/handler.c @@ -448,7 +448,7 @@ void setTonieboxSettings(TonieFreshnessCheckResponse *freshResp, settings_t *set freshResp->led = settings->toniebox.led; } -bool_t isValidTaf(const char *contentPath) +bool_t isValidTaf(const char *contentPath, bool checkHashAndSize) { bool_t valid = false; FsFile *file = fsOpenFile(contentPath, FS_FILE_MODE_READ); @@ -470,7 +470,41 @@ bool_t isValidTaf(const char *contentPath) { if (tafHeader->sha1_hash.len == 20) { - valid = true; + if (checkHashAndSize) + { + Sha1Context sha1Ctx; + size_t audio_length = 0; + sha1Init(&sha1Ctx); + char buffer[TONIEFILE_FRAME_SIZE]; + uint8_t sha1[SHA1_DIGEST_SIZE]; + while (true) + { + error_t error = fsReadFile(file, buffer, TONIEFILE_FRAME_SIZE, &read_length); + if (error != NO_ERROR && error != ERROR_END_OF_FILE) + { + TRACE_ERROR("Cannot read file, error=%" PRIu16 "\n", error); + break; + } + if (read_length == 0) + { + break; + } + audio_length += read_length; + sha1Update(&sha1Ctx, buffer, read_length); + } + sha1Final(&sha1Ctx, sha1); + if (osMemcmp(tafHeader->sha1_hash.data, sha1, SHA1_DIGEST_SIZE) == 0) + { + if (audio_length == tafHeader->num_bytes) + { + valid = true; + } + } + } + else + { + valid = true; + } } toniebox_audio_file_header__free_unpacked(tafHeader, NULL); } @@ -551,6 +585,11 @@ void readTrackPositions(tonie_info_t *tonieInfo, FsFile *file) trackPos->count = 0; osFreeMem(trackPos->pos); trackPos->pos = NULL; + + if (!isValidTaf(tonieInfo->contentPath, true)) + { + TRACE_ERROR("SHA1 not valid or length different for TAF %s\r\n", tonieInfo->contentPath); + } } } } @@ -632,7 +671,7 @@ tonie_info_t *getTonieInfo(const char *contentPath, bool lock, settings_t *setti { if (tonieInfo->tafHeader->sha1_hash.len == 20) { - tonieInfo->valid = true; + tonieInfo->valid = isValidTaf(tonieInfo->contentPath, settings->core.full_taf_validation); readTrackPositions(tonieInfo, file); if (tonieInfo->tafHeader->num_bytes == get_settings()->encode.stream_max_size) { diff --git a/src/settings.c b/src/settings.c index dfcba756..da6cbd53 100644 --- a/src/settings.c +++ b/src/settings.c @@ -116,6 +116,7 @@ static void option_map_init(uint8_t settingsId) OPTION_STRING("core.flex_uid", &settings->core.flex_uid, "", "Flex-Tonie UID", "UID which shall get selected audio files assigned", LEVEL_DETAIL) OPTION_UNSIGNED("core.settings_level", &settings->core.settings_level, 1, 1, 3, "Settings level", "1: Basic, 2: Detail, 3: Expert", LEVEL_BASIC) OPTION_BOOL("core.tonies_json_auto_update", &settings->core.tonies_json_auto_update, TRUE, "Auto-Update tonies.json", "Auto-Update tonies.json for Tonies information and images.", LEVEL_DETAIL) + OPTION_BOOL("core.full_taf_validation", &settings->core.full_taf_validation, FALSE, "Full TAF validation", "Validate TAFs by checking the audio length and the SHA1 hash. (may be slow, as file needs to be fully read!)", LEVEL_EXPERT) OPTION_TREE_DESC("security_mit", "Security mitigation", LEVEL_EXPERT) OPTION_BOOL("security_mit.warnAccess", &settings->security_mit.warnAccess, TRUE, "Warning on unwanted access", "If teddyCloud detects unusal access, warn on frontend until restart. (See on*)", LEVEL_EXPERT) diff --git a/src/tonie_audio_playlist.c b/src/tonie_audio_playlist.c index f2be7f21..b2c5fd26 100644 --- a/src/tonie_audio_playlist.c +++ b/src/tonie_audio_playlist.c @@ -96,7 +96,7 @@ error_t tap_load(char *filename, tonie_audio_playlist_t *tap) cJSON_Delete(tapJson); if (error == NO_ERROR) { - if (isValidTaf(tap->_filepath_resolved)) + if (isValidTaf(tap->_filepath_resolved, true)) { tap->_cached = true; // TODO check audio id if different and check settings. diff --git a/src/toniefile.c b/src/toniefile.c index b304b1c8..e1ce8655 100644 --- a/src/toniefile.c +++ b/src/toniefile.c @@ -362,6 +362,11 @@ error_t toniefile_close(toniefile_t *ctx) fsCloseFile(ctx->file); + if (!isValidTaf(ctx->fullPath, true)) + { + TRACE_ERROR("SHA1 not valid or length different for TAF %s\r\n", ctx->fullPath); + } + osFreeMem(ctx->taf.sha1_hash.data); osFreeMem(ctx->taf.track_page_nums); opus_encoder_destroy(ctx->enc);