Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions tests/check/check_codec_av1.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,21 @@ START_TEST(signed_stream_with_fh)
setting.with_fh = true;
test_stream_t *list = create_signed_stream("ItPtPtItPtPtItPtPtItPtPtItPtPt", setting);
test_stream_check_types(list, "ItPtPtItSPtPtItSPtPtItSPtPtItSPtPt");

// ItPtPtItSPtPtItSPtPtItSPtPtItSPtPt
//
// ItPtPtItS ......PP. (valid, 2 pending)
// ItSPtPtItS .......PP. (valid, 2 pending)
// ItSPtPtItS .......PP. (valid, 2 pending)
// ItSPtPtItS .......PP. (valid, 2 pending)
// 8 pending
// ItSPtPt PP.PPPP (valid, 7 pending)
signed_video_accumulated_validation_t final_validation = {
SV_AUTH_RESULT_OK, false, 34, 27, 7, SV_PUBKEY_VALIDATION_NOT_FEASIBLE, true, 0, 0};
const struct validation_stats expected = {
.valid_gops = 4, .pending_bu = 8, .final_validation = &final_validation};
validate_stream(NULL, list, expected, true);

test_stream_free(list);
}
END_TEST
Expand Down
178 changes: 1 addition & 177 deletions tests/check/check_signed_video_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
#include "sv_internal.h" // set_hash_list_size()
#include "sv_openssl_internal.h" // openssl_read_pubkey_from_private_key()
#include "sv_tlv.h" // sv_write_byte_many()
#include "test_helpers.h" // sv_setting, create_signed_stream()
#include "test_helpers.h" // sv_setting, create_signed_stream(), validation_stats, validate_stream()
#include "test_stream.h" // test_stream_create()

#define TMP_FIX_TO_ALLOW_TWO_INVALID_SEIS_AT_STARTUP true
Expand Down Expand Up @@ -61,182 +61,6 @@ teardown()
* TODO: Currently, validation is triggered already on the second I-frame, which triggers an
* unsigned GOP.
*/

/* Struct to accumulate validation results used to compare against expected values. */
struct validation_stats {
int valid_gops;
int valid_gops_with_missing_info;
int invalid_gops;
int unsigned_gops;
int missed_bu;
int pending_bu;
int has_signature;
bool public_key_has_changed;
bool has_no_timestamp;
signed_video_accumulated_validation_t *final_validation;
};

/* General comments to the validation tests.
* All tests loop through the settings in settings[NUM_SETTINGS]; See signed_video_helpers.h. The
* index in the loop is _i and something the check test framework provides.
*/

/* validate_stream(...)
*
* Helper function to validate the authentication result.
* It takes a test stream |list| as input together with |expected| values of
* valid gops
* invalid gops
* unsigned gops, that is gops without signature
* missed number of gops
* etc
*
* Note that the items in the |list| are consumed, that is, deleted after usage.
*
* If a NULL pointer |list| is passed in no action is taken.
* If a NULL pointer |sv| is passed in a new session is created. This is
* convenient if there are no other actions to take on |sv| outside this scope,
* like reset.
*/
static void
validate_stream(signed_video_t *sv,
test_stream_t *list,
struct validation_stats expected,
bool check_version)
{
if (!list) return;

bool internal_sv = false;
if (!sv) {
sv = signed_video_create(list->codec);
internal_sv = true;
}

signed_video_authenticity_t *auth_report = NULL;
signed_video_latest_validation_t *latest = NULL;

int valid_gops = 0;
int valid_gops_with_missing_info = 0;
int invalid_gops = 0;
int unsigned_gops = 0;
int missed_bu = 0;
int pending_bu = 0;
int has_signature = 0;
bool public_key_has_changed = false;
bool has_timestamp = false;
// Loop through all items in the stream
test_stream_item_t *item = list->first_item;
while (item) {
SignedVideoReturnCode rc =
signed_video_add_nalu_and_authenticate(sv, item->data, item->data_size, &auth_report);
ck_assert_int_eq(rc, SV_OK);

if (auth_report) {
latest = &(auth_report->latest_validation);
ck_assert(latest);
if (latest->number_of_expected_picture_nalus >= 0) {
missed_bu +=
latest->number_of_expected_picture_nalus - latest->number_of_received_picture_nalus;
}
pending_bu += latest->number_of_pending_picture_nalus;
switch (latest->authenticity) {
case SV_AUTH_RESULT_OK_WITH_MISSING_INFO:
valid_gops_with_missing_info++;
break;
case SV_AUTH_RESULT_OK:
valid_gops++;
break;
case SV_AUTH_RESULT_NOT_OK:
invalid_gops++;
break;
case SV_AUTH_RESULT_SIGNATURE_PRESENT:
has_signature++;
break;
case SV_AUTH_RESULT_NOT_SIGNED:
unsigned_gops++;
break;
default:
break;
}
public_key_has_changed |= latest->public_key_has_changed;
has_timestamp |= latest->has_timestamp;

if (latest->has_timestamp) {
if (sv->onvif || sv->legacy_sv) {
// Media Signing and Legacy code only have one timestamp
ck_assert_int_eq(latest->start_timestamp, latest->end_timestamp);
} else {
ck_assert_int_lt(latest->start_timestamp, latest->end_timestamp);
}
}

// Check if product_info has been received and set correctly.
if ((latest->authenticity != SV_AUTH_RESULT_NOT_SIGNED) &&
(latest->authenticity != SV_AUTH_RESULT_SIGNATURE_PRESENT)) {
#ifdef NO_ONVIF_MEDIA_SIGNING
ck_assert_int_eq(strcmp(auth_report->product_info.hardware_id, HW_ID), 0);
ck_assert_int_eq(strcmp(auth_report->product_info.address, ADDR), 0);
#endif
ck_assert_int_eq(strcmp(auth_report->product_info.firmware_version, FW_VER), 0);
ck_assert_int_eq(strcmp(auth_report->product_info.serial_number, SER_NO), 0);
ck_assert_int_eq(strcmp(auth_report->product_info.manufacturer, MANUFACT), 0);

// Check if code version used when signing the video is equal to the code version used when
// validating the authenticity.
if (check_version && strlen(auth_report->version_on_signing_side) != 0) {
ck_assert(!signed_video_compare_versions(
auth_report->version_on_signing_side, auth_report->this_version));
}
}
// Get an authenticity report from separate API and compare accumulated results.
signed_video_authenticity_t *extra_auth_report = signed_video_get_authenticity_report(sv);
ck_assert_int_eq(
memcmp(&auth_report->accumulated_validation, &extra_auth_report->accumulated_validation,
sizeof(signed_video_accumulated_validation_t)),
0);
signed_video_authenticity_report_free(extra_auth_report);

// We are done with auth_report.
latest = NULL;
signed_video_authenticity_report_free(auth_report);
}
// Move to next Bitstream Unit.
item = item->next;
}
// Check GOP statistics against expected.
ck_assert_int_eq(valid_gops, expected.valid_gops);
ck_assert_int_eq(valid_gops_with_missing_info, expected.valid_gops_with_missing_info);
ck_assert_int_eq(invalid_gops, expected.invalid_gops);
ck_assert_int_eq(unsigned_gops, expected.unsigned_gops);
ck_assert_int_eq(missed_bu, expected.missed_bu);
ck_assert_int_eq(pending_bu, expected.pending_bu);
ck_assert_int_eq(has_signature, expected.has_signature);
ck_assert_int_eq(public_key_has_changed, expected.public_key_has_changed);
ck_assert_int_eq(has_timestamp, !expected.has_no_timestamp);

// Get the authenticity report and compare the stats against expected.
if (expected.final_validation) {
auth_report = signed_video_get_authenticity_report(sv);
ck_assert_int_eq(
auth_report->accumulated_validation.authenticity, expected.final_validation->authenticity);
ck_assert_int_eq(auth_report->accumulated_validation.public_key_has_changed,
expected.final_validation->public_key_has_changed);
ck_assert_int_eq(auth_report->accumulated_validation.number_of_received_nalus,
expected.final_validation->number_of_received_nalus);
ck_assert_int_eq(auth_report->accumulated_validation.number_of_validated_nalus,
expected.final_validation->number_of_validated_nalus);
ck_assert_int_eq(auth_report->accumulated_validation.number_of_pending_nalus,
expected.final_validation->number_of_pending_nalus);
ck_assert_int_eq(auth_report->accumulated_validation.public_key_validation,
expected.final_validation->public_key_validation);
ck_assert_int_eq(auth_report->accumulated_validation.has_timestamp,
expected.final_validation->has_timestamp);
signed_video_authenticity_report_free(auth_report);
}

if (internal_sv) signed_video_free(sv);
}

/* Test description
* The public API signed_video_add_nalu_and_authenticate(...) is checked for invalid parameters, and
* invalid Bitstream Units.
Expand Down
154 changes: 154 additions & 0 deletions tests/check/test_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -601,3 +601,157 @@ tlv_has_mandatory_tags(const uint8_t *tlv_data, size_t tlv_data_size)
}
return has_mandatory_tags;
}

/* validate_stream(...)
*
* Helper function to validate the authentication result.
* It takes a test stream |list| as input together with |expected| values of
* valid gops
* invalid gops
* unsigned gops, that is gops without signature
* missed number of gops
* etc
*
* If a NULL pointer |list| is passed in no action is taken.
* If a NULL pointer |sv| is passed in a new session is created. This is
* convenient if there are no other actions to take on |sv| outside this scope,
* like reset.
*/
void
validate_stream(signed_video_t *sv,
test_stream_t *list,
struct validation_stats expected,
bool check_version)
{
if (!list) return;

bool internal_sv = false;
if (!sv) {
sv = signed_video_create(list->codec);
internal_sv = true;
}

signed_video_authenticity_t *auth_report = NULL;
signed_video_latest_validation_t *latest = NULL;

int valid_gops = 0;
int valid_gops_with_missing_info = 0;
int invalid_gops = 0;
int unsigned_gops = 0;
int missed_bu = 0;
int pending_bu = 0;
int has_signature = 0;
bool public_key_has_changed = false;
bool has_timestamp = false;
// Loop through all items in the stream
test_stream_item_t *item = list->first_item;
while (item) {
SignedVideoReturnCode rc =
signed_video_add_nalu_and_authenticate(sv, item->data, item->data_size, &auth_report);
ck_assert_int_eq(rc, SV_OK);

if (auth_report) {
latest = &(auth_report->latest_validation);
ck_assert(latest);
if (latest->number_of_expected_picture_nalus >= 0) {
missed_bu +=
latest->number_of_expected_picture_nalus - latest->number_of_received_picture_nalus;
}
pending_bu += latest->number_of_pending_picture_nalus;
switch (latest->authenticity) {
case SV_AUTH_RESULT_OK_WITH_MISSING_INFO:
valid_gops_with_missing_info++;
break;
case SV_AUTH_RESULT_OK:
valid_gops++;
break;
case SV_AUTH_RESULT_NOT_OK:
invalid_gops++;
break;
case SV_AUTH_RESULT_SIGNATURE_PRESENT:
has_signature++;
break;
case SV_AUTH_RESULT_NOT_SIGNED:
unsigned_gops++;
break;
default:
break;
}
public_key_has_changed |= latest->public_key_has_changed;
has_timestamp |= latest->has_timestamp;

if (latest->has_timestamp) {
if (sv->onvif || sv->legacy_sv) {
// Media Signing and Legacy code only have one timestamp
ck_assert_int_eq(latest->start_timestamp, latest->end_timestamp);
} else {
ck_assert_int_lt(latest->start_timestamp, latest->end_timestamp);
}
}

// Check if product_info has been received and set correctly.
if ((latest->authenticity != SV_AUTH_RESULT_NOT_SIGNED) &&
(latest->authenticity != SV_AUTH_RESULT_SIGNATURE_PRESENT)) {
#ifdef NO_ONVIF_MEDIA_SIGNING
ck_assert_int_eq(strcmp(auth_report->product_info.hardware_id, HW_ID), 0);
ck_assert_int_eq(strcmp(auth_report->product_info.address, ADDR), 0);
#endif
ck_assert_int_eq(strcmp(auth_report->product_info.firmware_version, FW_VER), 0);
ck_assert_int_eq(strcmp(auth_report->product_info.serial_number, SER_NO), 0);
ck_assert_int_eq(strcmp(auth_report->product_info.manufacturer, MANUFACT), 0);

// Check if code version used when signing the video is equal to the code version used when
// validating the authenticity.
if (check_version && strlen(auth_report->version_on_signing_side) != 0) {
ck_assert(!signed_video_compare_versions(
auth_report->version_on_signing_side, auth_report->this_version));
}
}
// Get an authenticity report from separate API and compare accumulated results.
signed_video_authenticity_t *extra_auth_report = signed_video_get_authenticity_report(sv);
ck_assert_int_eq(
memcmp(&auth_report->accumulated_validation, &extra_auth_report->accumulated_validation,
sizeof(signed_video_accumulated_validation_t)),
0);
signed_video_authenticity_report_free(extra_auth_report);

// We are done with auth_report.
latest = NULL;
signed_video_authenticity_report_free(auth_report);
}
// Move to next Bitstream Unit.
item = item->next;
}
// Check GOP statistics against expected.
ck_assert_int_eq(valid_gops, expected.valid_gops);
ck_assert_int_eq(valid_gops_with_missing_info, expected.valid_gops_with_missing_info);
ck_assert_int_eq(invalid_gops, expected.invalid_gops);
ck_assert_int_eq(unsigned_gops, expected.unsigned_gops);
ck_assert_int_eq(missed_bu, expected.missed_bu);
ck_assert_int_eq(pending_bu, expected.pending_bu);
ck_assert_int_eq(has_signature, expected.has_signature);
ck_assert_int_eq(public_key_has_changed, expected.public_key_has_changed);
ck_assert_int_eq(has_timestamp, !expected.has_no_timestamp);

// Get the authenticity report and compare the stats against expected.
if (expected.final_validation) {
auth_report = signed_video_get_authenticity_report(sv);
ck_assert_int_eq(
auth_report->accumulated_validation.authenticity, expected.final_validation->authenticity);
ck_assert_int_eq(auth_report->accumulated_validation.public_key_has_changed,
expected.final_validation->public_key_has_changed);
ck_assert_int_eq(auth_report->accumulated_validation.number_of_received_nalus,
expected.final_validation->number_of_received_nalus);
ck_assert_int_eq(auth_report->accumulated_validation.number_of_validated_nalus,
expected.final_validation->number_of_validated_nalus);
ck_assert_int_eq(auth_report->accumulated_validation.number_of_pending_nalus,
expected.final_validation->number_of_pending_nalus);
ck_assert_int_eq(auth_report->accumulated_validation.public_key_validation,
expected.final_validation->public_key_validation);
ck_assert_int_eq(auth_report->accumulated_validation.has_timestamp,
expected.final_validation->has_timestamp);
signed_video_authenticity_report_free(auth_report);
}

if (internal_sv) signed_video_free(sv);
}
Loading